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