1 | /*****************************************************************************
|
---|
2 | * "Gif-Lib" - Yet another gif library. *
|
---|
3 | * *
|
---|
4 | * Written by: Gershon Elber Ver 0.1, Jun. 1989 *
|
---|
5 | * Extensively hacked by: Eric S. Raymond Ver 1.?, Sep 1992 *
|
---|
6 | ******************************************************************************
|
---|
7 | * GIF construction tools *
|
---|
8 | ******************************************************************************
|
---|
9 | * History: *
|
---|
10 | * 15 Sep 92 - Version 1.0 by Eric Raymond. *
|
---|
11 | *****************************************************************************/
|
---|
12 | #include <stdlib.h>
|
---|
13 | #include <stdio.h>
|
---|
14 | #include <string.h>
|
---|
15 | #include <malloc.h>
|
---|
16 | #include "gif_lib.h"
|
---|
17 |
|
---|
18 | #define MAX(x, y) (((x) > (y)) ? (x) : (y))
|
---|
19 |
|
---|
20 | /******************************************************************************
|
---|
21 | * Miscellaneous utility functions *
|
---|
22 | ******************************************************************************/
|
---|
23 |
|
---|
24 | int BitSize(int n)
|
---|
25 | /* return smallest bitfield size n will fit in */
|
---|
26 | {
|
---|
27 | register i;
|
---|
28 |
|
---|
29 | for (i = 1; i <= 8; i++)
|
---|
30 | if ((1 << i) >= n)
|
---|
31 | break;
|
---|
32 | return(i);
|
---|
33 | }
|
---|
34 |
|
---|
35 |
|
---|
36 | /******************************************************************************
|
---|
37 | * Color map object functions *
|
---|
38 | ******************************************************************************/
|
---|
39 |
|
---|
40 | ColorMapObject *MakeMapObject(int ColorCount, GifColorType *ColorMap)
|
---|
41 | /*
|
---|
42 | * Allocate a color map of given size; initialize with contents of
|
---|
43 | * ColorMap if that pointer is non-NULL.
|
---|
44 | */
|
---|
45 | {
|
---|
46 | ColorMapObject *Object;
|
---|
47 |
|
---|
48 | if (ColorCount != (1 << BitSize(ColorCount)))
|
---|
49 | return((ColorMapObject *)NULL);
|
---|
50 |
|
---|
51 | Object = (ColorMapObject *)malloc(sizeof(ColorMapObject));
|
---|
52 | if (Object == (ColorMapObject *)NULL)
|
---|
53 | return((ColorMapObject *)NULL);
|
---|
54 |
|
---|
55 | Object->Colors = (GifColorType *)calloc(ColorCount, sizeof(GifColorType));
|
---|
56 | if (Object->Colors == (GifColorType *)NULL)
|
---|
57 | return((ColorMapObject *)NULL);
|
---|
58 |
|
---|
59 | Object->ColorCount = ColorCount;
|
---|
60 | Object->BitsPerPixel = BitSize(ColorCount);
|
---|
61 |
|
---|
62 | if (ColorMap)
|
---|
63 | memcpy((char *)Object->Colors,
|
---|
64 | (char *)ColorMap, ColorCount * sizeof(GifColorType));
|
---|
65 |
|
---|
66 | return(Object);
|
---|
67 | }
|
---|
68 |
|
---|
69 | void FreeMapObject(ColorMapObject *Object)
|
---|
70 | /*
|
---|
71 | * Free a color map object
|
---|
72 | */
|
---|
73 | {
|
---|
74 | free(Object->Colors);
|
---|
75 | free(Object);
|
---|
76 | }
|
---|
77 |
|
---|
78 | #ifdef DEBUG
|
---|
79 | void DumpColorMap(ColorMapObject *Object, FILE *fp)
|
---|
80 | {
|
---|
81 | if (Object)
|
---|
82 | {
|
---|
83 | int i, j, Len = Object->ColorCount;
|
---|
84 |
|
---|
85 | for (i = 0; i < Len; i+=4) {
|
---|
86 | for (j = 0; j < 4 && j < Len; j++) {
|
---|
87 | fprintf(fp,
|
---|
88 | "%3d: %02x %02x %02x ", i + j,
|
---|
89 | Object->Colors[i + j].Red,
|
---|
90 | Object->Colors[i + j].Green,
|
---|
91 | Object->Colors[i + j].Blue);
|
---|
92 | }
|
---|
93 | fprintf(fp, "\n");
|
---|
94 | }
|
---|
95 | }
|
---|
96 | }
|
---|
97 | #endif /* DEBUG */
|
---|
98 |
|
---|
99 | ColorMapObject *UnionColorMap(
|
---|
100 | ColorMapObject *ColorIn1,
|
---|
101 | ColorMapObject *ColorIn2,
|
---|
102 | GifPixelType ColorTransIn2[])
|
---|
103 | /*
|
---|
104 | * Compute the union of two given color maps and return it. If result can't
|
---|
105 | * fit into 256 colors, NULL is returned, the allocated union otherwise.
|
---|
106 | * ColorIn1 is copied as is to ColorUnion, while colors from ColorIn2 are
|
---|
107 | * copied iff they didn't exist before. ColorTransIn2 maps the old
|
---|
108 | * ColorIn2 into ColorUnion color map table.
|
---|
109 | */
|
---|
110 | {
|
---|
111 | int i, j, CrntSlot, RoundUpTo, NewBitSize;
|
---|
112 | ColorMapObject *ColorUnion;
|
---|
113 |
|
---|
114 | /*
|
---|
115 | * Allocate table which will hold the result for sure.
|
---|
116 | */
|
---|
117 | ColorUnion
|
---|
118 | = MakeMapObject(MAX(ColorIn1->ColorCount,ColorIn2->ColorCount)*2,NULL);
|
---|
119 |
|
---|
120 | if (ColorUnion == NULL)
|
---|
121 | return(NULL);
|
---|
122 |
|
---|
123 | /* Copy ColorIn1 to ColorUnionSize; */
|
---|
124 | for (i = 0; i < ColorIn1->ColorCount; i++)
|
---|
125 | ColorUnion->Colors[i] = ColorIn1->Colors[i];
|
---|
126 | CrntSlot = ColorIn1->ColorCount;
|
---|
127 |
|
---|
128 | /*
|
---|
129 | * Potentially obnoxious hack:
|
---|
130 | *
|
---|
131 | * Back CrntSlot down past all contiguous {0, 0, 0} slots at the end
|
---|
132 | * of table 1. This is very useful if your display is limited to
|
---|
133 | * 16 colors.
|
---|
134 | */
|
---|
135 | while (ColorIn1->Colors[CrntSlot-1].Red == 0
|
---|
136 | && ColorIn1->Colors[CrntSlot-1].Green == 0
|
---|
137 | && ColorIn1->Colors[CrntSlot-1].Red == 0)
|
---|
138 | CrntSlot--;
|
---|
139 |
|
---|
140 | /* Copy ColorIn2 to ColorUnionSize (use old colors if they exist): */
|
---|
141 | for (i = 0; i < ColorIn2->ColorCount && CrntSlot<=256; i++)
|
---|
142 | {
|
---|
143 | /* Let's see if this color already exists: */
|
---|
144 | for (j = 0; j < ColorIn1->ColorCount; j++)
|
---|
145 | if (memcmp(&ColorIn1->Colors[j], &ColorIn2->Colors[i], sizeof(GifColorType)) == 0)
|
---|
146 | break;
|
---|
147 |
|
---|
148 | if (j < ColorIn1->ColorCount)
|
---|
149 | ColorTransIn2[i] = j; /* color exists in Color1 */
|
---|
150 | else
|
---|
151 | {
|
---|
152 | /* Color is new - copy it to a new slot: */
|
---|
153 | ColorUnion->Colors[CrntSlot] = ColorIn2->Colors[i];
|
---|
154 | ColorTransIn2[i] = CrntSlot++;
|
---|
155 | }
|
---|
156 | }
|
---|
157 |
|
---|
158 | if (CrntSlot > 256)
|
---|
159 | {
|
---|
160 | FreeMapObject(ColorUnion);
|
---|
161 | return((ColorMapObject *)NULL);
|
---|
162 | }
|
---|
163 |
|
---|
164 | NewBitSize = BitSize(CrntSlot);
|
---|
165 | RoundUpTo = (1 << NewBitSize);
|
---|
166 |
|
---|
167 | if (RoundUpTo != ColorUnion->ColorCount)
|
---|
168 | {
|
---|
169 | register GifColorType *Map = ColorUnion->Colors;
|
---|
170 |
|
---|
171 | /*
|
---|
172 | * Zero out slots up to next power of 2.
|
---|
173 | * We know these slots exist because of the way ColorUnion's
|
---|
174 | * start dimension was computed.
|
---|
175 | */
|
---|
176 | for (j = CrntSlot; j < RoundUpTo; j++)
|
---|
177 | Map[j].Red = Map[j].Green = Map[j].Blue = 0;
|
---|
178 |
|
---|
179 | /* perhaps we can shrink the map? */
|
---|
180 | if (RoundUpTo < ColorUnion->ColorCount)
|
---|
181 | ColorUnion->Colors
|
---|
182 | = (GifColorType *)realloc(Map, sizeof(GifColorType)*RoundUpTo);
|
---|
183 | }
|
---|
184 |
|
---|
185 | ColorUnion->ColorCount = RoundUpTo;
|
---|
186 | ColorUnion->BitsPerPixel = NewBitSize;
|
---|
187 |
|
---|
188 | return(ColorUnion);
|
---|
189 | }
|
---|
190 |
|
---|
191 | void ApplyTranslation(SavedImage *Image, GifPixelType Translation[])
|
---|
192 | /*
|
---|
193 | * Apply a given color translation to the raster bits of an image
|
---|
194 | */
|
---|
195 | {
|
---|
196 | register int i;
|
---|
197 | register int RasterSize = Image->ImageDesc.Height * Image->ImageDesc.Width;
|
---|
198 |
|
---|
199 | for (i = 0; i < RasterSize; i++)
|
---|
200 | Image->RasterBits[i] = Translation[Image->RasterBits[i]];
|
---|
201 | }
|
---|
202 |
|
---|
203 | /******************************************************************************
|
---|
204 | * Extension record functions *
|
---|
205 | ******************************************************************************/
|
---|
206 |
|
---|
207 | void MakeExtension(SavedImage *New, int Function)
|
---|
208 | {
|
---|
209 | New->Function = Function;
|
---|
210 | /*
|
---|
211 | * Someday we might have to deal with multiple extensions.
|
---|
212 | */
|
---|
213 | }
|
---|
214 |
|
---|
215 | int AddExtensionBlock(SavedImage *New, int Len, char ExtData[])
|
---|
216 | {
|
---|
217 | ExtensionBlock *ep;
|
---|
218 |
|
---|
219 | if (New->ExtensionBlocks == NULL)
|
---|
220 | New->ExtensionBlocks = (ExtensionBlock *)malloc(sizeof(ExtensionBlock));
|
---|
221 | else
|
---|
222 | New->ExtensionBlocks =
|
---|
223 | (ExtensionBlock *)realloc(New->ExtensionBlocks,
|
---|
224 | sizeof(ExtensionBlock) * (New->ExtensionBlockCount + 1));
|
---|
225 |
|
---|
226 | if (New->ExtensionBlocks == NULL)
|
---|
227 | return(GIF_ERROR);
|
---|
228 |
|
---|
229 | ep = &New->ExtensionBlocks[New->ExtensionBlockCount++];
|
---|
230 |
|
---|
231 | if ((ep->Bytes = (char *)malloc(ep->ByteCount = Len)) == NULL)
|
---|
232 | return(GIF_ERROR);
|
---|
233 |
|
---|
234 | if (ExtData) {
|
---|
235 | memcpy(ep->Bytes, ExtData, Len);
|
---|
236 | ep->Function = New->Function;
|
---|
237 | }
|
---|
238 |
|
---|
239 | return(GIF_OK);
|
---|
240 | }
|
---|
241 |
|
---|
242 | void FreeExtension(SavedImage *Image)
|
---|
243 | {
|
---|
244 | ExtensionBlock *ep;
|
---|
245 |
|
---|
246 | for (ep = Image->ExtensionBlocks;
|
---|
247 | ep < Image->ExtensionBlocks + Image->ExtensionBlockCount;
|
---|
248 | ep++)
|
---|
249 | (void) free((char *)ep->Bytes);
|
---|
250 | free((char *)Image->ExtensionBlocks);
|
---|
251 | Image->ExtensionBlocks = NULL;
|
---|
252 | }
|
---|
253 |
|
---|
254 | /******************************************************************************
|
---|
255 | * Image block allocation functions *
|
---|
256 | ******************************************************************************/
|
---|
257 | SavedImage *MakeSavedImage(GifFileType *GifFile, SavedImage *CopyFrom)
|
---|
258 | /*
|
---|
259 | * Append an image block to the SavedImages array
|
---|
260 | */
|
---|
261 | {
|
---|
262 | SavedImage *sp;
|
---|
263 |
|
---|
264 | if (GifFile->SavedImages == NULL)
|
---|
265 | GifFile->SavedImages = (SavedImage *)malloc(sizeof(SavedImage));
|
---|
266 | else
|
---|
267 | GifFile->SavedImages = (SavedImage *)realloc(GifFile->SavedImages,
|
---|
268 | sizeof(SavedImage) * (GifFile->ImageCount+1));
|
---|
269 |
|
---|
270 | if (GifFile->SavedImages == NULL)
|
---|
271 | return((SavedImage *)NULL);
|
---|
272 | else
|
---|
273 | {
|
---|
274 | sp = &GifFile->SavedImages[GifFile->ImageCount++];
|
---|
275 | memset((char *)sp, '\0', sizeof(SavedImage));
|
---|
276 |
|
---|
277 | if (CopyFrom)
|
---|
278 | {
|
---|
279 | memcpy((char *)sp, CopyFrom, sizeof(SavedImage));
|
---|
280 |
|
---|
281 | /*
|
---|
282 | * Make our own allocated copies of the heap fields in the
|
---|
283 | * copied record. This guards against potential aliasing
|
---|
284 | * problems.
|
---|
285 | */
|
---|
286 |
|
---|
287 | /* first, the local color map */
|
---|
288 | if (sp->ImageDesc.ColorMap)
|
---|
289 | sp->ImageDesc.ColorMap =
|
---|
290 | MakeMapObject(CopyFrom->ImageDesc.ColorMap->ColorCount,
|
---|
291 | CopyFrom->ImageDesc.ColorMap->Colors);
|
---|
292 |
|
---|
293 | /* next, the raster */
|
---|
294 | sp->RasterBits = (char *)malloc(sizeof(GifPixelType)
|
---|
295 | * CopyFrom->ImageDesc.Height
|
---|
296 | * CopyFrom->ImageDesc.Width);
|
---|
297 | memcpy(sp->RasterBits,
|
---|
298 | CopyFrom->RasterBits,
|
---|
299 | sizeof(GifPixelType)
|
---|
300 | * CopyFrom->ImageDesc.Height
|
---|
301 | * CopyFrom->ImageDesc.Width);
|
---|
302 |
|
---|
303 | /* finally, the extension blocks */
|
---|
304 | if (sp->ExtensionBlocks)
|
---|
305 | {
|
---|
306 | sp->ExtensionBlocks
|
---|
307 | = (ExtensionBlock*)malloc(sizeof(ExtensionBlock)
|
---|
308 | * CopyFrom->ExtensionBlockCount);
|
---|
309 | memcpy(sp->ExtensionBlocks,
|
---|
310 | CopyFrom->ExtensionBlocks,
|
---|
311 | sizeof(ExtensionBlock)
|
---|
312 | * CopyFrom->ExtensionBlockCount);
|
---|
313 |
|
---|
314 | /*
|
---|
315 | * For the moment, the actual blocks can take their
|
---|
316 | * chances with free(). We'll fix this later.
|
---|
317 | */
|
---|
318 | }
|
---|
319 | }
|
---|
320 |
|
---|
321 | return(sp);
|
---|
322 | }
|
---|
323 | }
|
---|
324 |
|
---|
325 | void FreeSavedImages(GifFileType *GifFile)
|
---|
326 | {
|
---|
327 | SavedImage *sp;
|
---|
328 |
|
---|
329 | for (sp = GifFile->SavedImages;
|
---|
330 | sp < GifFile->SavedImages + GifFile->ImageCount;
|
---|
331 | sp++)
|
---|
332 | {
|
---|
333 | if (sp->ImageDesc.ColorMap)
|
---|
334 | FreeMapObject(sp->ImageDesc.ColorMap);
|
---|
335 |
|
---|
336 | if (sp->RasterBits)
|
---|
337 | free((char *)sp->RasterBits);
|
---|
338 |
|
---|
339 | if (sp->ExtensionBlocks)
|
---|
340 | FreeExtension(sp);
|
---|
341 | }
|
---|
342 | free((char *) GifFile->SavedImages);
|
---|
343 | }
|
---|
344 |
|
---|
345 |
|
---|
346 |
|
---|