4 /* XXX: Reading still needs to support reading all those gif properties */
9 gif.c - read and write gif files for Imager
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
23 char *data; // a GIF file in memory
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
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,
42 This source file provides the C level interface to reading and writing
45 This has been tested with giflib 3 and 4, though you lose the callback
46 functionality with giflib3.
55 static char const *gif_error_msg(int code);
56 static void gif_push_error(void);
60 static int gif_read_callback(GifFileType *gft, GifByteType *buf, int length);
65 Internal. A structure passed to the reader function used for reading
68 Used with giflib 4 and later.
73 struct gif_scalar_info {
80 =item my_gif_inputfunc(GifFileType *gft, GifByteType *buf, int length)
82 Internal. The reader callback passed to giflib.
84 Used with giflib 4 and later.
90 my_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); */
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);
105 /* Make some variables global, so we could access them faster: */
108 InterlacedOffset[] = { 0, 4, 2, 1 }, /* The way Interlaced image should. */
109 InterlacedJumps[] = { 8, 8, 4, 2 }; /* be read - offsets and jumps... */
115 i_colortable_copy(int **colour_table, int *colours, ColorMapObject *colourmap) {
116 GifColorType *mapentry;
118 int colourmapsize = colourmap->ColorCount;
120 if(colours) *colours = colourmapsize;
121 if(!colour_table) return;
123 *colour_table = mymalloc(sizeof(int) * colourmapsize * 3);
124 memset(*colour_table, 0, sizeof(int) * colourmapsize * 3);
126 for(q=0; q<colourmapsize; q++) {
127 mapentry = &colourmap->Colors[q];
128 (*colour_table)[q*3 + 0] = mapentry->Red;
129 (*colour_table)[q*3 + 1] = mapentry->Green;
130 (*colour_table)[q*3 + 2] = mapentry->Blue;
136 =item i_readgif_low(GifFileType *GifFile, int **colour_table, int *colours)
138 Internal. Low-level function for reading a GIF file. The caller must
139 create the appropriate GifFileType object and pass it in.
145 i_readgif_low(GifFileType *GifFile, int **colour_table, int *colours) {
147 int i, j, Size, Row, Col, Width, Height, ExtCode, Count, x;
148 int cmapcnt = 0, ImageNum = 0, BackGround = 0, ColorMapSize = 0;
149 ColorMapObject *ColorMap;
151 GifRecordType RecordType;
152 GifByteType *Extension;
155 static GifColorType *ColorMapEntry;
158 mm_log((1,"i_readgif_low(GifFile %p, colour_table %p, colours %p)\n", GifFile, colour_table, colours));
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.
164 if (colour_table) *colour_table = NULL;
166 BackGround = GifFile->SBackGroundColor;
167 ColorMap = (GifFile->Image.ColorMap ? GifFile->Image.ColorMap : GifFile->SColorMap);
170 ColorMapSize = ColorMap->ColorCount;
171 i_colortable_copy(colour_table, colours, ColorMap);
176 im = i_img_empty_ch(NULL, GifFile->SWidth, GifFile->SHeight, 3);
178 Size = GifFile->SWidth * sizeof(GifPixelType);
180 GifRow = (GifRowType) mymalloc(Size);
182 for (i = 0; i < GifFile->SWidth; i++) GifRow[i] = GifFile->SBackGroundColor;
184 /* Scan the content of the GIF file and load the image(s) in: */
186 if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR) {
188 i_push_error(0, "Unable to get record type");
189 if (colour_table && *colour_table) {
190 myfree(*colour_table);
191 *colour_table = NULL;
194 DGifCloseFile(GifFile);
198 switch (RecordType) {
199 case IMAGE_DESC_RECORD_TYPE:
200 if (DGifGetImageDesc(GifFile) == GIF_ERROR) {
202 i_push_error(0, "Unable to get image descriptor");
203 if (colour_table && *colour_table) {
204 myfree(*colour_table);
205 *colour_table = NULL;
208 DGifCloseFile(GifFile);
212 if (( ColorMap = (GifFile->Image.ColorMap ? GifFile->Image.ColorMap : GifFile->SColorMap) )) {
213 mm_log((1, "Adding local colormap\n"));
214 ColorMapSize = ColorMap->ColorCount;
216 i_colortable_copy(colour_table, colours, ColorMap);
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 */
225 DGifCloseFile(GifFile);
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;
234 mm_log((1,"i_readgif_low: Image %d at (%d, %d) [%dx%d]: \n",ImageNum, Col, Row, Width, Height));
236 if (GifFile->Image.Left + GifFile->Image.Width > GifFile->SWidth ||
237 GifFile->Image.Top + GifFile->Image.Height > GifFile->SHeight) {
238 i_push_errorf(0, "Image %d is not confined to screen dimension, aborted.\n",ImageNum);
239 if (colour_table && *colour_table) {
240 myfree(*colour_table);
241 *colour_table = NULL;
244 DGifCloseFile(GifFile);
247 if (GifFile->Image.Interlace) {
249 for (Count = i = 0; i < 4; i++) for (j = Row + InterlacedOffset[i]; j < Row + Height; j += InterlacedJumps[i]) {
251 if (DGifGetLine(GifFile, GifRow, Width) == GIF_ERROR) {
253 i_push_error(0, "Reading GIF line");
254 if (colour_table && *colour_table) {
255 myfree(*colour_table);
256 *colour_table = NULL;
259 DGifCloseFile(GifFile);
263 for (x = 0; x < Width; x++) {
264 ColorMapEntry = &ColorMap->Colors[GifRow[x]];
265 col.rgb.r = ColorMapEntry->Red;
266 col.rgb.g = ColorMapEntry->Green;
267 col.rgb.b = ColorMapEntry->Blue;
268 i_ppix(im,Col+x,j,&col);
274 for (i = 0; i < Height; i++) {
275 if (DGifGetLine(GifFile, GifRow, Width) == GIF_ERROR) {
277 i_push_error(0, "Reading GIF line");
278 if (colour_table && *colour_table) {
279 myfree(*colour_table);
280 *colour_table = NULL;
283 DGifCloseFile(GifFile);
287 for (x = 0; x < Width; x++) {
288 ColorMapEntry = &ColorMap->Colors[GifRow[x]];
289 col.rgb.r = ColorMapEntry->Red;
290 col.rgb.g = ColorMapEntry->Green;
291 col.rgb.b = ColorMapEntry->Blue;
292 i_ppix(im, Col+x, Row, &col);
298 case EXTENSION_RECORD_TYPE:
299 /* Skip any extension blocks in file: */
300 if (DGifGetExtension(GifFile, &ExtCode, &Extension) == GIF_ERROR) {
302 i_push_error(0, "Reading extension record");
303 if (colour_table && *colour_table) {
304 myfree(*colour_table);
305 *colour_table = NULL;
308 DGifCloseFile(GifFile);
311 while (Extension != NULL) {
312 if (DGifGetExtensionNext(GifFile, &Extension) == GIF_ERROR) {
314 i_push_error(0, "reading next block of extension");
315 if (colour_table && *colour_table) {
316 myfree(*colour_table);
317 *colour_table = NULL;
320 DGifCloseFile(GifFile);
325 case TERMINATE_RECORD_TYPE:
327 default: /* Should be traps by DGifGetRecordType. */
330 } while (RecordType != TERMINATE_RECORD_TYPE);
334 if (DGifCloseFile(GifFile) == GIF_ERROR) {
336 i_push_error(0, "Closing GIF file object");
337 if (colour_table && *colour_table) {
338 myfree(*colour_table);
339 *colour_table = NULL;
348 =item i_readgif(int fd, int **colour_table, int *colours)
350 Reads in a GIF file from a file handle and converts it to an Imager
353 Returns the palette for the object in colour_table for colours
356 Returns NULL on failure.
362 i_readgif(int fd, int **colour_table, int *colours) {
363 GifFileType *GifFile;
367 mm_log((1,"i_readgif(fd %d, colour_table %p, colours %p)\n", fd, colour_table, colours));
369 if ((GifFile = DGifOpenFileHandle(fd)) == NULL) {
371 i_push_error(0, "Cannot create giflib file object");
372 mm_log((1,"i_readgif: Unable to open file\n"));
376 return i_readgif_low(GifFile, colour_table, colours);
381 Internal function called by i_readgif_multi_low() in error handling
384 static void free_images(i_img **imgs, int count) {
386 for (i = 0; i < count; ++i)
387 i_img_destroy(imgs[i]);
392 =item i_readgif_multi_low(GifFileType *gf, int *count)
394 Reads one of more gif images from the given GIF file.
396 Returns a pointer to an array of i_img *, and puts the count into
399 Unlike the normal i_readgif*() functions the images are paletted
400 images rather than a combined RGB image.
402 This functions sets tags on the images returned:
408 the offset of the image from the left of the "screen" ("Image Left
413 the offset of the image from the top of the "screen" ("Image Top Position")
417 non-zero if the image was interlaced ("Interlace Flag")
419 =item gif_screen_width
421 =item gif_screen_height
423 the size of the logical screen ("Logical Screen Width",
424 "Logical Screen Height")
428 Non-zero if this image had a local color map.
432 The index in the global colormap of the logical screen's background
433 color. This is only set if the current image uses the global
436 =item gif_trans_index
438 The index of the color in the colormap used for transparency. If the
439 image has a transparency then it is returned as a 4 channel image with
440 the alpha set to zero in this palette entry. ("Transparent Color Index")
444 The delay until the next frame is displayed, in 1/100 of a second.
449 whether or not a user input is expected before continuing (view dependent)
454 how the next frame is displayed ("Disposal Method")
458 the number of loops from the Netscape Loop extension. This may be zero.
462 the first block of the first gif comment before each image.
466 Where applicable, the ("name") is the name of that field from the GIF89
472 i_img **i_readgif_multi_low(GifFileType *GifFile, int *count) {
474 int i, j, Size, Width, Height, ExtCode, Count, x;
475 int ImageNum = 0, BackGround = 0, ColorMapSize = 0;
476 ColorMapObject *ColorMap;
478 GifRecordType RecordType;
479 GifByteType *Extension;
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 */
489 char *comment = NULL; /* a comment */
490 i_img **results = NULL;
491 int result_alloc = 0;
496 mm_log((1,"i_readgif_multi_low(GifFile %p, , count %p)\n", GifFile, count));
498 BackGround = GifFile->SBackGroundColor;
500 Size = GifFile->SWidth * sizeof(GifPixelType);
502 if ((GifRow = (GifRowType) mymalloc(Size)) == NULL)
503 m_fatal(0,"Failed to allocate memory required, aborted."); /* First row. */
505 /* Scan the content of the GIF file and load the image(s) in: */
507 if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR) {
509 i_push_error(0, "Unable to get record type");
510 free_images(results, *count);
511 DGifCloseFile(GifFile);
515 switch (RecordType) {
516 case IMAGE_DESC_RECORD_TYPE:
517 if (DGifGetImageDesc(GifFile) == GIF_ERROR) {
519 i_push_error(0, "Unable to get image descriptor");
520 free_images(results, *count);
521 DGifCloseFile(GifFile);
525 if (( ColorMap = (GifFile->Image.ColorMap ? GifFile->Image.ColorMap : GifFile->SColorMap) )) {
526 mm_log((1, "Adding local colormap\n"));
527 ColorMapSize = ColorMap->ColorCount;
529 /* No colormap and we are about to read in the image -
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);
538 Width = GifFile->Image.Width;
539 Height = GifFile->Image.Height;
541 if (got_gce && trans_index >= 0)
543 img = i_img_pal_new(Width, Height, channels, 256);
544 /* populate the palette of the new image */
545 mm_log((1, "ColorMapSize %d\n", ColorMapSize));
546 for (i = 0; i < ColorMapSize; ++i) {
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)
556 i_addcolors(img, &col, 1);
559 if (*count > result_alloc) {
560 if (result_alloc == 0) {
562 results = mymalloc(result_alloc * sizeof(i_img *));
567 newresults = myrealloc(results, result_alloc * sizeof(i_img *));
570 results[*count-1] = img;
571 i_tags_addn(&img->tags, "gif_left", 0, GifFile->Image.Left);
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);
581 if (GifFile->Image.ColorMap) {
582 i_tags_addn(&img->tags, "gif_localmap", 0, 1);
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);
593 i_tags_addn(&img->tags, "gif_loop", 0, ns_loop);
595 i_tags_add(&img->tags, "gif_comment", 0, comment, strlen(comment), 0);
601 mm_log((1,"i_readgif_multi_low: Image %d at (%d, %d) [%dx%d]: \n",
602 ImageNum, GifFile->Image.Left, GifFile->Image.Top, Width, Height));
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);
612 if (GifFile->Image.Interlace) {
613 for (Count = i = 0; i < 4; i++) {
614 for (j = InterlacedOffset[i]; j < Height;
615 j += InterlacedJumps[i]) {
617 if (DGifGetLine(GifFile, GifRow, Width) == GIF_ERROR) {
619 i_push_error(0, "Reading GIF line");
620 free_images(results, *count);
621 DGifCloseFile(GifFile);
625 i_ppal(img, 0, Width, j, GifRow);
630 for (i = 0; i < Height; i++) {
631 if (DGifGetLine(GifFile, GifRow, Width) == GIF_ERROR) {
633 i_push_error(0, "Reading GIF line");
634 free_images(results, *count);
635 DGifCloseFile(GifFile);
639 i_ppal(img, 0, Width, i, GifRow);
643 case EXTENSION_RECORD_TYPE:
644 /* Skip any extension blocks in file: */
645 if (DGifGetExtension(GifFile, &ExtCode, &Extension) == GIF_ERROR) {
647 i_push_error(0, "Reading extension record");
648 free_images(results, *count);
649 DGifCloseFile(GifFile);
652 if (ExtCode == 0xF9) {
654 if (Extension[1] & 1)
655 trans_index = Extension[4];
658 gif_delay = Extension[2] + 256 * Extension[3];
659 user_input = (Extension[0] & 2) != 0;
660 disposal = (Extension[0] >> 2) & 3;
662 if (ExtCode == 0xFF && *Extension == 11) {
663 if (memcmp(Extension+1, "NETSCAPE2.0", 11) == 0) {
664 if (DGifGetExtensionNext(GifFile, &Extension) == GIF_ERROR) {
666 i_push_error(0, "reading loop extension");
667 free_images(results, *count);
668 DGifCloseFile(GifFile);
671 if (Extension && *Extension == 3) {
673 ns_loop = Extension[2] + 256 * Extension[3];
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.
685 comment = mymalloc(*Extension+1);
686 memcpy(comment, Extension+1, *Extension);
687 comment[*Extension] = '\0';
690 while (Extension != NULL) {
691 if (DGifGetExtensionNext(GifFile, &Extension) == GIF_ERROR) {
693 i_push_error(0, "reading next block of extension");
694 free_images(results, *count);
695 DGifCloseFile(GifFile);
700 case TERMINATE_RECORD_TYPE:
702 default: /* Should be trapped by DGifGetRecordType. */
705 } while (RecordType != TERMINATE_RECORD_TYPE);
709 i_tags_add(&(results[*count-1]->tags), "gif_comment", 0, comment,
717 if (DGifCloseFile(GifFile) == GIF_ERROR) {
719 i_push_error(0, "Closing GIF file object");
720 free_images(results, *count);
728 =item i_readgif_multi(int fd, int *count)
733 i_readgif_multi(int fd, int *count) {
734 GifFileType *GifFile;
738 mm_log((1,"i_readgif_multi(fd %d, &count %p)\n", fd, count));
740 if ((GifFile = DGifOpenFileHandle(fd)) == NULL) {
742 i_push_error(0, "Cannot create giflib file object");
743 mm_log((1,"i_readgif: Unable to open file\n"));
747 return i_readgif_multi_low(GifFile, count);
751 =item i_readgif_multi_scalar(char *data, int length, int *count)
756 i_readgif_multi_scalar(char *data, int length, int *count) {
758 GifFileType *GifFile;
759 struct gif_scalar_info gsi;
767 mm_log((1,"i_readgif_multi_scalar(data %p, length %d, &count %p)\n",
768 data, length, count));
770 if ((GifFile = DGifOpen( (void*) &gsi, my_gif_inputfunc )) == NULL) {
772 i_push_error(0, "Cannot create giflib callback object");
773 mm_log((1,"i_readgif_multi_scalar: Unable to open scalar datasource.\n"));
777 return i_readgif_multi_low(GifFile, count);
784 =item i_readgif_callback(i_read_callback_t cb, char *userdata, int **colour_table, int *colours)
786 Read a GIF file into an Imager RGB file, the data of the GIF file is
787 retreived by callin the user supplied callback function.
789 This function is only used with giflib 4 and higher.
795 i_readgif_multi_callback(i_read_callback_t cb, char *userdata, int *count) {
797 GifFileType *GifFile;
800 i_gen_read_data *gci = i_gen_read_data_new(cb, userdata);
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) {
807 i_push_error(0, "Cannot create giflib callback object");
808 mm_log((1,"i_readgif_callback: Unable to open callback datasource.\n"));
813 result = i_readgif_multi_low(GifFile, count);
814 free_gen_read_data(gci);
823 =item i_writegif(i_img *im, int fd, int max_colors, int pixdev, int fixedlen, i_color fixed[])
825 Write I<img> to the file handle I<fd>. The resulting GIF will use a
826 maximum of 1<<I<max_colours> colours, with the first I<fixedlen>
827 colours taken from I<fixed>.
829 Returns non-zero on success.
835 i_writegif(i_img *im, int fd, int max_colors, int pixdev, int fixedlen, i_color fixed[]) {
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);
853 =item i_writegifmc(i_img *im, int fd, int max_colors)
855 Write I<img> to the file handle I<fd>. The resulting GIF will use a
856 maximum of 1<<I<max_colours> colours.
858 Returns non-zero on success.
864 i_writegifmc(i_img *im, int fd, int max_colors) {
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;
875 quant.translate = pt_giflib;
876 return i_writegif_gen(&quant, fd, &im, 1, &opts);
881 =item i_readgif_scalar(char *data, int length, int **colour_table, int *colours)
883 Reads a GIF file from an in memory copy of the file. This can be used
884 if you get the 'file' from some source other than an actual file (or
885 some other file handle).
887 This function is only available with giflib 4 and higher.
892 i_readgif_scalar(char *data, int length, int **colour_table, int *colours) {
894 GifFileType *GifFile;
895 struct gif_scalar_info gsi;
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) {
906 i_push_error(0, "Cannot create giflib callback object");
907 mm_log((1,"i_readgif_scalar: Unable to open scalar datasource.\n"));
911 return i_readgif_low(GifFile, colour_table, colours);
920 =item gif_read_callback(GifFileType *gft, GifByteType *buf, int length)
922 Internal. The reader callback wrapper passed to giflib.
924 This function is only used with giflib 4 and higher.
930 gif_read_callback(GifFileType *gft, GifByteType *buf, int length) {
931 return i_gen_reader((i_gen_read_data *)gft->UserData, (char*)buf, length);
938 =item i_readgif_callback(i_read_callback_t cb, char *userdata, int **colour_table, int *colours)
940 Read a GIF file into an Imager RGB file, the data of the GIF file is
941 retreived by callin the user supplied callback function.
943 This function is only used with giflib 4 and higher.
949 i_readgif_callback(i_read_callback_t cb, char *userdata, int **colour_table, int *colours) {
951 GifFileType *GifFile;
954 i_gen_read_data *gci = i_gen_read_data_new(cb, userdata);
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) {
961 i_push_error(0, "Cannot create giflib callback object");
962 mm_log((1,"i_readgif_callback: Unable to open callback datasource.\n"));
967 result = i_readgif_low(GifFile, colour_table, colours);
968 free_gen_read_data(gci);
977 =item do_write(GifFileType *gf, i_gif_opts *opts, i_img *img, i_palidx *data)
979 Internal. Low level image write function. Writes in interlace if
980 that was requested in the GIF options.
982 Returns non-zero on success.
987 do_write(GifFileType *gf, i_gif_opts *opts, i_img *img, i_palidx *data) {
988 if (opts->interlace) {
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) {
994 i_push_error(0, "Could not save image data:");
995 mm_log((1, "Error in EGifPutLine\n"));
1004 for (y = 0; y < img->ysize; ++y) {
1005 if (EGifPutLine(gf, data, img->xsize) == GIF_ERROR) {
1007 i_push_error(0, "Could not save image data:");
1008 mm_log((1, "Error in EGifPutLine\n"));
1020 =item do_gce(GifFileType *gf, int index, i_gif_opts *opts, int want_trans, int trans_index)
1022 Internal. Writes the GIF graphics control extension, if necessary.
1024 Returns non-zero on success.
1028 static int do_gce(GifFileType *gf, int index, i_gif_opts *opts, int want_trans, int trans_index)
1030 unsigned char gce[4] = {0};
1034 gce[3] = trans_index;
1037 if (index < opts->delay_count) {
1038 gce[1] = opts->delays[index] % 256;
1039 gce[2] = opts->delays[index] / 256;
1042 if (index < opts->user_input_count) {
1043 if (opts->user_input_flags[index])
1047 if (index < opts->disposal_count) {
1048 gce[0] |= (opts->disposal[index] & 3) << 2;
1052 if (EGifPutExtension(gf, 0xF9, sizeof(gce), gce) == GIF_ERROR) {
1054 i_push_error(0, "Could not save GCE");
1061 =item do_ns_loop(GifFileType *gf, i_gif_opts *opts)
1063 Internal. Add the Netscape2.0 loop extension block, if requested.
1065 The code for this function is currently "#if 0"ed out since the giflib
1066 extension writing code currently doesn't seem to support writing
1067 application extension blocks.
1071 static int do_ns_loop(GifFileType *gf, i_gif_opts *opts)
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
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.
1084 /* yes this was another attempt at supporting the loop extension */
1085 if (opts->loop_count) {
1086 unsigned char nsle[12] = "NETSCAPE2.0";
1087 unsigned char subblock[3];
1088 if (EGifPutExtension(gf, 0xFF, 11, nsle) == GIF_ERROR) {
1090 i_push_error(0, "writing loop extension");
1094 subblock[1] = opts->loop_count % 256;
1095 subblock[2] = opts->loop_count / 256;
1096 if (EGifPutExtension(gf, 0, 3, subblock) == GIF_ERROR) {
1098 i_push_error(0, "writing loop extention sub-block");
1101 if (EGifPutExtension(gf, 0, 0, subblock) == GIF_ERROR) {
1103 i_push_error(0, "writing loop extension terminator");
1112 =item make_gif_map(i_quantize *quant, i_gif_opts *opts, int want_trans)
1114 Create a giflib color map object from an Imager color map.
1119 static ColorMapObject *make_gif_map(i_quantize *quant, i_gif_opts *opts,
1121 GifColorType colors[256];
1123 int size = quant->mc_count;
1125 ColorMapObject *map;
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;
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;
1139 while (map_size < size)
1141 /* giflib spews for 1 colour maps, reasonable, I suppose */
1145 map = MakeMapObject(map_size, colors);
1146 mm_log((1, "XXX map is at %p and colors at %p\n", map, map->Colors));
1149 i_push_error(0, "Could not create color map object");
1156 =item gif_set_version(i_quantize *quant, i_gif_opts *opts)
1158 We need to call EGifSetGifVersion() before opening the file - put that
1161 Unfortunately giflib 4.1.0 crashes when we use this. Internally
1162 giflib 4.1.0 has code:
1164 static char *GifVersionPrefix = GIF87_STAMP;
1166 and the code that sets the version internally does:
1168 strncpy(&GifVersionPrefix[3], Version, 3);
1170 which is very broken.
1172 Failing to set the correct GIF version doesn't seem to cause a problem
1178 static 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
1183 if (opts->delay_count
1184 || opts->user_input_count
1185 || opts->disposal_count
1187 || quant->transp != tr_none)
1188 EGifSetGifVersion("89a");
1190 EGifSetGifVersion("87a");
1195 in_palette(i_color *c, i_quantize *quant, int size) {
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]) {
1210 =item has_common_palette(imgs, count, quant, want_trans)
1212 Tests if all the given images are paletted and have a common palette,
1213 if they do it builds that palette.
1215 A possible improvement might be to eliminate unused colors in the
1220 has_common_palette(i_img **imgs, int count, i_quantize *quant, int want_trans,
1222 int size = quant->mc_count;
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)
1234 if (opts->eliminate_unused) {
1235 i_palidx *line = mymalloc(sizeof(i_palidx) * imgs[imgn]->xsize);
1237 memset(used, 0, sizeof(used));
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)
1248 /* assume all are in use */
1249 memset(used, 1, sizeof(used));
1252 for (i = 0; i < i_colorcount(imgs[imgn]); ++i) {
1255 i_getcolors(imgs[imgn], i, &c, 1);
1257 if (in_palette(&c, quant, size) < 0) {
1258 if (size < quant->mc_size) {
1259 quant->mc_colors[size++] = c;
1262 /* oops, too many colors */
1270 quant->mc_count = size;
1276 quant_paletted(i_quantize *quant, i_img *img) {
1277 i_palidx *data = mymalloc(sizeof(i_palidx) * img->xsize * img->ysize);
1279 i_palidx trans[256];
1283 /* build a translation table */
1284 for (i = 0; i < i_colorcount(img); ++i) {
1286 i_getcolors(img, i, &c, 1);
1287 trans[i] = in_palette(&c, quant, quant->mc_count);
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) {
1302 =item i_writegif_low(i_quantize *quant, GifFileType *gf, i_img **imgs, int count, i_gif_opts *opts)
1304 Internal. Low-level function that does the high-level GIF processing
1307 Returns non-zero on success.
1313 i_writegif_low(i_quantize *quant, GifFileType *gf, i_img **imgs, int count,
1315 unsigned char *result;
1317 ColorMapObject *map;
1318 int scrw = 0, scrh = 0;
1319 int imgn, orig_count, orig_size;
1323 mm_log((1, "i_writegif_low(quant %p, gf %p, imgs %p, count %d, opts %p)\n",
1324 quant, gf, imgs, count, opts));
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;
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;
1341 if (imgs[imgn]->xsize > scrw)
1342 scrw = imgs[imgn]->xsize;
1343 if (imgs[imgn]->ysize > scrh)
1344 scrh = imgs[imgn]->ysize;
1349 i_push_error(0, "No images provided to write");
1350 return 0; /* what are you smoking? */
1353 orig_count = quant->mc_count;
1354 orig_size = quant->mc_size;
1356 if (opts->each_palette) {
1357 int want_trans = quant->transp != tr_none
1358 && imgs[0]->channels == 4;
1360 /* if the caller gives us too many colours we can't do transparency */
1361 if (want_trans && quant->mc_count == 256)
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)
1368 /* we always generate a global palette - this lets systems with a
1369 broken giflib work */
1370 if (has_common_palette(imgs, 1, quant, want_trans, opts)) {
1371 result = quant_paletted(quant, imgs[0]);
1374 quant_makemap(quant, imgs, 1);
1375 result = quant_translate(quant, imgs[0]);
1378 trans_index = quant->mc_count;
1379 quant_transparent(quant, result, imgs[0], trans_index);
1382 if ((map = make_gif_map(quant, opts, want_trans)) == NULL) {
1385 mm_log((1, "Error in MakeMapObject."));
1390 while (quant->mc_size > (1 << color_bits))
1393 if (EGifPutScreenDesc(gf, scrw, scrh, color_bits, 0, map) == GIF_ERROR) {
1395 i_push_error(0, "Could not save screen descriptor");
1399 mm_log((1, "Error in EGifPutScreenDesc."));
1404 if (!do_ns_loop(gf, opts))
1407 if (!do_gce(gf, 0, opts, want_trans, trans_index)) {
1412 if (opts->position_count) {
1413 posx = opts->positions[0].x;
1414 posy = opts->positions[0].y;
1418 if (EGifPutImageDesc(gf, posx, posy, imgs[0]->xsize, imgs[0]->ysize,
1419 opts->interlace, NULL) == GIF_ERROR) {
1421 i_push_error(0, "Could not save image descriptor");
1423 mm_log((1, "Error in EGifPutImageDesc."));
1426 if (!do_write(gf, opts, imgs[0], result)) {
1431 for (imgn = 1; imgn < count; ++imgn) {
1432 quant->mc_count = orig_count;
1433 quant->mc_size = orig_size;
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)
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)
1444 if (has_common_palette(imgs+imgn, 1, quant, want_trans, opts)) {
1445 result = quant_paletted(quant, imgs[imgn]);
1448 quant_makemap(quant, imgs+imgn, 1);
1449 result = quant_translate(quant, imgs[imgn]);
1452 quant_transparent(quant, result, imgs[imgn], quant->mc_count);
1453 trans_index = quant->mc_count;
1456 if (!do_gce(gf, imgn, opts, want_trans, quant->mc_count)) {
1461 if ((map = make_gif_map(quant, opts, want_trans)) == NULL) {
1464 mm_log((1, "Error in MakeMapObject."));
1467 if (imgn < opts->position_count) {
1468 posx = opts->positions[imgn].x;
1469 posy = opts->positions[imgn].y;
1473 if (EGifPutImageDesc(gf, posx, posy, imgs[imgn]->xsize,
1474 imgs[imgn]->ysize, opts->interlace,
1475 map) == GIF_ERROR) {
1477 i_push_error(0, "Could not save image descriptor");
1481 mm_log((1, "Error in EGifPutImageDesc."));
1486 if (!do_write(gf, opts, imgs[imgn], result)) {
1496 int do_quant_paletted = 0;
1498 /* get a palette entry for the transparency iff we have an image
1499 with an alpha channel */
1501 for (imgn = 0; imgn < count; ++imgn) {
1502 if (imgs[imgn]->channels == 4) {
1507 want_trans = want_trans && quant->transp != tr_none
1508 && quant->mc_count < 256;
1509 if (want_trans && quant->mc_size == 256)
1512 /* handle the first image separately - since we allow giflib
1513 conversion and giflib doesn't give us a separate function to build
1516 /* produce a colour map */
1517 if (has_common_palette(imgs, count, quant, want_trans, opts)) {
1518 result = quant_paletted(quant, imgs[0]);
1519 ++do_quant_paletted;
1522 quant_makemap(quant, imgs, count);
1523 result = quant_translate(quant, imgs[0]);
1526 if ((map = make_gif_map(quant, opts, want_trans)) == NULL) {
1529 mm_log((1, "Error in MakeMapObject"));
1533 while (quant->mc_count > (1 << color_bits))
1536 if (EGifPutScreenDesc(gf, scrw, scrh, color_bits, 0, map) == GIF_ERROR) {
1538 i_push_error(0, "Could not save screen descriptor");
1542 mm_log((1, "Error in EGifPutScreenDesc."));
1547 if (!do_ns_loop(gf, opts))
1550 if (!do_gce(gf, 0, opts, want_trans, quant->mc_count)) {
1555 if (opts->position_count) {
1556 posx = opts->positions[0].x;
1557 posy = opts->positions[0].y;
1561 if (EGifPutImageDesc(gf, posx, posy, imgs[0]->xsize, imgs[0]->ysize,
1562 opts->interlace, NULL) == GIF_ERROR) {
1564 i_push_error(0, "Could not save image descriptor");
1566 mm_log((1, "Error in EGifPutImageDesc."));
1569 if (want_trans && imgs[0]->channels == 4)
1570 quant_transparent(quant, result, imgs[0], quant->mc_count);
1572 if (!do_write(gf, opts, imgs[0], result)) {
1579 for (imgn = 1; imgn < count; ++imgn) {
1581 if (do_quant_paletted)
1582 result = quant_paletted(quant, imgs[imgn]);
1584 result = quant_translate(quant, imgs[imgn]);
1585 local_trans = want_trans && imgs[imgn]->channels == 4;
1587 quant_transparent(quant, result, imgs[imgn], quant->mc_count);
1588 if (!do_gce(gf, imgn, opts, local_trans, quant->mc_count)) {
1593 if (imgn < opts->position_count) {
1594 posx = opts->positions[imgn].x;
1595 posy = opts->positions[imgn].y;
1599 if (EGifPutImageDesc(gf, posx, posy,
1600 imgs[imgn]->xsize, imgs[imgn]->ysize,
1601 opts->interlace, NULL) == GIF_ERROR) {
1603 i_push_error(0, "Could not save image descriptor");
1606 mm_log((1, "Error in EGifPutImageDesc."));
1609 if (!do_write(gf, opts, imgs[imgn], result)) {
1617 if (EGifCloseFile(gf) == GIF_ERROR) {
1619 i_push_error(0, "Could not close GIF file");
1620 mm_log((1, "Error in EGifCloseFile\n"));
1628 =item i_writegif_gen(i_quantize *quant, int fd, i_img **imgs, int count, i_gif_opts *opts)
1630 General high-level function to write a GIF to a file.
1632 Writes the GIF images to the specified file handle using the options
1633 in quant and opts. See L<image.h/i_quantize> and
1634 L<image.h/i_gif_opts>.
1636 Returns non-zero on success.
1642 i_writegif_gen(i_quantize *quant, int fd, i_img **imgs, int count,
1647 mm_log((1, "i_writegif_gen(quant %p, fd %d, imgs %p, count %d, opts %p)\n",
1648 quant, fd, imgs, count, opts));
1650 gif_set_version(quant, opts);
1652 if ((gf = EGifOpenFileHandle(fd)) == NULL) {
1654 i_push_error(0, "Cannot create GIF file object");
1655 mm_log((1, "Error in EGifOpenFileHandle, unable to write image.\n"));
1659 return i_writegif_low(quant, gf, imgs, count, opts);
1662 #if IM_GIFMAJOR >= 4
1665 =item gif_writer_callback(GifFileType *gf, const GifByteType *data, int size)
1667 Internal. Wrapper for the user write callback function.
1672 static int gif_writer_callback(GifFileType *gf, const GifByteType *data, int size)
1674 i_gen_write_data *gwd = (i_gen_write_data *)gf->UserData;
1676 return i_gen_writer(gwd, (char*)data, size) ? size : 0;
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)
1684 General high-level function to write a GIF using callbacks to send
1687 Returns non-zero on success.
1693 i_writegif_callback(i_quantize *quant, i_write_callback_t cb, char *userdata,
1694 int maxlength, i_img **imgs, int count, i_gif_opts *opts)
1696 #if IM_GIFMAJOR >= 4
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);
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));
1708 if ((gf = EGifOpen(gwd, &gif_writer_callback)) == NULL) {
1710 i_push_error(0, "Cannot create GIF file object");
1711 mm_log((1, "Error in EGifOpenFileHandle, unable to write image.\n"));
1712 free_gen_write_data(gwd, 0);
1716 result = i_writegif_low(quant, gf, imgs, count, opts);
1717 return free_gen_write_data(gwd, result);
1724 =item gif_error_msg(int code)
1726 Grabs the most recent giflib error code from GifLastError() and
1727 returns a string that describes that error.
1729 The returned pointer points to a static buffer, either from a literal
1730 C string or a static buffer.
1734 static char const *gif_error_msg(int code) {
1735 static char msg[80];
1738 case E_GIF_ERR_OPEN_FAILED: /* should not see this */
1739 return "Failed to open given file";
1741 case E_GIF_ERR_WRITE_FAILED:
1742 return "Write failed";
1744 case E_GIF_ERR_HAS_SCRN_DSCR: /* should not see this */
1745 return "Screen descriptor already passed to giflib";
1747 case E_GIF_ERR_HAS_IMAG_DSCR: /* should not see this */
1748 return "Image descriptor already passed to giflib";
1750 case E_GIF_ERR_NO_COLOR_MAP: /* should not see this */
1751 return "Neither global nor local color map set";
1753 case E_GIF_ERR_DATA_TOO_BIG: /* should not see this */
1754 return "Too much pixel data passed to giflib";
1756 case E_GIF_ERR_NOT_ENOUGH_MEM:
1757 return "Out of memory";
1759 case E_GIF_ERR_DISK_IS_FULL:
1760 return "Disk is full";
1762 case E_GIF_ERR_CLOSE_FAILED: /* should not see this */
1763 return "File close failed";
1765 case E_GIF_ERR_NOT_WRITEABLE: /* should not see this */
1766 return "File not writable";
1768 case D_GIF_ERR_OPEN_FAILED:
1769 return "Failed to open file";
1771 case D_GIF_ERR_READ_FAILED:
1772 return "Failed to read from file";
1774 case D_GIF_ERR_NOT_GIF_FILE:
1775 return "File is not a GIF file";
1777 case D_GIF_ERR_NO_SCRN_DSCR:
1778 return "No screen descriptor detected - invalid file";
1780 case D_GIF_ERR_NO_IMAG_DSCR:
1781 return "No image descriptor detected - invalid file";
1783 case D_GIF_ERR_NO_COLOR_MAP:
1784 return "No global or local color map found";
1786 case D_GIF_ERR_WRONG_RECORD:
1787 return "Wrong record type detected - invalid file?";
1789 case D_GIF_ERR_DATA_TOO_BIG:
1790 return "Data in file too big for image";
1792 case D_GIF_ERR_NOT_ENOUGH_MEM:
1793 return "Out of memory";
1795 case D_GIF_ERR_CLOSE_FAILED:
1796 return "Close failed";
1798 case D_GIF_ERR_NOT_READABLE:
1799 return "File not opened for read";
1801 case D_GIF_ERR_IMAGE_DEFECT:
1802 return "Defective image";
1804 case D_GIF_ERR_EOF_TOO_SOON:
1805 return "Unexpected EOF - invalid file";
1808 sprintf(msg, "Unknown giflib error code %d", code);
1814 =item gif_push_error()
1816 Utility function that takes the current GIF error code, converts it to
1817 an error message and pushes it on the error stack.
1822 static void gif_push_error(void) {
1823 int code = GifLastError(); /* clears saved error */
1825 i_push_error(code, gif_error_msg(code));
1831 The Netscape loop extension isn't implemented. Giflib's extension
1832 writing code doesn't seem to support writing named extensions in this
1835 A bug in giflib is tickled by the i_writegif_callback(). This isn't a
1836 problem on ungiflib, but causes a SEGV on giflib. A patch is provided
1839 The GIF file tag (GIF87a vs GIF89a) currently isn't set. Using the
1840 supplied interface in giflib 4.1.0 causes a SEGV in
1841 EGifSetGifVersion(). See L<gif_set_version> for an explanation.
1845 Arnar M. Hrafnkelsson, addi@umich.edu