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