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