Added an Imager::log_entry() function and some extra logging
[imager.git] / gif.c
CommitLineData
02d1d628
AMH
1#include "image.h"
2#include <gif_lib.h>
3
5b0d044f
AMH
4/* XXX: Reading still needs to support reading all those gif properties */
5
a3923855
TC
6/*
7=head1 NAME
8
9gif.c - read and write gif files for Imager
10
11=head1 SYNOPSIS
12
13 i_img *img;
14 i_img *imgs[count];
15 int fd;
16 int *colour_table,
17 int colours;
18 int max_colours; // number of bits per colour
19 int pixdev; // how much noise to add
20 i_color fixed[N]; // fixed palette entries
21 int fixedlen; // number of fixed colours
22 int success; // non-zero on success
3bb1c1f3 23 char *data; // a GIF file in memory
a3923855
TC
24 int length; // how big data is
25 int reader(char *, char *, int, int);
26 int writer(char *, char *, int);
27 char *userdata; // user's data, whatever it is
28 i_quantize quant;
29 i_gif_opts opts;
30
31 img = i_readgif(fd, &colour_table, &colours);
32 success = i_writegif(img, fd, max_colours, pixdev, fixedlen, fixed);
33 success = i_writegifmc(img, fd, max_colours);
34 img = i_readgif_scalar(data, length, &colour_table, &colours);
35 img = i_readgif_callback(cb, userdata, &colour_table, &colours);
36 success = i_writegif_gen(&quant, fd, imgs, count, &opts);
37 success = i_writegif_callback(&quant, writer, userdata, maxlength,
38 imgs, count, &opts);
39
40=head1 DESCRIPTION
41
42This source file provides the C level interface to reading and writing
43GIF files for Imager.
44
45This has been tested with giflib 3 and 4, though you lose the callback
46functionality with giflib3.
47
48=head1 REFERENCE
49
50=over
51
52=cut
53*/
02d1d628 54
c48818b1 55static char const *gif_error_msg(int code);
faa9b3e7 56static void gif_push_error(void);
c48818b1 57
02d1d628
AMH
58#if IM_GIFMAJOR >= 4
59
faa9b3e7
TC
60static int gif_read_callback(GifFileType *gft, GifByteType *buf, int length);
61
a3923855
TC
62/*
63=item gif_scalar_info
64
65Internal. A structure passed to the reader function used for reading
66GIFs from scalars.
67
68Used with giflib 4 and later.
69
70=cut
71*/
72
02d1d628
AMH
73struct gif_scalar_info {
74 char *data;
75 int length;
76 int cpos;
77};
78
a3923855
TC
79/*
80=item my_gif_inputfunc(GifFileType *gft, GifByteType *buf, int length)
81
82Internal. The reader callback passed to giflib.
83
84Used with giflib 4 and later.
85
86=cut
87*/
88
02d1d628
AMH
89int
90my_gif_inputfunc(GifFileType* gft, GifByteType *buf,int length) {
91 struct gif_scalar_info *gsi=(struct gif_scalar_info *)gft->UserData;
92 /* fprintf(stderr,"my_gif_inputfunc: length=%d cpos=%d tlength=%d\n",length,gsi->cpos,gsi->length); */
93
94 if (gsi->cpos == gsi->length) return 0;
95 if (gsi->cpos+length > gsi->length) length=gsi->length-gsi->cpos; /* Don't read too much */
96 memcpy(buf,gsi->data+gsi->cpos,length);
97 gsi->cpos+=length;
98 return length;
99}
100
101#endif
102
02d1d628 103
02d1d628
AMH
104
105/* Make some variables global, so we could access them faster: */
106
107static int
2ff8ed30
AMH
108 InterlacedOffset[] = { 0, 4, 2, 1 }, /* The way Interlaced image should. */
109 InterlacedJumps[] = { 8, 8, 4, 2 }; /* be read - offsets and jumps... */
7828ca98 110
02d1d628 111
7828ca98
AMH
112
113static
114void
2ff8ed30 115i_colortable_copy(int **colour_table, int *colours, ColorMapObject *colourmap) {
7828ca98
AMH
116 GifColorType *mapentry;
117 int q;
2ff8ed30 118 int colourmapsize = colourmap->ColorCount;
7828ca98 119
2ff8ed30 120 if(colours) *colours = colourmapsize;
7828ca98
AMH
121 if(!colour_table) return;
122
2d20f216
TC
123 *colour_table = mymalloc(sizeof(int) * colourmapsize * 3);
124 memset(*colour_table, 0, sizeof(int) * colourmapsize * 3);
7828ca98 125
2ff8ed30
AMH
126 for(q=0; q<colourmapsize; q++) {
127 mapentry = &colourmap->Colors[q];
7828ca98
AMH
128 (*colour_table)[q*3 + 0] = mapentry->Red;
129 (*colour_table)[q*3 + 1] = mapentry->Green;
130 (*colour_table)[q*3 + 2] = mapentry->Blue;
131 }
132}
133
134
a3923855
TC
135/*
136=item i_readgif_low(GifFileType *GifFile, int **colour_table, int *colours)
137
138Internal. Low-level function for reading a GIF file. The caller must
139create the appropriate GifFileType object and pass it in.
140
141=cut
142*/
7828ca98 143
02d1d628
AMH
144i_img *
145i_readgif_low(GifFileType *GifFile, int **colour_table, int *colours) {
146 i_img *im;
147 int i, j, Size, Row, Col, Width, Height, ExtCode, Count, x;
2ff8ed30
AMH
148 int cmapcnt = 0, ImageNum = 0, BackGround = 0, ColorMapSize = 0;
149 ColorMapObject *ColorMap;
98c79495 150
02d1d628
AMH
151 GifRecordType RecordType;
152 GifByteType *Extension;
153
154 GifRowType GifRow;
155 static GifColorType *ColorMapEntry;
156 i_color col;
157
02d1d628
AMH
158 mm_log((1,"i_readgif_low(GifFile %p, colour_table %p, colours %p)\n", GifFile, colour_table, colours));
159
e6172a17
TC
160 /* it's possible that the caller has called us with *colour_table being
161 non-NULL, but we check that to see if we need to free an allocated
162 colour table on error.
163 */
895dbd34 164 if (colour_table) *colour_table = NULL;
e6172a17 165
02d1d628
AMH
166 BackGround = GifFile->SBackGroundColor;
167 ColorMap = (GifFile->Image.ColorMap ? GifFile->Image.ColorMap : GifFile->SColorMap);
02d1d628 168
7828ca98
AMH
169 if (ColorMap) {
170 ColorMapSize = ColorMap->ColorCount;
171 i_colortable_copy(colour_table, colours, ColorMap);
172 cmapcnt++;
02d1d628 173 }
02d1d628 174
7828ca98 175
895dbd34 176 im = i_img_empty_ch(NULL, GifFile->SWidth, GifFile->SHeight, 3);
7828ca98 177
02d1d628
AMH
178 Size = GifFile->SWidth * sizeof(GifPixelType);
179
5b0d044f 180 GifRow = (GifRowType) mymalloc(Size);
02d1d628
AMH
181
182 for (i = 0; i < GifFile->SWidth; i++) GifRow[i] = GifFile->SBackGroundColor;
183
184 /* Scan the content of the GIF file and load the image(s) in: */
185 do {
186 if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR) {
77fc6afd
TC
187 gif_push_error();
188 i_push_error(0, "Unable to get record type");
e6172a17 189 if (colour_table && *colour_table) {
ea9f6207 190 myfree(*colour_table);
e6172a17
TC
191 *colour_table = NULL;
192 }
77fc6afd
TC
193 i_img_destroy(im);
194 DGifCloseFile(GifFile);
195 return NULL;
02d1d628
AMH
196 }
197
198 switch (RecordType) {
199 case IMAGE_DESC_RECORD_TYPE:
200 if (DGifGetImageDesc(GifFile) == GIF_ERROR) {
77fc6afd
TC
201 gif_push_error();
202 i_push_error(0, "Unable to get image descriptor");
e6172a17 203 if (colour_table && *colour_table) {
ea9f6207 204 myfree(*colour_table);
e6172a17
TC
205 *colour_table = NULL;
206 }
77fc6afd
TC
207 i_img_destroy(im);
208 DGifCloseFile(GifFile);
209 return NULL;
02d1d628 210 }
7828ca98 211
43a881d3
TC
212 if (( ColorMap = (GifFile->Image.ColorMap ? GifFile->Image.ColorMap : GifFile->SColorMap) )) {
213 mm_log((1, "Adding local colormap\n"));
214 ColorMapSize = ColorMap->ColorCount;
215 if ( cmapcnt == 0) {
7828ca98
AMH
216 i_colortable_copy(colour_table, colours, ColorMap);
217 cmapcnt++;
7828ca98 218 }
43a881d3
TC
219 } else {
220 /* No colormap and we are about to read in the image - abandon for now */
221 mm_log((1, "Going in with no colormap\n"));
222 i_push_error(0, "Image does not have a local or a global color map");
223 /* we can't have allocated a colour table here */
224 i_img_destroy(im);
225 DGifCloseFile(GifFile);
226 return NULL;
7828ca98 227 }
43a881d3 228
02d1d628
AMH
229 Row = GifFile->Image.Top; /* Image Position relative to Screen. */
230 Col = GifFile->Image.Left;
231 Width = GifFile->Image.Width;
232 Height = GifFile->Image.Height;
233 ImageNum++;
895dbd34 234 mm_log((1,"i_readgif_low: Image %d at (%d, %d) [%dx%d]: \n",ImageNum, Col, Row, Width, Height));
02d1d628
AMH
235
236 if (GifFile->Image.Left + GifFile->Image.Width > GifFile->SWidth ||
237 GifFile->Image.Top + GifFile->Image.Height > GifFile->SHeight) {
77fc6afd 238 i_push_errorf(0, "Image %d is not confined to screen dimension, aborted.\n",ImageNum);
e6172a17 239 if (colour_table && *colour_table) {
ea9f6207 240 myfree(*colour_table);
e6172a17
TC
241 *colour_table = NULL;
242 }
77fc6afd
TC
243 i_img_destroy(im);
244 DGifCloseFile(GifFile);
02d1d628
AMH
245 return(0);
246 }
247 if (GifFile->Image.Interlace) {
248
249 for (Count = i = 0; i < 4; i++) for (j = Row + InterlacedOffset[i]; j < Row + Height; j += InterlacedJumps[i]) {
250 Count++;
43a881d3 251 if (DGifGetLine(GifFile, GifRow, Width) == GIF_ERROR) {
77fc6afd
TC
252 gif_push_error();
253 i_push_error(0, "Reading GIF line");
e6172a17 254 if (colour_table && *colour_table) {
ea9f6207 255 myfree(*colour_table);
e6172a17
TC
256 *colour_table = NULL;
257 }
77fc6afd
TC
258 i_img_destroy(im);
259 DGifCloseFile(GifFile);
260 return NULL;
02d1d628
AMH
261 }
262
43a881d3 263 for (x = 0; x < Width; x++) {
02d1d628
AMH
264 ColorMapEntry = &ColorMap->Colors[GifRow[x]];
265 col.rgb.r = ColorMapEntry->Red;
266 col.rgb.g = ColorMapEntry->Green;
267 col.rgb.b = ColorMapEntry->Blue;
43a881d3 268 i_ppix(im,Col+x,j,&col);
02d1d628
AMH
269 }
270
271 }
272 }
273 else {
274 for (i = 0; i < Height; i++) {
43a881d3 275 if (DGifGetLine(GifFile, GifRow, Width) == GIF_ERROR) {
77fc6afd
TC
276 gif_push_error();
277 i_push_error(0, "Reading GIF line");
e6172a17 278 if (colour_table && *colour_table) {
ea9f6207 279 myfree(*colour_table);
e6172a17
TC
280 *colour_table = NULL;
281 }
77fc6afd
TC
282 i_img_destroy(im);
283 DGifCloseFile(GifFile);
284 return NULL;
02d1d628
AMH
285 }
286
43a881d3 287 for (x = 0; x < Width; x++) {
02d1d628
AMH
288 ColorMapEntry = &ColorMap->Colors[GifRow[x]];
289 col.rgb.r = ColorMapEntry->Red;
290 col.rgb.g = ColorMapEntry->Green;
291 col.rgb.b = ColorMapEntry->Blue;
43a881d3 292 i_ppix(im, Col+x, Row, &col);
02d1d628
AMH
293 }
294 Row++;
295 }
296 }
297 break;
298 case EXTENSION_RECORD_TYPE:
299 /* Skip any extension blocks in file: */
300 if (DGifGetExtension(GifFile, &ExtCode, &Extension) == GIF_ERROR) {
77fc6afd
TC
301 gif_push_error();
302 i_push_error(0, "Reading extension record");
e6172a17 303 if (colour_table && *colour_table) {
ea9f6207 304 myfree(*colour_table);
e6172a17
TC
305 *colour_table = NULL;
306 }
77fc6afd
TC
307 i_img_destroy(im);
308 DGifCloseFile(GifFile);
309 return NULL;
02d1d628
AMH
310 }
311 while (Extension != NULL) {
312 if (DGifGetExtensionNext(GifFile, &Extension) == GIF_ERROR) {
77fc6afd
TC
313 gif_push_error();
314 i_push_error(0, "reading next block of extension");
e6172a17 315 if (colour_table && *colour_table) {
ea9f6207 316 myfree(*colour_table);
e6172a17
TC
317 *colour_table = NULL;
318 }
77fc6afd
TC
319 i_img_destroy(im);
320 DGifCloseFile(GifFile);
321 return NULL;
02d1d628
AMH
322 }
323 }
324 break;
325 case TERMINATE_RECORD_TYPE:
326 break;
327 default: /* Should be traps by DGifGetRecordType. */
328 break;
329 }
330 } while (RecordType != TERMINATE_RECORD_TYPE);
331
332 myfree(GifRow);
333
334 if (DGifCloseFile(GifFile) == GIF_ERROR) {
77fc6afd
TC
335 gif_push_error();
336 i_push_error(0, "Closing GIF file object");
e6172a17 337 if (colour_table && *colour_table) {
ea9f6207 338 myfree(*colour_table);
e6172a17
TC
339 *colour_table = NULL;
340 }
77fc6afd
TC
341 i_img_destroy(im);
342 return NULL;
02d1d628
AMH
343 }
344 return im;
345}
346
a3923855
TC
347/*
348=item i_readgif(int fd, int **colour_table, int *colours)
349
350Reads in a GIF file from a file handle and converts it to an Imager
351RGB image object.
352
353Returns the palette for the object in colour_table for colours
354colours.
355
356Returns NULL on failure.
357
358=cut
359*/
02d1d628
AMH
360
361i_img *
362i_readgif(int fd, int **colour_table, int *colours) {
363 GifFileType *GifFile;
77fc6afd
TC
364
365 i_clear_error();
02d1d628
AMH
366
367 mm_log((1,"i_readgif(fd %d, colour_table %p, colours %p)\n", fd, colour_table, colours));
368
369 if ((GifFile = DGifOpenFileHandle(fd)) == NULL) {
77fc6afd
TC
370 gif_push_error();
371 i_push_error(0, "Cannot create giflib file object");
02d1d628
AMH
372 mm_log((1,"i_readgif: Unable to open file\n"));
373 return NULL;
374 }
375
376 return i_readgif_low(GifFile, colour_table, colours);
377}
378
faa9b3e7
TC
379/*
380
381Internal function called by i_readgif_multi_low() in error handling
382
383*/
384static void free_images(i_img **imgs, int count) {
385 int i;
386 for (i = 0; i < count; ++i)
387 i_img_destroy(imgs[i]);
388 myfree(imgs);
389}
390
391/*
392=item i_readgif_multi_low(GifFileType *gf, int *count)
393
394Reads one of more gif images from the given GIF file.
395
396Returns a pointer to an array of i_img *, and puts the count into
397*count.
398
399Unlike the normal i_readgif*() functions the images are paletted
400images rather than a combined RGB image.
401
402This functions sets tags on the images returned:
403
404=over
405
406=item gif_left
407
408the offset of the image from the left of the "screen" ("Image Left
409Position")
410
411=item gif_top
412
413the offset of the image from the top of the "screen" ("Image Top Position")
414
415=item gif_interlace
416
417non-zero if the image was interlaced ("Interlace Flag")
418
419=item gif_screen_width
420
421=item gif_screen_height
422
423the size of the logical screen ("Logical Screen Width",
424"Logical Screen Height")
425
426=item gif_local_map
427
428Non-zero if this image had a local color map.
429
430=item gif_background
431
432The index in the global colormap of the logical screen's background
433color. This is only set if the current image uses the global
434colormap.
435
436=item gif_trans_index
437
438The index of the color in the colormap used for transparency. If the
439image has a transparency then it is returned as a 4 channel image with
440the alpha set to zero in this palette entry. ("Transparent Color Index")
441
442=item gif_delay
443
444The delay until the next frame is displayed, in 1/100 of a second.
445("Delay Time").
446
447=item gif_user_input
448
449whether or not a user input is expected before continuing (view dependent)
450("User Input Flag").
451
452=item gif_disposal
453
454how the next frame is displayed ("Disposal Method")
455
456=item gif_loop
457
458the number of loops from the Netscape Loop extension. This may be zero.
459
460=item gif_comment
461
462the first block of the first gif comment before each image.
463
464=back
465
466Where applicable, the ("name") is the name of that field from the GIF89
467standard.
468
469=cut
470*/
471
472i_img **i_readgif_multi_low(GifFileType *GifFile, int *count) {
473 i_img *img;
ef7ab4d6 474 int i, j, Size, Width, Height, ExtCode, Count, x;
faa9b3e7
TC
475 int ImageNum = 0, BackGround = 0, ColorMapSize = 0;
476 ColorMapObject *ColorMap;
477
478 GifRecordType RecordType;
479 GifByteType *Extension;
480
481 GifRowType GifRow;
482 int got_gce = 0;
483 int trans_index; /* transparent index if we see a GCE */
484 int gif_delay; /* delay from a GCE */
485 int user_input; /* user input flag from a GCE */
486 int disposal; /* disposal method from a GCE */
487 int got_ns_loop = 0;
488 int ns_loop;
489 char *comment = NULL; /* a comment */
490 i_img **results = NULL;
491 int result_alloc = 0;
492 int channels;
493
494 *count = 0;
495
496 mm_log((1,"i_readgif_multi_low(GifFile %p, , count %p)\n", GifFile, count));
497
498 BackGround = GifFile->SBackGroundColor;
499
500 Size = GifFile->SWidth * sizeof(GifPixelType);
501
502 if ((GifRow = (GifRowType) mymalloc(Size)) == NULL)
503 m_fatal(0,"Failed to allocate memory required, aborted."); /* First row. */
504
505 /* Scan the content of the GIF file and load the image(s) in: */
506 do {
507 if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR) {
508 gif_push_error();
509 i_push_error(0, "Unable to get record type");
510 free_images(results, *count);
511 DGifCloseFile(GifFile);
512 return NULL;
513 }
514
515 switch (RecordType) {
516 case IMAGE_DESC_RECORD_TYPE:
517 if (DGifGetImageDesc(GifFile) == GIF_ERROR) {
518 gif_push_error();
519 i_push_error(0, "Unable to get image descriptor");
520 free_images(results, *count);
521 DGifCloseFile(GifFile);
522 return NULL;
523 }
524
525 if (( ColorMap = (GifFile->Image.ColorMap ? GifFile->Image.ColorMap : GifFile->SColorMap) )) {
526 mm_log((1, "Adding local colormap\n"));
527 ColorMapSize = ColorMap->ColorCount;
528 } else {
529 /* No colormap and we are about to read in the image -
530 abandon for now */
531 mm_log((1, "Going in with no colormap\n"));
532 i_push_error(0, "Image does not have a local or a global color map");
533 free_images(results, *count);
534 DGifCloseFile(GifFile);
535 return NULL;
536 }
537
538 Width = GifFile->Image.Width;
539 Height = GifFile->Image.Height;
540 channels = 3;
541 if (got_gce && trans_index >= 0)
542 channels = 4;
543 img = i_img_pal_new(Width, Height, channels, 256);
544 /* populate the palette of the new image */
7f882a01 545 mm_log((1, "ColorMapSize %d\n", ColorMapSize));
faa9b3e7
TC
546 for (i = 0; i < ColorMapSize; ++i) {
547 i_color col;
548 col.rgba.r = ColorMap->Colors[i].Red;
549 col.rgba.g = ColorMap->Colors[i].Green;
550 col.rgba.b = ColorMap->Colors[i].Blue;
551 if (channels == 4 && trans_index == i)
552 col.rgba.a = 0;
553 else
554 col.rgba.a = 255;
555
556 i_addcolors(img, &col, 1);
557 }
558 ++*count;
559 if (*count > result_alloc) {
560 if (result_alloc == 0) {
561 result_alloc = 5;
562 results = mymalloc(result_alloc * sizeof(i_img *));
563 }
564 else {
565 i_img **newresults;
566 result_alloc *= 2;
567 newresults = myrealloc(results, result_alloc * sizeof(i_img *));
568 }
569 }
570 results[*count-1] = img;
571 i_tags_addn(&img->tags, "gif_left", 0, GifFile->Image.Left);
572 /**(char *)0 = 1;*/
573 i_tags_addn(&img->tags, "gif_top", 0, GifFile->Image.Top);
574 i_tags_addn(&img->tags, "gif_interlace", 0, GifFile->Image.Interlace);
575 i_tags_addn(&img->tags, "gif_screen_width", 0, GifFile->SWidth);
576 i_tags_addn(&img->tags, "gif_screen_height", 0, GifFile->SHeight);
577 if (GifFile->SColorMap && !GifFile->Image.ColorMap) {
578 i_tags_addn(&img->tags, "gif_background", 0,
579 GifFile->SBackGroundColor);
580 }
581 if (GifFile->Image.ColorMap) {
582 i_tags_addn(&img->tags, "gif_localmap", 0, 1);
583 }
faa9b3e7
TC
584 if (got_gce) {
585 if (trans_index >= 0)
586 i_tags_addn(&img->tags, "gif_trans_index", 0, trans_index);
587 i_tags_addn(&img->tags, "gif_delay", 0, gif_delay);
588 i_tags_addn(&img->tags, "gif_user_input", 0, user_input);
589 i_tags_addn(&img->tags, "gif_disposal", 0, disposal);
590 }
591 got_gce = 0;
592 if (got_ns_loop)
593 i_tags_addn(&img->tags, "gif_loop", 0, ns_loop);
594 if (comment) {
595 i_tags_add(&img->tags, "gif_comment", 0, comment, strlen(comment), 0);
596 myfree(comment);
597 comment = NULL;
598 }
599
600 ImageNum++;
7f882a01 601 mm_log((1,"i_readgif_multi_low: Image %d at (%d, %d) [%dx%d]: \n",
ef7ab4d6 602 ImageNum, GifFile->Image.Left, GifFile->Image.Top, Width, Height));
faa9b3e7
TC
603
604 if (GifFile->Image.Left + GifFile->Image.Width > GifFile->SWidth ||
605 GifFile->Image.Top + GifFile->Image.Height > GifFile->SHeight) {
606 i_push_errorf(0, "Image %d is not confined to screen dimension, aborted.\n",ImageNum);
607 free_images(results, *count);
608 DGifCloseFile(GifFile);
609 return(0);
610 }
7f882a01 611
faa9b3e7
TC
612 if (GifFile->Image.Interlace) {
613 for (Count = i = 0; i < 4; i++) {
614 for (j = InterlacedOffset[i]; j < Height;
615 j += InterlacedJumps[i]) {
616 Count++;
617 if (DGifGetLine(GifFile, GifRow, Width) == GIF_ERROR) {
618 gif_push_error();
619 i_push_error(0, "Reading GIF line");
620 free_images(results, *count);
621 DGifCloseFile(GifFile);
622 return NULL;
623 }
624
625 i_ppal(img, 0, Width, j, GifRow);
626 }
627 }
628 }
629 else {
630 for (i = 0; i < Height; i++) {
631 if (DGifGetLine(GifFile, GifRow, Width) == GIF_ERROR) {
632 gif_push_error();
633 i_push_error(0, "Reading GIF line");
634 free_images(results, *count);
635 DGifCloseFile(GifFile);
636 return NULL;
637 }
638
639 i_ppal(img, 0, Width, i, GifRow);
640 }
641 }
642 break;
643 case EXTENSION_RECORD_TYPE:
644 /* Skip any extension blocks in file: */
645 if (DGifGetExtension(GifFile, &ExtCode, &Extension) == GIF_ERROR) {
646 gif_push_error();
647 i_push_error(0, "Reading extension record");
648 free_images(results, *count);
649 DGifCloseFile(GifFile);
650 return NULL;
651 }
652 if (ExtCode == 0xF9) {
653 got_gce = 1;
654 if (Extension[1] & 1)
655 trans_index = Extension[4];
656 else
657 trans_index = -1;
658 gif_delay = Extension[2] + 256 * Extension[3];
659 user_input = (Extension[0] & 2) != 0;
660 disposal = (Extension[0] >> 2) & 3;
661 }
662 if (ExtCode == 0xFF && *Extension == 11) {
663 if (memcmp(Extension+1, "NETSCAPE2.0", 11) == 0) {
664 if (DGifGetExtensionNext(GifFile, &Extension) == GIF_ERROR) {
665 gif_push_error();
666 i_push_error(0, "reading loop extension");
667 free_images(results, *count);
668 DGifCloseFile(GifFile);
669 return NULL;
670 }
671 if (Extension && *Extension == 3) {
672 got_ns_loop = 1;
673 ns_loop = Extension[2] + 256 * Extension[3];
674 }
675 }
676 }
677 else if (ExtCode == 0xFE) {
678 /* while it's possible for a GIF file to contain more than one
679 comment, I'm only implementing a single comment per image,
680 with the comment saved into the following image.
681 If someone wants more than that they can implement it.
682 I also don't handle comments that take more than one block.
683 */
684 if (!comment) {
685 comment = mymalloc(*Extension+1);
686 memcpy(comment, Extension+1, *Extension);
687 comment[*Extension] = '\0';
688 }
689 }
690 while (Extension != NULL) {
691 if (DGifGetExtensionNext(GifFile, &Extension) == GIF_ERROR) {
692 gif_push_error();
693 i_push_error(0, "reading next block of extension");
694 free_images(results, *count);
695 DGifCloseFile(GifFile);
696 return NULL;
697 }
698 }
699 break;
700 case TERMINATE_RECORD_TYPE:
701 break;
702 default: /* Should be trapped by DGifGetRecordType. */
703 break;
704 }
705 } while (RecordType != TERMINATE_RECORD_TYPE);
706
707 if (comment) {
708 if (*count) {
709 i_tags_add(&(results[*count-1]->tags), "gif_comment", 0, comment,
710 strlen(comment), 0);
711 }
712 myfree(comment);
713 }
714
715 myfree(GifRow);
716
717 if (DGifCloseFile(GifFile) == GIF_ERROR) {
718 gif_push_error();
719 i_push_error(0, "Closing GIF file object");
720 free_images(results, *count);
721 return NULL;
722 }
723
724 return results;
725}
726
727/*
728=item i_readgif_multi(int fd, int *count)
729
730=cut
731*/
732i_img **
733i_readgif_multi(int fd, int *count) {
734 GifFileType *GifFile;
735
736 i_clear_error();
737
738 mm_log((1,"i_readgif_multi(fd %d, &count %p)\n", fd, count));
739
740 if ((GifFile = DGifOpenFileHandle(fd)) == NULL) {
741 gif_push_error();
742 i_push_error(0, "Cannot create giflib file object");
743 mm_log((1,"i_readgif: Unable to open file\n"));
744 return NULL;
745 }
746
747 return i_readgif_multi_low(GifFile, count);
748}
749
750/*
751=item i_readgif_multi_scalar(char *data, int length, int *count)
752
753=cut
754*/
755i_img **
756i_readgif_multi_scalar(char *data, int length, int *count) {
757#if IM_GIFMAJOR >= 4
758 GifFileType *GifFile;
759 struct gif_scalar_info gsi;
760
761 i_clear_error();
762
763 gsi.cpos=0;
764 gsi.length=length;
765 gsi.data=data;
766
767 mm_log((1,"i_readgif_multi_scalar(data %p, length %d, &count %p)\n",
768 data, length, count));
769
770 if ((GifFile = DGifOpen( (void*) &gsi, my_gif_inputfunc )) == NULL) {
771 gif_push_error();
772 i_push_error(0, "Cannot create giflib callback object");
773 mm_log((1,"i_readgif_multi_scalar: Unable to open scalar datasource.\n"));
774 return NULL;
775 }
776
777 return i_readgif_multi_low(GifFile, count);
778#else
779 return NULL;
780#endif
781}
782
783/*
784=item i_readgif_callback(i_read_callback_t cb, char *userdata, int **colour_table, int *colours)
785
786Read a GIF file into an Imager RGB file, the data of the GIF file is
787retreived by callin the user supplied callback function.
788
789This function is only used with giflib 4 and higher.
790
791=cut
792*/
793
794i_img**
795i_readgif_multi_callback(i_read_callback_t cb, char *userdata, int *count) {
796#if IM_GIFMAJOR >= 4
797 GifFileType *GifFile;
798 i_img **result;
799
800 i_gen_read_data *gci = i_gen_read_data_new(cb, userdata);
801
802 i_clear_error();
803
804 mm_log((1,"i_readgif_multi_callback(callback %p, userdata %p, count %p)\n", cb, userdata, count));
805 if ((GifFile = DGifOpen( (void*) gci, gif_read_callback )) == NULL) {
806 gif_push_error();
807 i_push_error(0, "Cannot create giflib callback object");
808 mm_log((1,"i_readgif_callback: Unable to open callback datasource.\n"));
809 myfree(gci);
810 return NULL;
811 }
812
813 result = i_readgif_multi_low(GifFile, count);
814 free_gen_read_data(gci);
815
816 return result;
817#else
818 return NULL;
819#endif
820}
821
a3923855
TC
822/*
823=item i_writegif(i_img *im, int fd, int max_colors, int pixdev, int fixedlen, i_color fixed[])
824
825Write I<img> to the file handle I<fd>. The resulting GIF will use a
826maximum of 1<<I<max_colours> colours, with the first I<fixedlen>
827colours taken from I<fixed>.
828
829Returns non-zero on success.
830
831=cut
832*/
02d1d628
AMH
833
834undef_int
5b0d044f 835i_writegif(i_img *im, int fd, int max_colors, int pixdev, int fixedlen, i_color fixed[]) {
02d1d628
AMH
836 i_color colors[256];
837 i_quantize quant;
838 i_gif_opts opts;
839
840 memset(&quant, 0, sizeof(quant));
841 memset(&opts, 0, sizeof(opts));
842 quant.make_colors = mc_addi;
843 quant.mc_colors = colors;
844 quant.mc_size = 1<<max_colors;
845 quant.mc_count = fixedlen;
846 memcpy(colors, fixed, fixedlen * sizeof(i_color));
847 quant.translate = pt_perturb;
848 quant.perturb = pixdev;
849 return i_writegif_gen(&quant, fd, &im, 1, &opts);
850}
851
a3923855
TC
852/*
853=item i_writegifmc(i_img *im, int fd, int max_colors)
854
855Write I<img> to the file handle I<fd>. The resulting GIF will use a
856maximum of 1<<I<max_colours> colours.
857
858Returns non-zero on success.
859
860=cut
861*/
862
02d1d628
AMH
863undef_int
864i_writegifmc(i_img *im, int fd, int max_colors) {
865 i_color colors[256];
866 i_quantize quant;
867 i_gif_opts opts;
868
869 memset(&quant, 0, sizeof(quant));
870 memset(&opts, 0, sizeof(opts));
871 quant.make_colors = mc_none; /* ignored for pt_giflib */
872 quant.mc_colors = colors;
873 quant.mc_size = 1 << max_colors;
874 quant.mc_count = 0;
875 quant.translate = pt_giflib;
876 return i_writegif_gen(&quant, fd, &im, 1, &opts);
877}
878
02d1d628 879
a3923855
TC
880/*
881=item i_readgif_scalar(char *data, int length, int **colour_table, int *colours)
882
883Reads a GIF file from an in memory copy of the file. This can be used
884if you get the 'file' from some source other than an actual file (or
885some other file handle).
886
887This function is only available with giflib 4 and higher.
888
889=cut
890*/
02d1d628
AMH
891i_img*
892i_readgif_scalar(char *data, int length, int **colour_table, int *colours) {
893#if IM_GIFMAJOR >= 4
894 GifFileType *GifFile;
02d1d628
AMH
895 struct gif_scalar_info gsi;
896
77fc6afd
TC
897 i_clear_error();
898
02d1d628
AMH
899 gsi.cpos=0;
900 gsi.length=length;
901 gsi.data=data;
902
903 mm_log((1,"i_readgif_scalar(char* data, int length, colour_table %p, colours %p)\n", data, length, colour_table, colours));
904 if ((GifFile = DGifOpen( (void*) &gsi, my_gif_inputfunc )) == NULL) {
77fc6afd
TC
905 gif_push_error();
906 i_push_error(0, "Cannot create giflib callback object");
02d1d628
AMH
907 mm_log((1,"i_readgif_scalar: Unable to open scalar datasource.\n"));
908 return NULL;
909 }
910
911 return i_readgif_low(GifFile, colour_table, colours);
912#else
913 return NULL;
914#endif
915}
916
917#if IM_GIFMAJOR >= 4
918
a3923855
TC
919/*
920=item gif_read_callback(GifFileType *gft, GifByteType *buf, int length)
921
922Internal. The reader callback wrapper passed to giflib.
923
924This function is only used with giflib 4 and higher.
925
926=cut
927*/
928
02d1d628
AMH
929static int
930gif_read_callback(GifFileType *gft, GifByteType *buf, int length) {
ef7ab4d6 931 return i_gen_reader((i_gen_read_data *)gft->UserData, (char*)buf, length);
02d1d628
AMH
932}
933
934#endif
935
a3923855
TC
936
937/*
938=item i_readgif_callback(i_read_callback_t cb, char *userdata, int **colour_table, int *colours)
939
940Read a GIF file into an Imager RGB file, the data of the GIF file is
941retreived by callin the user supplied callback function.
942
943This function is only used with giflib 4 and higher.
944
945=cut
946*/
947
02d1d628
AMH
948i_img*
949i_readgif_callback(i_read_callback_t cb, char *userdata, int **colour_table, int *colours) {
950#if IM_GIFMAJOR >= 4
951 GifFileType *GifFile;
952 i_img *result;
77fc6afd 953
02d1d628
AMH
954 i_gen_read_data *gci = i_gen_read_data_new(cb, userdata);
955
9d0f387b
TC
956 i_clear_error();
957
02d1d628
AMH
958 mm_log((1,"i_readgif_callback(callback %p, userdata %p, colour_table %p, colours %p)\n", cb, userdata, colour_table, colours));
959 if ((GifFile = DGifOpen( (void*) gci, gif_read_callback )) == NULL) {
77fc6afd
TC
960 gif_push_error();
961 i_push_error(0, "Cannot create giflib callback object");
02d1d628
AMH
962 mm_log((1,"i_readgif_callback: Unable to open callback datasource.\n"));
963 myfree(gci);
964 return NULL;
965 }
966
967 result = i_readgif_low(GifFile, colour_table, colours);
968 free_gen_read_data(gci);
969
970 return result;
971#else
972 return NULL;
973#endif
974}
975
a3923855
TC
976/*
977=item do_write(GifFileType *gf, i_gif_opts *opts, i_img *img, i_palidx *data)
978
979Internal. Low level image write function. Writes in interlace if
980that was requested in the GIF options.
981
982Returns non-zero on success.
983
984=cut
985*/
02d1d628
AMH
986static undef_int
987do_write(GifFileType *gf, i_gif_opts *opts, i_img *img, i_palidx *data) {
988 if (opts->interlace) {
989 int i, j;
990 for (i = 0; i < 4; ++i) {
991 for (j = InterlacedOffset[i]; j < img->ysize; j += InterlacedJumps[i]) {
992 if (EGifPutLine(gf, data+j*img->xsize, img->xsize) == GIF_ERROR) {
c48818b1
TC
993 gif_push_error();
994 i_push_error(0, "Could not save image data:");
02d1d628
AMH
995 mm_log((1, "Error in EGifPutLine\n"));
996 EGifCloseFile(gf);
997 return 0;
998 }
999 }
1000 }
1001 }
1002 else {
1003 int y;
1004 for (y = 0; y < img->ysize; ++y) {
1005 if (EGifPutLine(gf, data, img->xsize) == GIF_ERROR) {
c48818b1
TC
1006 gif_push_error();
1007 i_push_error(0, "Could not save image data:");
02d1d628
AMH
1008 mm_log((1, "Error in EGifPutLine\n"));
1009 EGifCloseFile(gf);
1010 return 0;
1011 }
1012 data += img->xsize;
1013 }
1014 }
1015
1016 return 1;
1017}
1018
a3923855
TC
1019/*
1020=item do_gce(GifFileType *gf, int index, i_gif_opts *opts, int want_trans, int trans_index)
1021
1022Internal. Writes the GIF graphics control extension, if necessary.
1023
1024Returns non-zero on success.
1025
1026=cut
1027*/
02d1d628
AMH
1028static int do_gce(GifFileType *gf, int index, i_gif_opts *opts, int want_trans, int trans_index)
1029{
1030 unsigned char gce[4] = {0};
1031 int want_gce = 0;
1032 if (want_trans) {
1033 gce[0] |= 1;
1034 gce[3] = trans_index;
1035 ++want_gce;
1036 }
1037 if (index < opts->delay_count) {
1038 gce[1] = opts->delays[index] % 256;
1039 gce[2] = opts->delays[index] / 256;
1040 ++want_gce;
1041 }
1042 if (index < opts->user_input_count) {
1043 if (opts->user_input_flags[index])
1044 gce[0] |= 2;
1045 ++want_gce;
1046 }
1047 if (index < opts->disposal_count) {
1048 gce[0] |= (opts->disposal[index] & 3) << 2;
1049 ++want_gce;
1050 }
1051 if (want_gce) {
c48818b1
TC
1052 if (EGifPutExtension(gf, 0xF9, sizeof(gce), gce) == GIF_ERROR) {
1053 gif_push_error();
1054 i_push_error(0, "Could not save GCE");
1055 }
02d1d628
AMH
1056 }
1057 return 1;
1058}
1059
a3923855
TC
1060/*
1061=item do_ns_loop(GifFileType *gf, i_gif_opts *opts)
1062
1063Internal. Add the Netscape2.0 loop extension block, if requested.
1064
1065The code for this function is currently "#if 0"ed out since the giflib
1066extension writing code currently doesn't seem to support writing
1067application extension blocks.
1068
1069=cut
1070*/
02d1d628
AMH
1071static int do_ns_loop(GifFileType *gf, i_gif_opts *opts)
1072{
02d1d628
AMH
1073 /* EGifPutExtension() doesn't appear to handle application
1074 extension blocks in any way
1075 Since giflib wraps the fd with a FILE * (and puts that in its
1076 private data), we can't do an end-run and write the data
1077 directly to the fd.
1078 There's no open interface that takes a FILE * either, so we
1079 can't workaround it that way either.
1080 If giflib's callback interface wasn't broken by default, I'd
1081 force file writes to use callbacks, but it is broken by default.
1082 */
28a9109d
TC
1083#if 0
1084 /* yes this was another attempt at supporting the loop extension */
02d1d628 1085 if (opts->loop_count) {
28a9109d
TC
1086 unsigned char nsle[12] = "NETSCAPE2.0";
1087 unsigned char subblock[3];
1088 if (EGifPutExtension(gf, 0xFF, 11, nsle) == GIF_ERROR) {
1089 gif_push_error();
1090 i_push_error(0, "writing loop extension");
1091 return 0;
1092 }
1093 subblock[0] = 1;
1094 subblock[1] = opts->loop_count % 256;
1095 subblock[2] = opts->loop_count / 256;
1096 if (EGifPutExtension(gf, 0, 3, subblock) == GIF_ERROR) {
1097 gif_push_error();
1098 i_push_error(0, "writing loop extention sub-block");
1099 return 0;
1100 }
1101 if (EGifPutExtension(gf, 0, 0, subblock) == GIF_ERROR) {
1102 gif_push_error();
1103 i_push_error(0, "writing loop extension terminator");
1104 return 0;
1105 }
02d1d628
AMH
1106 }
1107#endif
1108 return 1;
1109}
1110
a3923855
TC
1111/*
1112=item make_gif_map(i_quantize *quant, i_gif_opts *opts, int want_trans)
1113
1114Create a giflib color map object from an Imager color map.
1115
1116=cut
1117*/
1118
02d1d628
AMH
1119static ColorMapObject *make_gif_map(i_quantize *quant, i_gif_opts *opts,
1120 int want_trans) {
1121 GifColorType colors[256];
1122 int i;
1123 int size = quant->mc_count;
1124 int map_size;
c48818b1 1125 ColorMapObject *map;
02d1d628
AMH
1126
1127 for (i = 0; i < quant->mc_count; ++i) {
1128 colors[i].Red = quant->mc_colors[i].rgb.r;
1129 colors[i].Green = quant->mc_colors[i].rgb.g;
1130 colors[i].Blue = quant->mc_colors[i].rgb.b;
1131 }
1132 if (want_trans) {
1133 colors[size].Red = opts->tran_color.rgb.r;
1134 colors[size].Green = opts->tran_color.rgb.g;
1135 colors[size].Blue = opts->tran_color.rgb.b;
1136 ++size;
1137 }
1138 map_size = 1;
1139 while (map_size < size)
1140 map_size <<= 1;
85363ac2
TC
1141 /* giflib spews for 1 colour maps, reasonable, I suppose */
1142 if (map_size == 1)
1143 map_size = 2;
a743c0a6 1144
c48818b1 1145 map = MakeMapObject(map_size, colors);
a743c0a6 1146 mm_log((1, "XXX map is at %p and colors at %p\n", map, map->Colors));
c48818b1
TC
1147 if (!map) {
1148 gif_push_error();
1149 i_push_error(0, "Could not create color map object");
1150 return NULL;
1151 }
1152 return map;
02d1d628
AMH
1153}
1154
a3923855
TC
1155/*
1156=item gif_set_version(i_quantize *quant, i_gif_opts *opts)
1157
1158We need to call EGifSetGifVersion() before opening the file - put that
1159common code here.
1160
1161Unfortunately giflib 4.1.0 crashes when we use this. Internally
1162giflib 4.1.0 has code:
1163
1164 static char *GifVersionPrefix = GIF87_STAMP;
1165
1166and the code that sets the version internally does:
1167
1168 strncpy(&GifVersionPrefix[3], Version, 3);
1169
1170which is very broken.
1171
1172Failing to set the correct GIF version doesn't seem to cause a problem
1173with readers.
1174
1175=cut
02d1d628 1176*/
a3923855 1177
02d1d628
AMH
1178static void gif_set_version(i_quantize *quant, i_gif_opts *opts) {
1179 /* the following crashed giflib
1180 the EGifSetGifVersion() is seriously borked in giflib
1181 it's less borked in the ungiflib beta, but we don't have a mechanism
1182 to distinguish them
1183 if (opts->delay_count
1184 || opts->user_input_count
1185 || opts->disposal_count
1186 || opts->loop_count
1187 || quant->transp != tr_none)
1188 EGifSetGifVersion("89a");
1189 else
1190 EGifSetGifVersion("87a");
1191 */
1192}
1193
bf9dd17c
TC
1194static int
1195in_palette(i_color *c, i_quantize *quant, int size) {
1196 int i;
1197
1198 for (i = 0; i < size; ++i) {
1199 if (c->channel[0] == quant->mc_colors[i].channel[0]
1200 && c->channel[1] == quant->mc_colors[i].channel[1]
1201 && c->channel[2] == quant->mc_colors[i].channel[2]) {
1202 return i;
1203 }
1204 }
1205
1206 return -1;
1207}
1208
1209/*
1210=item has_common_palette(imgs, count, quant, want_trans)
1211
1212Tests if all the given images are paletted and have a common palette,
1213if they do it builds that palette.
1214
1215A possible improvement might be to eliminate unused colors in the
1216images palettes.
1217
1218=cut */
1219static int
1220has_common_palette(i_img **imgs, int count, i_quantize *quant, int want_trans,
1221 i_gif_opts *opts) {
1222 int size = quant->mc_count;
1223 int i, j;
1224 int imgn;
1225 int x, y;
1226 char used[256];
1227
1228 /* we try to build a common palette here, if we can manage that, then
1229 that's the palette we use */
1230 for (imgn = 0; imgn < count; ++imgn) {
1231 if (imgs[imgn]->type != i_palette_type)
1232 return 0;
1233
1234 if (opts->eliminate_unused) {
1235 i_palidx *line = mymalloc(sizeof(i_palidx) * imgs[imgn]->xsize);
1236 int x, y;
1237 memset(used, 0, sizeof(used));
1238
1239 for (y = 0; y < imgs[imgn]->ysize; ++y) {
1240 i_gpal(imgs[imgn], 0, imgs[imgn]->xsize, y, line);
1241 for (x = 0; x < imgs[imgn]->xsize; ++x)
1242 used[line[x]] = 1;
1243 }
1244
1245 myfree(line);
1246 }
1247 else {
1248 /* assume all are in use */
1249 memset(used, 1, sizeof(used));
1250 }
1251
1252 for (i = 0; i < i_colorcount(imgs[imgn]); ++i) {
1253 i_color c;
1254
1255 i_getcolors(imgs[imgn], i, &c, 1);
1256 if (used[i]) {
1257 if (in_palette(&c, quant, size) < 0) {
1258 if (size < quant->mc_size) {
1259 quant->mc_colors[size++] = c;
1260 }
1261 else {
1262 /* oops, too many colors */
1263 return 0;
1264 }
1265 }
1266 }
1267 }
1268 }
1269
1270 quant->mc_count = size;
1271
1272 return 1;
1273}
1274
1275static i_palidx *
1276quant_paletted(i_quantize *quant, i_img *img) {
1277 i_palidx *data = mymalloc(sizeof(i_palidx) * img->xsize * img->ysize);
1278 i_palidx *p = data;
1279 i_palidx trans[256];
1280 int i;
1281 int x, y;
1282
1283 /* build a translation table */
1284 for (i = 0; i < i_colorcount(img); ++i) {
1285 i_color c;
1286 i_getcolors(img, i, &c, 1);
1287 trans[i] = in_palette(&c, quant, quant->mc_count);
1288 }
1289
1290 for (y = 0; y < img->ysize; ++y) {
1291 i_gpal(img, 0, img->xsize, y, data+img->xsize * y);
1292 for (x = 0; x < img->xsize; ++x) {
1293 *p = trans[*p];
1294 ++p;
1295 }
1296 }
1297
1298 return data;
1299}
1300
a3923855
TC
1301/*
1302=item i_writegif_low(i_quantize *quant, GifFileType *gf, i_img **imgs, int count, i_gif_opts *opts)
1303
1304Internal. Low-level function that does the high-level GIF processing
1305:)
1306
1307Returns non-zero on success.
1308
1309=cut
1310*/
1311
02d1d628
AMH
1312static undef_int
1313i_writegif_low(i_quantize *quant, GifFileType *gf, i_img **imgs, int count,
1314 i_gif_opts *opts) {
1315 unsigned char *result;
1316 int color_bits;
1317 ColorMapObject *map;
1318 int scrw = 0, scrh = 0;
1319 int imgn, orig_count, orig_size;
1320 int posx, posy;
bf9dd17c 1321 int trans_index;
02d1d628
AMH
1322
1323 mm_log((1, "i_writegif_low(quant %p, gf %p, imgs %p, count %d, opts %p)\n",
1324 quant, gf, imgs, count, opts));
1325
1326 /**((char *)0) = 1;*/
1327 /* sanity is nice */
1328 if (quant->mc_size > 256)
1329 quant->mc_size = 256;
1330 if (quant->mc_count > quant->mc_size)
1331 quant->mc_count = quant->mc_size;
1332
1333 for (imgn = 0; imgn < count; ++imgn) {
1334 if (imgn < opts->position_count) {
1335 if (imgs[imgn]->xsize + opts->positions[imgn].x > scrw)
1336 scrw = imgs[imgn]->xsize + opts->positions[imgn].x;
1337 if (imgs[imgn]->ysize + opts->positions[imgn].y > scrw)
1338 scrh = imgs[imgn]->ysize + opts->positions[imgn].y;
1339 }
1340 else {
1341 if (imgs[imgn]->xsize > scrw)
1342 scrw = imgs[imgn]->xsize;
1343 if (imgs[imgn]->ysize > scrh)
1344 scrh = imgs[imgn]->ysize;
1345 }
1346 }
1347
c48818b1
TC
1348 if (count <= 0) {
1349 i_push_error(0, "No images provided to write");
02d1d628 1350 return 0; /* what are you smoking? */
c48818b1 1351 }
02d1d628
AMH
1352
1353 orig_count = quant->mc_count;
1354 orig_size = quant->mc_size;
1355
1356 if (opts->each_palette) {
5dcf9039
TC
1357 int want_trans = quant->transp != tr_none
1358 && imgs[0]->channels == 4;
1359
1360 /* if the caller gives us too many colours we can't do transparency */
1361 if (want_trans && quant->mc_count == 256)
1362 want_trans = 0;
1363 /* if they want transparency but give us a big size, make it smaller
1364 to give room for a transparency colour */
1365 if (want_trans && quant->mc_size == 256)
1366 --quant->mc_size;
02d1d628
AMH
1367
1368 /* we always generate a global palette - this lets systems with a
1369 broken giflib work */
bf9dd17c
TC
1370 if (has_common_palette(imgs, 1, quant, want_trans, opts)) {
1371 result = quant_paletted(quant, imgs[0]);
1372 }
1373 else {
1374 quant_makemap(quant, imgs, 1);
1375 result = quant_translate(quant, imgs[0]);
1376 }
1377 if (want_trans) {
1378 trans_index = quant->mc_count;
1379 quant_transparent(quant, result, imgs[0], trans_index);
1380 }
02d1d628 1381
02d1d628
AMH
1382 if ((map = make_gif_map(quant, opts, want_trans)) == NULL) {
1383 myfree(result);
1384 EGifCloseFile(gf);
1385 mm_log((1, "Error in MakeMapObject."));
1386 return 0;
1387 }
1388
1389 color_bits = 1;
1390 while (quant->mc_size > (1 << color_bits))
1391 ++color_bits;
1392
1393 if (EGifPutScreenDesc(gf, scrw, scrh, color_bits, 0, map) == GIF_ERROR) {
c48818b1
TC
1394 gif_push_error();
1395 i_push_error(0, "Could not save screen descriptor");
02d1d628
AMH
1396 FreeMapObject(map);
1397 myfree(result);
1398 EGifCloseFile(gf);
1399 mm_log((1, "Error in EGifPutScreenDesc."));
1400 return 0;
1401 }
1402 FreeMapObject(map);
1403
1404 if (!do_ns_loop(gf, opts))
1405 return 0;
1406
bf9dd17c 1407 if (!do_gce(gf, 0, opts, want_trans, trans_index)) {
02d1d628
AMH
1408 myfree(result);
1409 EGifCloseFile(gf);
1410 return 0;
1411 }
1412 if (opts->position_count) {
1413 posx = opts->positions[0].x;
1414 posy = opts->positions[0].y;
1415 }
1416 else
1417 posx = posy = 0;
1418 if (EGifPutImageDesc(gf, posx, posy, imgs[0]->xsize, imgs[0]->ysize,
1419 opts->interlace, NULL) == GIF_ERROR) {
c48818b1
TC
1420 gif_push_error();
1421 i_push_error(0, "Could not save image descriptor");
02d1d628
AMH
1422 EGifCloseFile(gf);
1423 mm_log((1, "Error in EGifPutImageDesc."));
1424 return 0;
1425 }
1426 if (!do_write(gf, opts, imgs[0], result)) {
1427 EGifCloseFile(gf);
1428 myfree(result);
1429 return 0;
1430 }
1431 for (imgn = 1; imgn < count; ++imgn) {
1432 quant->mc_count = orig_count;
1433 quant->mc_size = orig_size;
5dcf9039
TC
1434 want_trans = quant->transp != tr_none
1435 && imgs[0]->channels == 4;
1436 /* if the caller gives us too many colours we can't do transparency */
1437 if (want_trans && quant->mc_count == 256)
1438 want_trans = 0;
1439 /* if they want transparency but give us a big size, make it smaller
1440 to give room for a transparency colour */
1441 if (want_trans && quant->mc_size == 256)
1442 --quant->mc_size;
1443
bf9dd17c
TC
1444 if (has_common_palette(imgs+imgn, 1, quant, want_trans, opts)) {
1445 result = quant_paletted(quant, imgs[imgn]);
1446 }
1447 else {
1448 quant_makemap(quant, imgs+imgn, 1);
1449 result = quant_translate(quant, imgs[imgn]);
1450 }
1451 if (want_trans) {
1452 quant_transparent(quant, result, imgs[imgn], quant->mc_count);
1453 trans_index = quant->mc_count;
1454 }
1455
02d1d628
AMH
1456 if (!do_gce(gf, imgn, opts, want_trans, quant->mc_count)) {
1457 myfree(result);
1458 EGifCloseFile(gf);
1459 return 0;
1460 }
1461 if ((map = make_gif_map(quant, opts, want_trans)) == NULL) {
1462 myfree(result);
1463 EGifCloseFile(gf);
1464 mm_log((1, "Error in MakeMapObject."));
1465 return 0;
1466 }
1467 if (imgn < opts->position_count) {
1468 posx = opts->positions[imgn].x;
1469 posy = opts->positions[imgn].y;
1470 }
1471 else
1472 posx = posy = 0;
1473 if (EGifPutImageDesc(gf, posx, posy, imgs[imgn]->xsize,
1474 imgs[imgn]->ysize, opts->interlace,
1475 map) == GIF_ERROR) {
c48818b1
TC
1476 gif_push_error();
1477 i_push_error(0, "Could not save image descriptor");
02d1d628
AMH
1478 myfree(result);
1479 FreeMapObject(map);
1480 EGifCloseFile(gf);
1481 mm_log((1, "Error in EGifPutImageDesc."));
1482 return 0;
1483 }
1484 FreeMapObject(map);
1485
1486 if (!do_write(gf, opts, imgs[imgn], result)) {
1487 EGifCloseFile(gf);
1488 myfree(result);
1489 return 0;
1490 }
1491 myfree(result);
1492 }
1493 }
1494 else {
1495 int want_trans;
bf9dd17c 1496 int do_quant_paletted = 0;
02d1d628 1497
02d1d628
AMH
1498 /* get a palette entry for the transparency iff we have an image
1499 with an alpha channel */
1500 want_trans = 0;
1501 for (imgn = 0; imgn < count; ++imgn) {
1502 if (imgs[imgn]->channels == 4) {
1503 ++want_trans;
1504 break;
1505 }
1506 }
5dcf9039
TC
1507 want_trans = want_trans && quant->transp != tr_none
1508 && quant->mc_count < 256;
1509 if (want_trans && quant->mc_size == 256)
1510 --quant->mc_size;
1511
1512 /* handle the first image separately - since we allow giflib
1513 conversion and giflib doesn't give us a separate function to build
1514 the colormap. */
1515
1516 /* produce a colour map */
bf9dd17c
TC
1517 if (has_common_palette(imgs, count, quant, want_trans, opts)) {
1518 result = quant_paletted(quant, imgs[0]);
1519 ++do_quant_paletted;
1520 }
1521 else {
1522 quant_makemap(quant, imgs, count);
1523 result = quant_translate(quant, imgs[0]);
1524 }
5dcf9039 1525
02d1d628
AMH
1526 if ((map = make_gif_map(quant, opts, want_trans)) == NULL) {
1527 myfree(result);
1528 EGifCloseFile(gf);
1529 mm_log((1, "Error in MakeMapObject"));
1530 return 0;
1531 }
1532 color_bits = 1;
1533 while (quant->mc_count > (1 << color_bits))
1534 ++color_bits;
1535
1536 if (EGifPutScreenDesc(gf, scrw, scrh, color_bits, 0, map) == GIF_ERROR) {
c48818b1
TC
1537 gif_push_error();
1538 i_push_error(0, "Could not save screen descriptor");
02d1d628
AMH
1539 FreeMapObject(map);
1540 myfree(result);
1541 EGifCloseFile(gf);
1542 mm_log((1, "Error in EGifPutScreenDesc."));
1543 return 0;
1544 }
1545 FreeMapObject(map);
1546
1547 if (!do_ns_loop(gf, opts))
1548 return 0;
1549
1550 if (!do_gce(gf, 0, opts, want_trans, quant->mc_count)) {
1551 myfree(result);
1552 EGifCloseFile(gf);
1553 return 0;
1554 }
1555 if (opts->position_count) {
1556 posx = opts->positions[0].x;
1557 posy = opts->positions[0].y;
1558 }
1559 else
1560 posx = posy = 0;
1561 if (EGifPutImageDesc(gf, posx, posy, imgs[0]->xsize, imgs[0]->ysize,
1562 opts->interlace, NULL) == GIF_ERROR) {
c48818b1
TC
1563 gif_push_error();
1564 i_push_error(0, "Could not save image descriptor");
02d1d628
AMH
1565 EGifCloseFile(gf);
1566 mm_log((1, "Error in EGifPutImageDesc."));
1567 return 0;
1568 }
1569 if (want_trans && imgs[0]->channels == 4)
1570 quant_transparent(quant, result, imgs[0], quant->mc_count);
1571
1572 if (!do_write(gf, opts, imgs[0], result)) {
1573 EGifCloseFile(gf);
1574 myfree(result);
1575 return 0;
1576 }
1577 myfree(result);
1578
1579 for (imgn = 1; imgn < count; ++imgn) {
1580 int local_trans;
bf9dd17c
TC
1581 if (do_quant_paletted)
1582 result = quant_paletted(quant, imgs[imgn]);
1583 else
1584 result = quant_translate(quant, imgs[imgn]);
02d1d628
AMH
1585 local_trans = want_trans && imgs[imgn]->channels == 4;
1586 if (local_trans)
1587 quant_transparent(quant, result, imgs[imgn], quant->mc_count);
1588 if (!do_gce(gf, imgn, opts, local_trans, quant->mc_count)) {
1589 myfree(result);
1590 EGifCloseFile(gf);
1591 return 0;
1592 }
1593 if (imgn < opts->position_count) {
1594 posx = opts->positions[imgn].x;
1595 posy = opts->positions[imgn].y;
1596 }
1597 else
1598 posx = posy = 0;
1599 if (EGifPutImageDesc(gf, posx, posy,
1600 imgs[imgn]->xsize, imgs[imgn]->ysize,
1601 opts->interlace, NULL) == GIF_ERROR) {
c48818b1
TC
1602 gif_push_error();
1603 i_push_error(0, "Could not save image descriptor");
02d1d628
AMH
1604 myfree(result);
1605 EGifCloseFile(gf);
1606 mm_log((1, "Error in EGifPutImageDesc."));
1607 return 0;
1608 }
1609 if (!do_write(gf, opts, imgs[imgn], result)) {
1610 EGifCloseFile(gf);
1611 myfree(result);
1612 return 0;
1613 }
1614 myfree(result);
1615 }
1616 }
1617 if (EGifCloseFile(gf) == GIF_ERROR) {
c48818b1
TC
1618 gif_push_error();
1619 i_push_error(0, "Could not close GIF file");
02d1d628
AMH
1620 mm_log((1, "Error in EGifCloseFile\n"));
1621 return 0;
1622 }
1623
1624 return 1;
1625}
1626
a3923855
TC
1627/*
1628=item i_writegif_gen(i_quantize *quant, int fd, i_img **imgs, int count, i_gif_opts *opts)
1629
1630General high-level function to write a GIF to a file.
1631
1632Writes the GIF images to the specified file handle using the options
1633in quant and opts. See L<image.h/i_quantize> and
1634L<image.h/i_gif_opts>.
1635
1636Returns non-zero on success.
1637
1638=cut
1639*/
1640
02d1d628
AMH
1641undef_int
1642i_writegif_gen(i_quantize *quant, int fd, i_img **imgs, int count,
1643 i_gif_opts *opts) {
1644 GifFileType *gf;
1645
c48818b1 1646 i_clear_error();
02d1d628
AMH
1647 mm_log((1, "i_writegif_gen(quant %p, fd %d, imgs %p, count %d, opts %p)\n",
1648 quant, fd, imgs, count, opts));
1649
1650 gif_set_version(quant, opts);
1651
02d1d628 1652 if ((gf = EGifOpenFileHandle(fd)) == NULL) {
c48818b1
TC
1653 gif_push_error();
1654 i_push_error(0, "Cannot create GIF file object");
02d1d628
AMH
1655 mm_log((1, "Error in EGifOpenFileHandle, unable to write image.\n"));
1656 return 0;
1657 }
1658
1659 return i_writegif_low(quant, gf, imgs, count, opts);
1660}
1661
1662#if IM_GIFMAJOR >= 4
1663
a3923855
TC
1664/*
1665=item gif_writer_callback(GifFileType *gf, const GifByteType *data, int size)
1666
1667Internal. Wrapper for the user write callback function.
1668
1669=cut
1670*/
1671
02d1d628
AMH
1672static int gif_writer_callback(GifFileType *gf, const GifByteType *data, int size)
1673{
1674 i_gen_write_data *gwd = (i_gen_write_data *)gf->UserData;
1675
ef7ab4d6 1676 return i_gen_writer(gwd, (char*)data, size) ? size : 0;
02d1d628
AMH
1677}
1678
1679#endif
1680
a3923855
TC
1681/*
1682=item i_writegif_callback(i_quantize *quant, i_write_callback_t cb, char *userdata, int maxlength, i_img **imgs, int count, i_gif_opts *opts)
1683
1684General high-level function to write a GIF using callbacks to send
1685back the data.
1686
1687Returns non-zero on success.
1688
1689=cut
1690*/
1691
02d1d628
AMH
1692undef_int
1693i_writegif_callback(i_quantize *quant, i_write_callback_t cb, char *userdata,
1694 int maxlength, i_img **imgs, int count, i_gif_opts *opts)
1695{
1696#if IM_GIFMAJOR >= 4
1697 GifFileType *gf;
1698 i_gen_write_data *gwd = i_gen_write_data_new(cb, userdata, maxlength);
1699 /* giflib declares this incorrectly as EgifOpen */
1700 extern GifFileType *EGifOpen(void *userData, OutputFunc writeFunc);
1701 int result;
1702
c48818b1
TC
1703 i_clear_error();
1704
02d1d628
AMH
1705 mm_log((1, "i_writegif_callback(quant %p, i_write_callback_t %p, userdata $p, maxlength %d, imgs %p, count %d, opts %p)\n",
1706 quant, cb, userdata, maxlength, imgs, count, opts));
1707
1708 if ((gf = EGifOpen(gwd, &gif_writer_callback)) == NULL) {
c48818b1
TC
1709 gif_push_error();
1710 i_push_error(0, "Cannot create GIF file object");
02d1d628
AMH
1711 mm_log((1, "Error in EGifOpenFileHandle, unable to write image.\n"));
1712 free_gen_write_data(gwd, 0);
1713 return 0;
1714 }
1715
1716 result = i_writegif_low(quant, gf, imgs, count, opts);
1717 return free_gen_write_data(gwd, result);
1718#else
1719 return 0;
1720#endif
1721}
a3923855 1722
c48818b1
TC
1723/*
1724=item gif_error_msg(int code)
1725
1726Grabs the most recent giflib error code from GifLastError() and
1727returns a string that describes that error.
1728
1729The returned pointer points to a static buffer, either from a literal
1730C string or a static buffer.
1731
1732=cut */
1733
1734static char const *gif_error_msg(int code) {
1735 static char msg[80];
1736
1737 switch (code) {
1738 case E_GIF_ERR_OPEN_FAILED: /* should not see this */
1739 return "Failed to open given file";
1740
1741 case E_GIF_ERR_WRITE_FAILED:
1742 return "Write failed";
1743
1744 case E_GIF_ERR_HAS_SCRN_DSCR: /* should not see this */
1745 return "Screen descriptor already passed to giflib";
1746
1747 case E_GIF_ERR_HAS_IMAG_DSCR: /* should not see this */
1748 return "Image descriptor already passed to giflib";
1749
1750 case E_GIF_ERR_NO_COLOR_MAP: /* should not see this */
1751 return "Neither global nor local color map set";
1752
1753 case E_GIF_ERR_DATA_TOO_BIG: /* should not see this */
1754 return "Too much pixel data passed to giflib";
1755
1756 case E_GIF_ERR_NOT_ENOUGH_MEM:
1757 return "Out of memory";
1758
1759 case E_GIF_ERR_DISK_IS_FULL:
1760 return "Disk is full";
1761
1762 case E_GIF_ERR_CLOSE_FAILED: /* should not see this */
1763 return "File close failed";
1764
1765 case E_GIF_ERR_NOT_WRITEABLE: /* should not see this */
1766 return "File not writable";
1767
1768 case D_GIF_ERR_OPEN_FAILED:
1769 return "Failed to open file";
1770
1771 case D_GIF_ERR_READ_FAILED:
1772 return "Failed to read from file";
1773
1774 case D_GIF_ERR_NOT_GIF_FILE:
1775 return "File is not a GIF file";
1776
1777 case D_GIF_ERR_NO_SCRN_DSCR:
1778 return "No screen descriptor detected - invalid file";
1779
1780 case D_GIF_ERR_NO_IMAG_DSCR:
1781 return "No image descriptor detected - invalid file";
1782
1783 case D_GIF_ERR_NO_COLOR_MAP:
1784 return "No global or local color map found";
1785
1786 case D_GIF_ERR_WRONG_RECORD:
1787 return "Wrong record type detected - invalid file?";
1788
1789 case D_GIF_ERR_DATA_TOO_BIG:
1790 return "Data in file too big for image";
1791
1792 case D_GIF_ERR_NOT_ENOUGH_MEM:
1793 return "Out of memory";
1794
1795 case D_GIF_ERR_CLOSE_FAILED:
1796 return "Close failed";
1797
1798 case D_GIF_ERR_NOT_READABLE:
1799 return "File not opened for read";
1800
1801 case D_GIF_ERR_IMAGE_DEFECT:
1802 return "Defective image";
1803
1804 case D_GIF_ERR_EOF_TOO_SOON:
1805 return "Unexpected EOF - invalid file";
1806
1807 default:
1808 sprintf(msg, "Unknown giflib error code %d", code);
1809 return msg;
1810 }
1811}
1812
1813/*
1814=item gif_push_error()
1815
1816Utility function that takes the current GIF error code, converts it to
1817an error message and pushes it on the error stack.
1818
1819=cut
1820*/
1821
faa9b3e7 1822static void gif_push_error(void) {
c48818b1
TC
1823 int code = GifLastError(); /* clears saved error */
1824
1825 i_push_error(code, gif_error_msg(code));
1826}
1827
a3923855
TC
1828/*
1829=head1 BUGS
1830
1831The Netscape loop extension isn't implemented. Giflib's extension
1832writing code doesn't seem to support writing named extensions in this
1833form.
1834
1835A bug in giflib is tickled by the i_writegif_callback(). This isn't a
1836problem on ungiflib, but causes a SEGV on giflib. A patch is provided
1837in t/t10formats.t
1838
1839The GIF file tag (GIF87a vs GIF89a) currently isn't set. Using the
1840supplied interface in giflib 4.1.0 causes a SEGV in
1841EGifSetGifVersion(). See L<gif_set_version> for an explanation.
1842
1843=head1 AUTHOR
1844
1845Arnar M. Hrafnkelsson, addi@umich.edu
1846
1847=head1 SEE ALSO
1848
1849perl(1), Imager(3)
1850
1851=cut
1852
1853*/