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