1 /* giffunc.c - General functions for the GIF library.
2 Copyright (C) 1997-2019 Eddie Kohler, ekohler@gmail.com
3 This file is part of the LCDF GIF library.
4
5 The LCDF GIF library is free software. It is distributed under the GNU
6 General Public License, version 2; you can copy, distribute, or alter it at
7 will, as long as this notice is kept intact and this source code is made
8 available. There is no warranty, express or implied. */
9
10 #if HAVE_CONFIG_H
11 # include <config.h>
12 #endif
13 #include <lcdfgif/gif.h>
14 #include <string.h>
15 #include <stdarg.h>
16 #ifdef __cplusplus
17 extern "C" {
18 #endif
19
20
21 Gif_Stream *
Gif_NewStream(void)22 Gif_NewStream(void)
23 {
24 Gif_Stream *gfs = Gif_New(Gif_Stream);
25 if (!gfs)
26 return 0;
27 gfs->images = 0;
28 gfs->nimages = gfs->imagescap = 0;
29 gfs->global = 0;
30 gfs->background = 256;
31 gfs->screen_width = gfs->screen_height = 0;
32 gfs->loopcount = -1;
33 gfs->end_comment = 0;
34 gfs->end_extension_list = 0;
35 gfs->errors = 0;
36 gfs->user_flags = 0;
37 gfs->refcount = 0;
38 gfs->landmark = 0;
39 return gfs;
40 }
41
42
43 Gif_Image *
Gif_NewImage(void)44 Gif_NewImage(void)
45 {
46 Gif_Image *gfi = Gif_New(Gif_Image);
47 if (!gfi)
48 return 0;
49 gfi->width = gfi->height = 0;
50 gfi->img = 0;
51 gfi->image_data = 0;
52 gfi->left = gfi->top = 0;
53 gfi->delay = 0;
54 gfi->disposal = GIF_DISPOSAL_NONE;
55 gfi->interlace = 0;
56 gfi->local = 0;
57 gfi->transparent = -1;
58 gfi->user_flags = 0;
59 gfi->identifier = 0;
60 gfi->comment = 0;
61 gfi->extension_list = 0;
62 gfi->free_image_data = Gif_Free;
63 gfi->compressed_len = 0;
64 gfi->compressed_errors = 0;
65 gfi->compressed = 0;
66 gfi->free_compressed = 0;
67 gfi->user_data = 0;
68 gfi->free_user_data = 0;
69 gfi->refcount = 0;
70 return gfi;
71 }
72
73
74 Gif_Colormap *
Gif_NewColormap(void)75 Gif_NewColormap(void)
76 {
77 Gif_Colormap *gfcm = Gif_New(Gif_Colormap);
78 if (!gfcm)
79 return 0;
80 gfcm->ncol = 0;
81 gfcm->capacity = 0;
82 gfcm->col = 0;
83 gfcm->refcount = 0;
84 gfcm->user_flags = 0;
85 return gfcm;
86 }
87
88
89 Gif_Colormap *
Gif_NewFullColormap(int count,int capacity)90 Gif_NewFullColormap(int count, int capacity)
91 {
92 Gif_Colormap *gfcm = Gif_New(Gif_Colormap);
93 if (!gfcm || capacity <= 0 || count < 0) {
94 Gif_Delete(gfcm);
95 return 0;
96 }
97 if (count > capacity)
98 capacity = count;
99 gfcm->ncol = count;
100 gfcm->capacity = capacity;
101 gfcm->col = Gif_NewArray(Gif_Color, capacity);
102 gfcm->refcount = 0;
103 gfcm->user_flags = 0;
104 if (!gfcm->col) {
105 Gif_Delete(gfcm);
106 return 0;
107 } else
108 return gfcm;
109 }
110
111
112 Gif_Comment *
Gif_NewComment(void)113 Gif_NewComment(void)
114 {
115 Gif_Comment *gfcom = Gif_New(Gif_Comment);
116 if (!gfcom)
117 return 0;
118 gfcom->str = 0;
119 gfcom->len = 0;
120 gfcom->count = gfcom->cap = 0;
121 return gfcom;
122 }
123
124
125 Gif_Extension *
Gif_NewExtension(int kind,const char * appname,int applength)126 Gif_NewExtension(int kind, const char* appname, int applength)
127 {
128 Gif_Extension *gfex = Gif_New(Gif_Extension);
129 if (!gfex)
130 return 0;
131 gfex->kind = kind;
132 if (appname) {
133 gfex->appname = (char*) Gif_NewArray(char, applength + 1);
134 if (!gfex->appname) {
135 Gif_Delete(gfex);
136 return 0;
137 }
138 memcpy(gfex->appname, appname, applength);
139 gfex->appname[applength] = 0;
140 gfex->applength = applength;
141 } else {
142 gfex->appname = 0;
143 gfex->applength = 0;
144 }
145 gfex->data = 0;
146 gfex->stream = 0;
147 gfex->image = 0;
148 gfex->next = 0;
149 gfex->free_data = 0;
150 gfex->packetized = 0;
151 return gfex;
152 }
153
154 Gif_Extension*
Gif_CopyExtension(Gif_Extension * src)155 Gif_CopyExtension(Gif_Extension* src)
156 {
157 Gif_Extension* dst = Gif_NewExtension(src->kind, src->appname, src->applength);
158 if (!dst)
159 return NULL;
160 if (!src->data || !src->free_data) {
161 dst->data = src->data;
162 dst->length = src->length;
163 } else {
164 dst->data = Gif_NewArray(uint8_t, src->length);
165 if (!dst->data) {
166 Gif_DeleteExtension(dst);
167 return NULL;
168 }
169 memcpy(dst->data, src->data, src->length);
170 dst->length = src->length;
171 dst->free_data = Gif_Free;
172 }
173 dst->packetized = src->packetized;
174 return dst;
175 }
176
177
178 char *
Gif_CopyString(const char * s)179 Gif_CopyString(const char *s)
180 {
181 int l;
182 char *copy;
183 if (!s)
184 return 0;
185 l = strlen(s);
186 copy = Gif_NewArray(char, l + 1);
187 if (!copy)
188 return 0;
189 memcpy(copy, s, l + 1);
190 return copy;
191 }
192
193
194 int
Gif_AddImage(Gif_Stream * gfs,Gif_Image * gfi)195 Gif_AddImage(Gif_Stream *gfs, Gif_Image *gfi)
196 {
197 if (gfs->nimages >= gfs->imagescap) {
198 if (gfs->imagescap)
199 gfs->imagescap *= 2;
200 else
201 gfs->imagescap = 2;
202 Gif_ReArray(gfs->images, Gif_Image *, gfs->imagescap);
203 if (!gfs->images)
204 return 0;
205 }
206 gfs->images[gfs->nimages] = gfi;
207 gfs->nimages++;
208 gfi->refcount++;
209 return 1;
210 }
211
212
213 void
Gif_RemoveImage(Gif_Stream * gfs,int inum)214 Gif_RemoveImage(Gif_Stream *gfs, int inum)
215 {
216 int j;
217 if (inum < 0 || inum >= gfs->nimages)
218 return;
219 Gif_DeleteImage(gfs->images[inum]);
220 for (j = inum; j < gfs->nimages - 1; j++)
221 gfs->images[j] = gfs->images[j+1];
222 gfs->nimages--;
223 }
224
225
226 int
Gif_ImageColorBound(const Gif_Image * gfi)227 Gif_ImageColorBound(const Gif_Image* gfi)
228 {
229 if (gfi->compressed && gfi->compressed[0] > 0 && gfi->compressed[0] < 8)
230 return 1 << gfi->compressed[0];
231 else
232 return 256;
233 }
234
235
236 int
Gif_AddCommentTake(Gif_Comment * gfcom,char * x,int xlen)237 Gif_AddCommentTake(Gif_Comment *gfcom, char *x, int xlen)
238 {
239 if (gfcom->count >= gfcom->cap) {
240 if (gfcom->cap)
241 gfcom->cap *= 2;
242 else
243 gfcom->cap = 2;
244 Gif_ReArray(gfcom->str, char *, gfcom->cap);
245 Gif_ReArray(gfcom->len, int, gfcom->cap);
246 if (!gfcom->str || !gfcom->len)
247 return 0;
248 }
249 if (xlen < 0)
250 xlen = strlen(x);
251 gfcom->str[ gfcom->count ] = x;
252 gfcom->len[ gfcom->count ] = xlen;
253 gfcom->count++;
254 return 1;
255 }
256
257
258 int
Gif_AddComment(Gif_Comment * gfcom,const char * x,int xlen)259 Gif_AddComment(Gif_Comment *gfcom, const char *x, int xlen)
260 {
261 char *new_x;
262 if (xlen < 0)
263 xlen = strlen(x);
264 new_x = Gif_NewArray(char, xlen);
265 if (!new_x)
266 return 0;
267 memcpy(new_x, x, xlen);
268 if (Gif_AddCommentTake(gfcom, new_x, xlen) == 0) {
269 Gif_DeleteArray(new_x);
270 return 0;
271 } else
272 return 1;
273 }
274
275
276 int
Gif_AddExtension(Gif_Stream * gfs,Gif_Image * gfi,Gif_Extension * gfex)277 Gif_AddExtension(Gif_Stream* gfs, Gif_Image* gfi, Gif_Extension* gfex)
278 {
279 Gif_Extension **pprev;
280 if (gfex->stream || gfex->image)
281 return 0;
282 pprev = gfi ? &gfi->extension_list : &gfs->end_extension_list;
283 while (*pprev)
284 pprev = &(*pprev)->next;
285 *pprev = gfex;
286 gfex->stream = gfs;
287 gfex->image = gfi;
288 gfex->next = 0;
289 return 1;
290 }
291
292
293 int
Gif_ImageNumber(Gif_Stream * gfs,Gif_Image * gfi)294 Gif_ImageNumber(Gif_Stream *gfs, Gif_Image *gfi)
295 {
296 int i;
297 if (gfs && gfi)
298 for (i = 0; i != gfs->nimages; ++i)
299 if (gfs->images[i] == gfi)
300 return i;
301 return -1;
302 }
303
304
305 void
Gif_CalculateScreenSize(Gif_Stream * gfs,int force)306 Gif_CalculateScreenSize(Gif_Stream *gfs, int force)
307 {
308 int i;
309 int screen_width = 0;
310 int screen_height = 0;
311
312 for (i = 0; i < gfs->nimages; i++) {
313 Gif_Image *gfi = gfs->images[i];
314 /* 17.Dec.1999 - I find this old behavior annoying. */
315 /* if (gfi->left != 0 || gfi->top != 0) continue; */
316 if (screen_width < gfi->left + gfi->width)
317 screen_width = gfi->left + gfi->width;
318 if (screen_height < gfi->top + gfi->height)
319 screen_height = gfi->top + gfi->height;
320 }
321
322 /* Only use the default 640x480 screen size if we are being forced to create
323 a new screen size or there's no screen size currently. */
324 if (screen_width == 0 && (gfs->screen_width == 0 || force))
325 screen_width = 640;
326 if (screen_height == 0 && (gfs->screen_height == 0 || force))
327 screen_height = 480;
328
329 if (gfs->screen_width < screen_width || force)
330 gfs->screen_width = screen_width;
331 if (gfs->screen_height < screen_height || force)
332 gfs->screen_height = screen_height;
333 }
334
335
336 Gif_Stream *
Gif_CopyStreamSkeleton(Gif_Stream * gfs)337 Gif_CopyStreamSkeleton(Gif_Stream *gfs)
338 {
339 Gif_Stream *ngfs = Gif_NewStream();
340 if (!ngfs)
341 return 0;
342 ngfs->global = Gif_CopyColormap(gfs->global);
343 ngfs->background = gfs->background;
344 ngfs->screen_width = gfs->screen_width;
345 ngfs->screen_height = gfs->screen_height;
346 ngfs->loopcount = gfs->loopcount;
347 if (gfs->global && !ngfs->global) {
348 Gif_DeleteStream(ngfs);
349 return 0;
350 } else
351 return ngfs;
352 }
353
354
355 Gif_Stream *
Gif_CopyStreamImages(Gif_Stream * gfs)356 Gif_CopyStreamImages(Gif_Stream *gfs)
357 {
358 Gif_Stream *ngfs = Gif_CopyStreamSkeleton(gfs);
359 int i;
360 if (!ngfs)
361 return 0;
362 for (i = 0; i < gfs->nimages; i++) {
363 Gif_Image *gfi = Gif_CopyImage(gfs->images[i]);
364 if (!gfi || !Gif_AddImage(ngfs, gfi)) {
365 Gif_DeleteStream(ngfs);
366 return 0;
367 }
368 }
369 return ngfs;
370 }
371
372
373 Gif_Colormap *
Gif_CopyColormap(Gif_Colormap * src)374 Gif_CopyColormap(Gif_Colormap *src)
375 {
376 Gif_Colormap *dest;
377 if (!src)
378 return 0;
379
380 dest = Gif_NewFullColormap(src->ncol, src->capacity);
381 if (!dest)
382 return 0;
383
384 memcpy(dest->col, src->col, sizeof(src->col[0]) * src->ncol);
385 return dest;
386 }
387
388
389 Gif_Image *
Gif_CopyImage(Gif_Image * src)390 Gif_CopyImage(Gif_Image *src)
391 {
392 Gif_Image *dest;
393 uint8_t *data;
394 int i;
395 if (!src)
396 return 0;
397
398 dest = Gif_NewImage();
399 if (!dest)
400 return 0;
401
402 dest->identifier = Gif_CopyString(src->identifier);
403 if (!dest->identifier && src->identifier)
404 goto failure;
405 if (src->comment) {
406 dest->comment = Gif_NewComment();
407 if (!dest->comment)
408 goto failure;
409 for (i = 0; i < src->comment->count; i++)
410 if (!Gif_AddComment(dest->comment, src->comment->str[i],
411 src->comment->len[i]))
412 goto failure;
413 }
414 if (src->extension_list) {
415 Gif_Extension* gfex = src->extension_list;
416 while (gfex) {
417 Gif_Extension* dstex = Gif_CopyExtension(gfex);
418 if (!dstex)
419 goto failure;
420 Gif_AddExtension(NULL, dest, dstex);
421 gfex = gfex->next;
422 }
423 }
424
425 dest->local = Gif_CopyColormap(src->local);
426 if (!dest->local && src->local)
427 goto failure;
428 dest->transparent = src->transparent;
429
430 dest->delay = src->delay;
431 dest->disposal = src->disposal;
432 dest->left = src->left;
433 dest->top = src->top;
434
435 dest->width = src->width;
436 dest->height = src->height;
437
438 dest->interlace = src->interlace;
439 if (src->img) {
440 dest->img = Gif_NewArray(uint8_t *, dest->height + 1);
441 dest->image_data = Gif_NewArray(uint8_t, (size_t) dest->width * (size_t) dest->height);
442 dest->free_image_data = Gif_Free;
443 if (!dest->img || !dest->image_data)
444 goto failure;
445 for (i = 0, data = dest->image_data; i < dest->height; i++) {
446 memcpy(data, src->img[i], dest->width);
447 dest->img[i] = data;
448 data += dest->width;
449 }
450 dest->img[dest->height] = 0;
451 }
452 if (src->compressed) {
453 if (src->free_compressed == 0)
454 dest->compressed = src->compressed;
455 else {
456 dest->compressed = Gif_NewArray(uint8_t, src->compressed_len);
457 dest->free_compressed = Gif_Free;
458 memcpy(dest->compressed, src->compressed, src->compressed_len);
459 }
460 dest->compressed_len = src->compressed_len;
461 dest->compressed_errors = src->compressed_errors;
462 }
463
464 return dest;
465
466 failure:
467 Gif_DeleteImage(dest);
468 return 0;
469 }
470
471
Gif_MakeImageEmpty(Gif_Image * gfi)472 void Gif_MakeImageEmpty(Gif_Image* gfi) {
473 Gif_ReleaseUncompressedImage(gfi);
474 Gif_ReleaseCompressedImage(gfi);
475 gfi->width = gfi->height = 1;
476 gfi->transparent = 0;
477 Gif_CreateUncompressedImage(gfi, 0);
478 gfi->img[0][0] = 0;
479 }
480
481
482 /** DELETION **/
483
484 typedef struct Gif_DeletionHook {
485 int kind;
486 Gif_DeletionHookFunc func;
487 void *callback_data;
488 struct Gif_DeletionHook *next;
489 } Gif_DeletionHook;
490
491 static Gif_DeletionHook *all_hooks;
492
493 void
Gif_DeleteStream(Gif_Stream * gfs)494 Gif_DeleteStream(Gif_Stream *gfs)
495 {
496 Gif_DeletionHook *hook;
497 int i;
498 if (!gfs || --gfs->refcount > 0)
499 return;
500
501 for (i = 0; i < gfs->nimages; i++)
502 Gif_DeleteImage(gfs->images[i]);
503 Gif_DeleteArray(gfs->images);
504
505 Gif_DeleteColormap(gfs->global);
506
507 Gif_DeleteComment(gfs->end_comment);
508 while (gfs->end_extension_list)
509 Gif_DeleteExtension(gfs->end_extension_list);
510
511 for (hook = all_hooks; hook; hook = hook->next)
512 if (hook->kind == GIF_T_STREAM)
513 (*hook->func)(GIF_T_STREAM, gfs, hook->callback_data);
514 Gif_Delete(gfs);
515 }
516
517
518 void
Gif_DeleteImage(Gif_Image * gfi)519 Gif_DeleteImage(Gif_Image *gfi)
520 {
521 Gif_DeletionHook *hook;
522 if (!gfi || --gfi->refcount > 0)
523 return;
524
525 for (hook = all_hooks; hook; hook = hook->next)
526 if (hook->kind == GIF_T_IMAGE)
527 (*hook->func)(GIF_T_IMAGE, gfi, hook->callback_data);
528
529 Gif_DeleteArray(gfi->identifier);
530 Gif_DeleteComment(gfi->comment);
531 while (gfi->extension_list)
532 Gif_DeleteExtension(gfi->extension_list);
533 Gif_DeleteColormap(gfi->local);
534 if (gfi->image_data && gfi->free_image_data)
535 (*gfi->free_image_data)((void *)gfi->image_data);
536 Gif_DeleteArray(gfi->img);
537 if (gfi->compressed && gfi->free_compressed)
538 (*gfi->free_compressed)((void *)gfi->compressed);
539 if (gfi->user_data && gfi->free_user_data)
540 (*gfi->free_user_data)(gfi->user_data);
541 Gif_Delete(gfi);
542 }
543
544
545 void
Gif_DeleteColormap(Gif_Colormap * gfcm)546 Gif_DeleteColormap(Gif_Colormap *gfcm)
547 {
548 Gif_DeletionHook *hook;
549 if (!gfcm || --gfcm->refcount > 0)
550 return;
551
552 for (hook = all_hooks; hook; hook = hook->next)
553 if (hook->kind == GIF_T_COLORMAP)
554 (*hook->func)(GIF_T_COLORMAP, gfcm, hook->callback_data);
555
556 Gif_DeleteArray(gfcm->col);
557 Gif_Delete(gfcm);
558 }
559
560
561 void
Gif_DeleteComment(Gif_Comment * gfcom)562 Gif_DeleteComment(Gif_Comment *gfcom)
563 {
564 int i;
565 if (!gfcom)
566 return;
567 for (i = 0; i < gfcom->count; i++)
568 Gif_DeleteArray(gfcom->str[i]);
569 Gif_DeleteArray(gfcom->str);
570 Gif_DeleteArray(gfcom->len);
571 Gif_Delete(gfcom);
572 }
573
574
575 void
Gif_DeleteExtension(Gif_Extension * gfex)576 Gif_DeleteExtension(Gif_Extension *gfex)
577 {
578 if (!gfex)
579 return;
580 if (gfex->data && gfex->free_data)
581 (*gfex->free_data)(gfex->data);
582 Gif_DeleteArray(gfex->appname);
583 if (gfex->stream || gfex->image) {
584 Gif_Extension** pprev;
585 if (gfex->image)
586 pprev = &gfex->image->extension_list;
587 else
588 pprev = &gfex->stream->end_extension_list;
589 while (*pprev && *pprev != gfex)
590 pprev = &(*pprev)->next;
591 if (*pprev)
592 *pprev = gfex->next;
593 }
594 Gif_Delete(gfex);
595 }
596
597
598 /** DELETION HOOKS **/
599
600 int
Gif_AddDeletionHook(int kind,void (* func)(int,void *,void *),void * cb)601 Gif_AddDeletionHook(int kind, void (*func)(int, void *, void *), void *cb)
602 {
603 Gif_DeletionHook *hook = Gif_New(Gif_DeletionHook);
604 if (!hook)
605 return 0;
606 Gif_RemoveDeletionHook(kind, func, cb);
607 hook->kind = kind;
608 hook->func = func;
609 hook->callback_data = cb;
610 hook->next = all_hooks;
611 all_hooks = hook;
612 return 1;
613 }
614
615 void
Gif_RemoveDeletionHook(int kind,void (* func)(int,void *,void *),void * cb)616 Gif_RemoveDeletionHook(int kind, void (*func)(int, void *, void *), void *cb)
617 {
618 Gif_DeletionHook *hook = all_hooks, *prev = 0;
619 while (hook) {
620 if (hook->kind == kind && hook->func == func
621 && hook->callback_data == cb) {
622 if (prev)
623 prev->next = hook->next;
624 else
625 all_hooks = hook->next;
626 Gif_Delete(hook);
627 return;
628 }
629 prev = hook;
630 hook = hook->next;
631 }
632 }
633
634
635 int
Gif_ColorEq(Gif_Color * c1,Gif_Color * c2)636 Gif_ColorEq(Gif_Color *c1, Gif_Color *c2)
637 {
638 return GIF_COLOREQ(c1, c2);
639 }
640
641
642 int
Gif_FindColor(Gif_Colormap * gfcm,Gif_Color * c)643 Gif_FindColor(Gif_Colormap *gfcm, Gif_Color *c)
644 {
645 int i;
646 for (i = 0; i < gfcm->ncol; i++)
647 if (GIF_COLOREQ(&gfcm->col[i], c))
648 return i;
649 return -1;
650 }
651
652
653 int
Gif_AddColor(Gif_Colormap * gfcm,Gif_Color * c,int look_from)654 Gif_AddColor(Gif_Colormap *gfcm, Gif_Color *c, int look_from)
655 {
656 int i;
657 if (look_from >= 0)
658 for (i = look_from; i < gfcm->ncol; i++)
659 if (GIF_COLOREQ(&gfcm->col[i], c))
660 return i;
661 if (gfcm->ncol >= gfcm->capacity) {
662 gfcm->capacity *= 2;
663 Gif_ReArray(gfcm->col, Gif_Color, gfcm->capacity);
664 if (gfcm->col == 0)
665 return -1;
666 }
667 i = gfcm->ncol;
668 gfcm->ncol++;
669 gfcm->col[i] = *c;
670 return i;
671 }
672
673
674 Gif_Image *
Gif_GetImage(Gif_Stream * gfs,int imagenumber)675 Gif_GetImage(Gif_Stream *gfs, int imagenumber)
676 {
677 if (imagenumber >= 0 && imagenumber < gfs->nimages)
678 return gfs->images[imagenumber];
679 else
680 return 0;
681 }
682
683
684 Gif_Image *
Gif_GetNamedImage(Gif_Stream * gfs,const char * name)685 Gif_GetNamedImage(Gif_Stream *gfs, const char *name)
686 {
687 int i;
688
689 if (!name)
690 return gfs->nimages ? gfs->images[0] : 0;
691
692 for (i = 0; i < gfs->nimages; i++)
693 if (gfs->images[i]->identifier &&
694 strcmp(gfs->images[i]->identifier, name) == 0)
695 return gfs->images[i];
696
697 return 0;
698 }
699
700
701 void
Gif_ReleaseCompressedImage(Gif_Image * gfi)702 Gif_ReleaseCompressedImage(Gif_Image *gfi)
703 {
704 if (gfi->compressed && gfi->free_compressed)
705 (*gfi->free_compressed)(gfi->compressed);
706 gfi->compressed = 0;
707 gfi->compressed_len = 0;
708 gfi->compressed_errors = 0;
709 gfi->free_compressed = 0;
710 }
711
712 void
Gif_ReleaseUncompressedImage(Gif_Image * gfi)713 Gif_ReleaseUncompressedImage(Gif_Image *gfi)
714 {
715 Gif_DeleteArray(gfi->img);
716 if (gfi->image_data && gfi->free_image_data)
717 (*gfi->free_image_data)(gfi->image_data);
718 gfi->img = 0;
719 gfi->image_data = 0;
720 gfi->free_image_data = 0;
721 }
722
723
724 int
Gif_ClipImage(Gif_Image * gfi,int left,int top,int width,int height)725 Gif_ClipImage(Gif_Image *gfi, int left, int top, int width, int height)
726 {
727 int new_width = gfi->width, new_height = gfi->height;
728 int y;
729
730 if (!gfi->img)
731 return 0;
732
733 if (gfi->left < left) {
734 int shift = left - gfi->left;
735 for (y = 0; y < gfi->height; y++)
736 gfi->img[y] += shift;
737 gfi->left += shift;
738 new_width -= shift;
739 }
740
741 if (gfi->top < top) {
742 int shift = top - gfi->top;
743 for (y = gfi->height - 1; y >= shift; y++)
744 gfi->img[y - shift] = gfi->img[y];
745 gfi->top += shift;
746 new_height -= shift;
747 }
748
749 if (gfi->left + new_width >= width)
750 new_width = width - gfi->left;
751
752 if (gfi->top + new_height >= height)
753 new_height = height - gfi->top;
754
755 if (new_width < 0)
756 new_width = 0;
757 if (new_height < 0)
758 new_height = 0;
759 gfi->width = new_width;
760 gfi->height = new_height;
761 return 1;
762 }
763
764
765 int
Gif_InterlaceLine(int line,int height)766 Gif_InterlaceLine(int line, int height)
767 {
768 height--;
769 if (line > height / 2)
770 return line * 2 - ( height | 1);
771 else if (line > height / 4)
772 return line * 4 - ((height & ~1) | 2);
773 else if (line > height / 8)
774 return line * 8 - ((height & ~3) | 4);
775 else
776 return line * 8;
777 }
778
779
780 int
Gif_SetUncompressedImage(Gif_Image * gfi,uint8_t * image_data,void (* free_data)(void *),int data_interlaced)781 Gif_SetUncompressedImage(Gif_Image *gfi, uint8_t *image_data,
782 void (*free_data)(void *), int data_interlaced)
783 {
784 /* NB does not affect compressed image (and must not) */
785 unsigned i;
786 unsigned width = gfi->width;
787 unsigned height = gfi->height;
788 uint8_t **img;
789
790 Gif_ReleaseUncompressedImage(gfi);
791 if (!image_data)
792 return 0;
793
794 img = Gif_NewArray(uint8_t *, height + 1);
795 if (!img)
796 return 0;
797
798 if (data_interlaced)
799 for (i = 0; i < height; i++)
800 img[ Gif_InterlaceLine(i, height) ] = image_data + width * i;
801 else
802 for (i = 0; i < height; i++)
803 img[i] = image_data + width * i;
804 img[height] = 0;
805
806 gfi->img = img;
807 gfi->image_data = image_data;
808 gfi->free_image_data = free_data;
809 return 1;
810 }
811
812 int
Gif_CreateUncompressedImage(Gif_Image * gfi,int data_interlaced)813 Gif_CreateUncompressedImage(Gif_Image *gfi, int data_interlaced)
814 {
815 size_t sz = (size_t) gfi->width * (size_t) gfi->height;
816 uint8_t *data = Gif_NewArray(uint8_t, sz ? sz : 1);
817 return Gif_SetUncompressedImage(gfi, data, Gif_Free, data_interlaced);
818 }
819
820 void
Gif_InitCompressInfo(Gif_CompressInfo * gcinfo)821 Gif_InitCompressInfo(Gif_CompressInfo *gcinfo)
822 {
823 gcinfo->flags = 0;
824 gcinfo->loss = 0;
825 }
826
827
828 void
Gif_Debug(char * x,...)829 Gif_Debug(char *x, ...)
830 {
831 va_list val;
832 va_start(val, x);
833 vfprintf(stderr, x, val);
834 va_end(val);
835 }
836
837
838 #if !GIF_ALLOCATOR_DEFINED
Gif_Realloc(void * p,size_t s,size_t n,const char * file,int line)839 void* Gif_Realloc(void* p, size_t s, size_t n, const char* file, int line) {
840 (void) file, (void) line;
841 if (s == 0 || n == 0)
842 Gif_Free(p);
843 else if (s == 1 || n == 1 || s <= ((size_t) -1) / n)
844 return realloc(p, s * n);
845 return (void*) 0;
846 }
847
848 #undef Gif_Free
Gif_Free(void * p)849 void Gif_Free(void* p) {
850 free(p);
851 }
852 #endif
853
854 #ifdef __cplusplus
855 }
856 #endif
857