1 | /* |
2 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
3 | * |
4 | * This code is free software; you can redistribute it and/or modify it |
5 | * under the terms of the GNU General Public License version 2 only, as |
6 | * published by the Free Software Foundation. Oracle designates this |
7 | * particular file as subject to the "Classpath" exception as provided |
8 | * by Oracle in the LICENSE file that accompanied this code. |
9 | * |
10 | * This code is distributed in the hope that it will be useful, but WITHOUT |
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
13 | * version 2 for more details (a copy is included in the LICENSE file that |
14 | * accompanied this code). |
15 | * |
16 | * You should have received a copy of the GNU General Public License version |
17 | * 2 along with this work; if not, write to the Free Software Foundation, |
18 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
19 | * |
20 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
21 | * or visit www.oracle.com if you need additional information or have any |
22 | * questions. |
23 | */ |
24 | |
25 | /***************************************************************************** |
26 | |
27 | GIF construction tools |
28 | |
29 | ****************************************************************************/ |
30 | |
31 | #include <stdlib.h> |
32 | #include <stdio.h> |
33 | #include <string.h> |
34 | |
35 | #include "gif_lib.h" |
36 | #include "gif_lib_private.h" |
37 | |
38 | #define MAX(x, y) (((x) > (y)) ? (x) : (y)) |
39 | |
40 | /****************************************************************************** |
41 | Miscellaneous utility functions |
42 | ******************************************************************************/ |
43 | |
44 | /* return smallest bitfield size n will fit in */ |
45 | int |
46 | GifBitSize(int n) |
47 | { |
48 | register int i; |
49 | |
50 | for (i = 1; i <= 8; i++) |
51 | if ((1 << i) >= n) |
52 | break; |
53 | return (i); |
54 | } |
55 | |
56 | /****************************************************************************** |
57 | Color map object functions |
58 | ******************************************************************************/ |
59 | |
60 | /* |
61 | * Allocate a color map of given size; initialize with contents of |
62 | * ColorMap if that pointer is non-NULL. |
63 | */ |
64 | ColorMapObject * |
65 | GifMakeMapObject(int ColorCount, const GifColorType *ColorMap) |
66 | { |
67 | ColorMapObject *Object; |
68 | |
69 | /*** FIXME: Our ColorCount has to be a power of two. Is it necessary to |
70 | * make the user know that or should we automatically round up instead? */ |
71 | if (ColorCount != (1 << GifBitSize(ColorCount))) { |
72 | return ((ColorMapObject *) NULL); |
73 | } |
74 | |
75 | Object = (ColorMapObject *)malloc(sizeof(ColorMapObject)); |
76 | if (Object == (ColorMapObject *) NULL) { |
77 | return ((ColorMapObject *) NULL); |
78 | } |
79 | |
80 | Object->Colors = (GifColorType *)calloc(ColorCount, sizeof(GifColorType)); |
81 | if (Object->Colors == (GifColorType *) NULL) { |
82 | free(Object); |
83 | return ((ColorMapObject *) NULL); |
84 | } |
85 | |
86 | Object->ColorCount = ColorCount; |
87 | Object->BitsPerPixel = GifBitSize(ColorCount); |
88 | Object->SortFlag = false; |
89 | |
90 | if (ColorMap != NULL) { |
91 | memcpy((char *)Object->Colors, |
92 | (char *)ColorMap, ColorCount * sizeof(GifColorType)); |
93 | } |
94 | |
95 | return (Object); |
96 | } |
97 | |
98 | /******************************************************************************* |
99 | Free a color map object |
100 | *******************************************************************************/ |
101 | void |
102 | GifFreeMapObject(ColorMapObject *Object) |
103 | { |
104 | if (Object != NULL) { |
105 | (void)free(Object->Colors); |
106 | (void)free(Object); |
107 | } |
108 | } |
109 | |
110 | #ifdef DEBUG |
111 | void |
112 | DumpColorMap(ColorMapObject *Object, |
113 | FILE * fp) |
114 | { |
115 | if (Object != NULL) { |
116 | int i, j, Len = Object->ColorCount; |
117 | |
118 | for (i = 0; i < Len; i += 4) { |
119 | for (j = 0; j < 4 && j < Len; j++) { |
120 | (void)fprintf(fp, "%3d: %02x %02x %02x " , i + j, |
121 | Object->Colors[i + j].Red, |
122 | Object->Colors[i + j].Green, |
123 | Object->Colors[i + j].Blue); |
124 | } |
125 | (void)fprintf(fp, "\n" ); |
126 | } |
127 | } |
128 | } |
129 | #endif /* DEBUG */ |
130 | |
131 | /******************************************************************************* |
132 | Compute the union of two given color maps and return it. If result can't |
133 | fit into 256 colors, NULL is returned, the allocated union otherwise. |
134 | ColorIn1 is copied as is to ColorUnion, while colors from ColorIn2 are |
135 | copied iff they didn't exist before. ColorTransIn2 maps the old |
136 | ColorIn2 into the ColorUnion color map table./ |
137 | *******************************************************************************/ |
138 | ColorMapObject * |
139 | GifUnionColorMap(const ColorMapObject *ColorIn1, |
140 | const ColorMapObject *ColorIn2, |
141 | GifPixelType ColorTransIn2[]) |
142 | { |
143 | int i, j, CrntSlot, RoundUpTo, NewGifBitSize; |
144 | ColorMapObject *ColorUnion; |
145 | |
146 | /* |
147 | * We don't worry about duplicates within either color map; if |
148 | * the caller wants to resolve those, he can perform unions |
149 | * with an empty color map. |
150 | */ |
151 | |
152 | /* Allocate table which will hold the result for sure. */ |
153 | ColorUnion = GifMakeMapObject(MAX(ColorIn1->ColorCount, |
154 | ColorIn2->ColorCount) * 2, NULL); |
155 | |
156 | if (ColorUnion == NULL) |
157 | return (NULL); |
158 | |
159 | /* |
160 | * Copy ColorIn1 to ColorUnion. |
161 | */ |
162 | for (i = 0; i < ColorIn1->ColorCount; i++) |
163 | ColorUnion->Colors[i] = ColorIn1->Colors[i]; |
164 | CrntSlot = ColorIn1->ColorCount; |
165 | |
166 | /* |
167 | * Potentially obnoxious hack: |
168 | * |
169 | * Back CrntSlot down past all contiguous {0, 0, 0} slots at the end |
170 | * of table 1. This is very useful if your display is limited to |
171 | * 16 colors. |
172 | */ |
173 | while (ColorIn1->Colors[CrntSlot - 1].Red == 0 |
174 | && ColorIn1->Colors[CrntSlot - 1].Green == 0 |
175 | && ColorIn1->Colors[CrntSlot - 1].Blue == 0) |
176 | CrntSlot--; |
177 | |
178 | /* Copy ColorIn2 to ColorUnion (use old colors if they exist): */ |
179 | for (i = 0; i < ColorIn2->ColorCount && CrntSlot <= 256; i++) { |
180 | /* Let's see if this color already exists: */ |
181 | for (j = 0; j < ColorIn1->ColorCount; j++) |
182 | if (memcmp (&ColorIn1->Colors[j], &ColorIn2->Colors[i], |
183 | sizeof(GifColorType)) == 0) |
184 | break; |
185 | |
186 | if (j < ColorIn1->ColorCount) |
187 | ColorTransIn2[i] = j; /* color exists in Color1 */ |
188 | else { |
189 | /* Color is new - copy it to a new slot: */ |
190 | ColorUnion->Colors[CrntSlot] = ColorIn2->Colors[i]; |
191 | ColorTransIn2[i] = CrntSlot++; |
192 | } |
193 | } |
194 | |
195 | if (CrntSlot > 256) { |
196 | GifFreeMapObject(ColorUnion); |
197 | return ((ColorMapObject *) NULL); |
198 | } |
199 | |
200 | NewGifBitSize = GifBitSize(CrntSlot); |
201 | RoundUpTo = (1 << NewGifBitSize); |
202 | |
203 | if (RoundUpTo != ColorUnion->ColorCount) { |
204 | register GifColorType *Map = ColorUnion->Colors; |
205 | |
206 | /* |
207 | * Zero out slots up to next power of 2. |
208 | * We know these slots exist because of the way ColorUnion's |
209 | * start dimension was computed. |
210 | */ |
211 | for (j = CrntSlot; j < RoundUpTo; j++) |
212 | Map[j].Red = Map[j].Green = Map[j].Blue = 0; |
213 | |
214 | /* perhaps we can shrink the map? */ |
215 | if (RoundUpTo < ColorUnion->ColorCount) { |
216 | GifColorType *new_map = (GifColorType *)reallocarray(Map, |
217 | RoundUpTo, sizeof(GifColorType)); |
218 | if( new_map == NULL ) { |
219 | GifFreeMapObject(ColorUnion); |
220 | return ((ColorMapObject *) NULL); |
221 | } |
222 | ColorUnion->Colors = new_map; |
223 | } |
224 | } |
225 | |
226 | ColorUnion->ColorCount = RoundUpTo; |
227 | ColorUnion->BitsPerPixel = NewGifBitSize; |
228 | |
229 | return (ColorUnion); |
230 | } |
231 | |
232 | /******************************************************************************* |
233 | Apply a given color translation to the raster bits of an image |
234 | *******************************************************************************/ |
235 | void |
236 | GifApplyTranslation(SavedImage *Image, GifPixelType Translation[]) |
237 | { |
238 | register int i; |
239 | register int RasterSize = Image->ImageDesc.Height * Image->ImageDesc.Width; |
240 | |
241 | for (i = 0; i < RasterSize; i++) |
242 | Image->RasterBits[i] = Translation[Image->RasterBits[i]]; |
243 | } |
244 | |
245 | /****************************************************************************** |
246 | Extension record functions |
247 | ******************************************************************************/ |
248 | int |
249 | GifAddExtensionBlock(int *ExtensionBlockCount, |
250 | ExtensionBlock **ExtensionBlocks, |
251 | int Function, |
252 | unsigned int Len, |
253 | unsigned char ExtData[]) |
254 | { |
255 | ExtensionBlock *ep; |
256 | |
257 | if (*ExtensionBlocks == NULL) |
258 | *ExtensionBlocks=(ExtensionBlock *)malloc(sizeof(ExtensionBlock)); |
259 | else { |
260 | ExtensionBlock* ep_new = (ExtensionBlock *)reallocarray |
261 | (*ExtensionBlocks, (*ExtensionBlockCount + 1), |
262 | sizeof(ExtensionBlock)); |
263 | if( ep_new == NULL ) |
264 | return (GIF_ERROR); |
265 | *ExtensionBlocks = ep_new; |
266 | } |
267 | |
268 | if (*ExtensionBlocks == NULL) |
269 | return (GIF_ERROR); |
270 | |
271 | ep = &(*ExtensionBlocks)[(*ExtensionBlockCount)++]; |
272 | |
273 | ep->Function = Function; |
274 | ep->ByteCount=Len; |
275 | ep->Bytes = (GifByteType *)malloc(ep->ByteCount); |
276 | if (ep->Bytes == NULL) |
277 | return (GIF_ERROR); |
278 | |
279 | if (ExtData != NULL) { |
280 | memcpy(ep->Bytes, ExtData, Len); |
281 | } |
282 | |
283 | return (GIF_OK); |
284 | } |
285 | |
286 | void |
287 | GifFreeExtensions(int *ExtensionBlockCount, |
288 | ExtensionBlock **ExtensionBlocks) |
289 | { |
290 | ExtensionBlock *ep; |
291 | |
292 | if (*ExtensionBlocks == NULL) |
293 | return; |
294 | |
295 | for (ep = *ExtensionBlocks; |
296 | ep < (*ExtensionBlocks + *ExtensionBlockCount); |
297 | ep++) |
298 | (void)free((char *)ep->Bytes); |
299 | (void)free((char *)*ExtensionBlocks); |
300 | *ExtensionBlocks = NULL; |
301 | *ExtensionBlockCount = 0; |
302 | } |
303 | |
304 | /****************************************************************************** |
305 | Image block allocation functions |
306 | ******************************************************************************/ |
307 | |
308 | /* Private Function: |
309 | * Frees the last image in the GifFile->SavedImages array |
310 | */ |
311 | void |
312 | FreeLastSavedImage(GifFileType *GifFile) |
313 | { |
314 | SavedImage *sp; |
315 | |
316 | if ((GifFile == NULL) || (GifFile->SavedImages == NULL)) |
317 | return; |
318 | |
319 | /* Remove one SavedImage from the GifFile */ |
320 | GifFile->ImageCount--; |
321 | sp = &GifFile->SavedImages[GifFile->ImageCount]; |
322 | |
323 | /* Deallocate its Colormap */ |
324 | if (sp->ImageDesc.ColorMap != NULL) { |
325 | GifFreeMapObject(sp->ImageDesc.ColorMap); |
326 | sp->ImageDesc.ColorMap = NULL; |
327 | } |
328 | |
329 | /* Deallocate the image data */ |
330 | if (sp->RasterBits != NULL) |
331 | free((char *)sp->RasterBits); |
332 | |
333 | /* Deallocate any extensions */ |
334 | GifFreeExtensions(&sp->ExtensionBlockCount, &sp->ExtensionBlocks); |
335 | |
336 | /*** FIXME: We could realloc the GifFile->SavedImages structure but is |
337 | * there a point to it? Saves some memory but we'd have to do it every |
338 | * time. If this is used in GifFreeSavedImages then it would be inefficient |
339 | * (The whole array is going to be deallocated.) If we just use it when |
340 | * we want to free the last Image it's convenient to do it here. |
341 | */ |
342 | } |
343 | |
344 | /* |
345 | * Append an image block to the SavedImages array |
346 | */ |
347 | SavedImage * |
348 | GifMakeSavedImage(GifFileType *GifFile, const SavedImage *CopyFrom) |
349 | { |
350 | if (GifFile->SavedImages == NULL) |
351 | GifFile->SavedImages = (SavedImage *)malloc(sizeof(SavedImage)); |
352 | else { |
353 | SavedImage* newSavedImages = (SavedImage *)reallocarray(GifFile->SavedImages, |
354 | (GifFile->ImageCount + 1), sizeof(SavedImage)); |
355 | if( newSavedImages == NULL) |
356 | return ((SavedImage *)NULL); |
357 | GifFile->SavedImages = newSavedImages; |
358 | } |
359 | if (GifFile->SavedImages == NULL) |
360 | return ((SavedImage *)NULL); |
361 | else { |
362 | SavedImage *sp = &GifFile->SavedImages[GifFile->ImageCount++]; |
363 | |
364 | if (CopyFrom != NULL) { |
365 | memcpy((char *)sp, CopyFrom, sizeof(SavedImage)); |
366 | |
367 | /* |
368 | * Make our own allocated copies of the heap fields in the |
369 | * copied record. This guards against potential aliasing |
370 | * problems. |
371 | */ |
372 | |
373 | /* first, the local color map */ |
374 | if (CopyFrom->ImageDesc.ColorMap != NULL) { |
375 | sp->ImageDesc.ColorMap = GifMakeMapObject( |
376 | CopyFrom->ImageDesc.ColorMap->ColorCount, |
377 | CopyFrom->ImageDesc.ColorMap->Colors); |
378 | if (sp->ImageDesc.ColorMap == NULL) { |
379 | FreeLastSavedImage(GifFile); |
380 | return (SavedImage *)(NULL); |
381 | } |
382 | } |
383 | |
384 | /* next, the raster */ |
385 | sp->RasterBits = (unsigned char *)reallocarray(NULL, |
386 | (CopyFrom->ImageDesc.Height * |
387 | CopyFrom->ImageDesc.Width), |
388 | sizeof(GifPixelType)); |
389 | if (sp->RasterBits == NULL) { |
390 | FreeLastSavedImage(GifFile); |
391 | return (SavedImage *)(NULL); |
392 | } |
393 | memcpy(sp->RasterBits, CopyFrom->RasterBits, |
394 | sizeof(GifPixelType) * CopyFrom->ImageDesc.Height * |
395 | CopyFrom->ImageDesc.Width); |
396 | |
397 | /* finally, the extension blocks */ |
398 | if (CopyFrom->ExtensionBlocks != NULL) { |
399 | sp->ExtensionBlocks = (ExtensionBlock *)reallocarray(NULL, |
400 | CopyFrom->ExtensionBlockCount, |
401 | sizeof(ExtensionBlock)); |
402 | if (sp->ExtensionBlocks == NULL) { |
403 | FreeLastSavedImage(GifFile); |
404 | return (SavedImage *)(NULL); |
405 | } |
406 | memcpy(sp->ExtensionBlocks, CopyFrom->ExtensionBlocks, |
407 | sizeof(ExtensionBlock) * CopyFrom->ExtensionBlockCount); |
408 | } |
409 | } |
410 | else { |
411 | memset((char *)sp, '\0', sizeof(SavedImage)); |
412 | } |
413 | |
414 | return (sp); |
415 | } |
416 | } |
417 | |
418 | void |
419 | GifFreeSavedImages(GifFileType *GifFile) |
420 | { |
421 | SavedImage *sp; |
422 | |
423 | if ((GifFile == NULL) || (GifFile->SavedImages == NULL)) { |
424 | return; |
425 | } |
426 | for (sp = GifFile->SavedImages; |
427 | sp < GifFile->SavedImages + GifFile->ImageCount; sp++) { |
428 | if (sp->ImageDesc.ColorMap != NULL) { |
429 | GifFreeMapObject(sp->ImageDesc.ColorMap); |
430 | sp->ImageDesc.ColorMap = NULL; |
431 | } |
432 | |
433 | if (sp->RasterBits != NULL) |
434 | free((char *)sp->RasterBits); |
435 | |
436 | GifFreeExtensions(&sp->ExtensionBlockCount, &sp->ExtensionBlocks); |
437 | } |
438 | free((char *)GifFile->SavedImages); |
439 | GifFile->SavedImages = NULL; |
440 | } |
441 | |
442 | /* end */ |
443 | |