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 = 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;
195 DGifCloseFile(GifFile);
199 switch (RecordType) {
200 case IMAGE_DESC_RECORD_TYPE:
201 if (DGifGetImageDesc(GifFile) == GIF_ERROR) {
203 i_push_error(0, "Unable to get image descriptor");
204 if (colour_table && *colour_table) {
205 myfree(*colour_table);
206 *colour_table = NULL;
210 DGifCloseFile(GifFile);
214 if (( ColorMap = (GifFile->Image.ColorMap ? GifFile->Image.ColorMap : GifFile->SColorMap) )) {
215 mm_log((1, "Adding local colormap\n"));
216 ColorMapSize = ColorMap->ColorCount;
218 i_colortable_copy(colour_table, colours, ColorMap);
222 /* No colormap and we are about to read in the image - abandon for now */
223 mm_log((1, "Going in with no colormap\n"));
224 i_push_error(0, "Image does not have a local or a global color map");
225 /* we can't have allocated a colour table here */
228 DGifCloseFile(GifFile);
232 Row = GifFile->Image.Top; /* Image Position relative to Screen. */
233 Col = GifFile->Image.Left;
234 Width = GifFile->Image.Width;
235 Height = GifFile->Image.Height;
237 mm_log((1,"i_readgif_low: Image %d at (%d, %d) [%dx%d]: \n",ImageNum, Col, Row, Width, Height));
239 if (GifFile->Image.Left + GifFile->Image.Width > GifFile->SWidth ||
240 GifFile->Image.Top + GifFile->Image.Height > GifFile->SHeight) {
241 i_push_errorf(0, "Image %d is not confined to screen dimension, aborted.\n",ImageNum);
242 if (colour_table && *colour_table) {
243 myfree(*colour_table);
244 *colour_table = NULL;
248 DGifCloseFile(GifFile);
251 if (GifFile->Image.Interlace) {
253 for (Count = i = 0; i < 4; i++) for (j = Row + InterlacedOffset[i]; j < Row + Height; j += InterlacedJumps[i]) {
255 if (DGifGetLine(GifFile, GifRow, Width) == GIF_ERROR) {
257 i_push_error(0, "Reading GIF line");
258 if (colour_table && *colour_table) {
259 myfree(*colour_table);
260 *colour_table = NULL;
264 DGifCloseFile(GifFile);
268 for (x = 0; x < Width; x++) {
269 ColorMapEntry = &ColorMap->Colors[GifRow[x]];
270 col.rgb.r = ColorMapEntry->Red;
271 col.rgb.g = ColorMapEntry->Green;
272 col.rgb.b = ColorMapEntry->Blue;
273 i_ppix(im,Col+x,j,&col);
279 for (i = 0; i < Height; i++) {
280 if (DGifGetLine(GifFile, GifRow, Width) == GIF_ERROR) {
282 i_push_error(0, "Reading GIF line");
283 if (colour_table && *colour_table) {
284 myfree(*colour_table);
285 *colour_table = NULL;
289 DGifCloseFile(GifFile);
293 for (x = 0; x < Width; x++) {
294 ColorMapEntry = &ColorMap->Colors[GifRow[x]];
295 col.rgb.r = ColorMapEntry->Red;
296 col.rgb.g = ColorMapEntry->Green;
297 col.rgb.b = ColorMapEntry->Blue;
298 i_ppix(im, Col+x, Row, &col);
304 case EXTENSION_RECORD_TYPE:
305 /* Skip any extension blocks in file: */
306 if (DGifGetExtension(GifFile, &ExtCode, &Extension) == GIF_ERROR) {
308 i_push_error(0, "Reading extension record");
309 if (colour_table && *colour_table) {
310 myfree(*colour_table);
311 *colour_table = NULL;
315 DGifCloseFile(GifFile);
318 while (Extension != NULL) {
319 if (DGifGetExtensionNext(GifFile, &Extension) == GIF_ERROR) {
321 i_push_error(0, "reading next block of extension");
322 if (colour_table && *colour_table) {
323 myfree(*colour_table);
324 *colour_table = NULL;
328 DGifCloseFile(GifFile);
333 case TERMINATE_RECORD_TYPE:
335 default: /* Should be traps by DGifGetRecordType. */
338 } while (RecordType != TERMINATE_RECORD_TYPE);
342 if (DGifCloseFile(GifFile) == GIF_ERROR) {
344 i_push_error(0, "Closing GIF file object");
345 if (colour_table && *colour_table) {
346 myfree(*colour_table);
347 *colour_table = NULL;
356 =item i_readgif(int fd, int **colour_table, int *colours)
358 Reads in a GIF file from a file handle and converts it to an Imager
361 Returns the palette for the object in colour_table for colours
364 Returns NULL on failure.
370 i_readgif(int fd, int **colour_table, int *colours) {
371 GifFileType *GifFile;
375 mm_log((1,"i_readgif(fd %d, colour_table %p, colours %p)\n", fd, colour_table, colours));
377 if ((GifFile = DGifOpenFileHandle(fd)) == NULL) {
379 i_push_error(0, "Cannot create giflib file object");
380 mm_log((1,"i_readgif: Unable to open file\n"));
384 return i_readgif_low(GifFile, colour_table, colours);
389 Internal function called by i_readgif_multi_low() in error handling
392 static void free_images(i_img **imgs, int count) {
394 for (i = 0; i < count; ++i)
395 i_img_destroy(imgs[i]);
400 =item i_readgif_multi_low(GifFileType *gf, int *count)
402 Reads one of more gif images from the given GIF file.
404 Returns a pointer to an array of i_img *, and puts the count into
407 Unlike the normal i_readgif*() functions the images are paletted
408 images rather than a combined RGB image.
410 This functions sets tags on the images returned:
416 the offset of the image from the left of the "screen" ("Image Left
421 the offset of the image from the top of the "screen" ("Image Top Position")
425 non-zero if the image was interlaced ("Interlace Flag")
427 =item gif_screen_width
429 =item gif_screen_height
431 the size of the logical screen ("Logical Screen Width",
432 "Logical Screen Height")
436 Non-zero if this image had a local color map.
440 The index in the global colormap of the logical screen's background
441 color. This is only set if the current image uses the global
444 =item gif_trans_index
446 The index of the color in the colormap used for transparency. If the
447 image has a transparency then it is returned as a 4 channel image with
448 the alpha set to zero in this palette entry. ("Transparent Color Index")
452 The delay until the next frame is displayed, in 1/100 of a second.
457 whether or not a user input is expected before continuing (view dependent)
462 how the next frame is displayed ("Disposal Method")
466 the number of loops from the Netscape Loop extension. This may be zero.
470 the first block of the first gif comment before each image.
474 Where applicable, the ("name") is the name of that field from the GIF89
480 i_img **i_readgif_multi_low(GifFileType *GifFile, int *count) {
482 int i, j, Size, Width, Height, ExtCode, Count, x;
483 int ImageNum = 0, BackGround = 0, ColorMapSize = 0;
484 ColorMapObject *ColorMap;
486 GifRecordType RecordType;
487 GifByteType *Extension;
491 int trans_index; /* transparent index if we see a GCE */
492 int gif_delay; /* delay from a GCE */
493 int user_input; /* user input flag from a GCE */
494 int disposal; /* disposal method from a GCE */
497 char *comment = NULL; /* a comment */
498 i_img **results = NULL;
499 int result_alloc = 0;
504 mm_log((1,"i_readgif_multi_low(GifFile %p, , count %p)\n", GifFile, count));
506 BackGround = GifFile->SBackGroundColor;
508 Size = GifFile->SWidth * sizeof(GifPixelType);
510 if ((GifRow = (GifRowType) mymalloc(Size)) == NULL)
511 m_fatal(0,"Failed to allocate memory required, aborted."); /* First row. */
513 /* Scan the content of the GIF file and load the image(s) in: */
515 if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR) {
517 i_push_error(0, "Unable to get record type");
518 free_images(results, *count);
519 DGifCloseFile(GifFile);
523 switch (RecordType) {
524 case IMAGE_DESC_RECORD_TYPE:
525 if (DGifGetImageDesc(GifFile) == GIF_ERROR) {
527 i_push_error(0, "Unable to get image descriptor");
528 free_images(results, *count);
529 DGifCloseFile(GifFile);
533 if (( ColorMap = (GifFile->Image.ColorMap ? GifFile->Image.ColorMap : GifFile->SColorMap) )) {
534 mm_log((1, "Adding local colormap\n"));
535 ColorMapSize = ColorMap->ColorCount;
537 /* No colormap and we are about to read in the image -
539 mm_log((1, "Going in with no colormap\n"));
540 i_push_error(0, "Image does not have a local or a global color map");
541 free_images(results, *count);
542 DGifCloseFile(GifFile);
546 Width = GifFile->Image.Width;
547 Height = GifFile->Image.Height;
549 if (got_gce && trans_index >= 0)
551 img = i_img_pal_new(Width, Height, channels, 256);
552 /* populate the palette of the new image */
553 mm_log((1, "ColorMapSize %d\n", ColorMapSize));
554 for (i = 0; i < ColorMapSize; ++i) {
556 col.rgba.r = ColorMap->Colors[i].Red;
557 col.rgba.g = ColorMap->Colors[i].Green;
558 col.rgba.b = ColorMap->Colors[i].Blue;
559 if (channels == 4 && trans_index == i)
564 i_addcolors(img, &col, 1);
567 if (*count > result_alloc) {
568 if (result_alloc == 0) {
570 results = mymalloc(result_alloc * sizeof(i_img *));
575 newresults = myrealloc(results, result_alloc * sizeof(i_img *));
578 results[*count-1] = img;
579 i_tags_addn(&img->tags, "gif_left", 0, GifFile->Image.Left);
581 i_tags_addn(&img->tags, "gif_top", 0, GifFile->Image.Top);
582 i_tags_addn(&img->tags, "gif_interlace", 0, GifFile->Image.Interlace);
583 i_tags_addn(&img->tags, "gif_screen_width", 0, GifFile->SWidth);
584 i_tags_addn(&img->tags, "gif_screen_height", 0, GifFile->SHeight);
585 if (GifFile->SColorMap && !GifFile->Image.ColorMap) {
586 i_tags_addn(&img->tags, "gif_background", 0,
587 GifFile->SBackGroundColor);
589 if (GifFile->Image.ColorMap) {
590 i_tags_addn(&img->tags, "gif_localmap", 0, 1);
593 if (trans_index >= 0)
594 i_tags_addn(&img->tags, "gif_trans_index", 0, trans_index);
595 i_tags_addn(&img->tags, "gif_delay", 0, gif_delay);
596 i_tags_addn(&img->tags, "gif_user_input", 0, user_input);
597 i_tags_addn(&img->tags, "gif_disposal", 0, disposal);
601 i_tags_addn(&img->tags, "gif_loop", 0, ns_loop);
603 i_tags_add(&img->tags, "gif_comment", 0, comment, strlen(comment), 0);
609 mm_log((1,"i_readgif_multi_low: Image %d at (%d, %d) [%dx%d]: \n",
610 ImageNum, GifFile->Image.Left, GifFile->Image.Top, Width, Height));
612 if (GifFile->Image.Left + GifFile->Image.Width > GifFile->SWidth ||
613 GifFile->Image.Top + GifFile->Image.Height > GifFile->SHeight) {
614 i_push_errorf(0, "Image %d is not confined to screen dimension, aborted.\n",ImageNum);
615 free_images(results, *count);
616 DGifCloseFile(GifFile);
620 if (GifFile->Image.Interlace) {
621 for (Count = i = 0; i < 4; i++) {
622 for (j = InterlacedOffset[i]; j < Height;
623 j += InterlacedJumps[i]) {
625 if (DGifGetLine(GifFile, GifRow, Width) == GIF_ERROR) {
627 i_push_error(0, "Reading GIF line");
628 free_images(results, *count);
629 DGifCloseFile(GifFile);
633 i_ppal(img, 0, Width, j, GifRow);
638 for (i = 0; i < Height; i++) {
639 if (DGifGetLine(GifFile, GifRow, Width) == GIF_ERROR) {
641 i_push_error(0, "Reading GIF line");
642 free_images(results, *count);
643 DGifCloseFile(GifFile);
647 i_ppal(img, 0, Width, i, GifRow);
651 case EXTENSION_RECORD_TYPE:
652 /* Skip any extension blocks in file: */
653 if (DGifGetExtension(GifFile, &ExtCode, &Extension) == GIF_ERROR) {
655 i_push_error(0, "Reading extension record");
656 free_images(results, *count);
657 DGifCloseFile(GifFile);
660 if (ExtCode == 0xF9) {
662 if (Extension[1] & 1)
663 trans_index = Extension[4];
666 gif_delay = Extension[2] + 256 * Extension[3];
667 user_input = (Extension[0] & 2) != 0;
668 disposal = (Extension[0] >> 2) & 3;
670 if (ExtCode == 0xFF && *Extension == 11) {
671 if (memcmp(Extension+1, "NETSCAPE2.0", 11) == 0) {
672 if (DGifGetExtensionNext(GifFile, &Extension) == GIF_ERROR) {
674 i_push_error(0, "reading loop extension");
675 free_images(results, *count);
676 DGifCloseFile(GifFile);
679 if (Extension && *Extension == 3) {
681 ns_loop = Extension[2] + 256 * Extension[3];
685 else if (ExtCode == 0xFE) {
686 /* while it's possible for a GIF file to contain more than one
687 comment, I'm only implementing a single comment per image,
688 with the comment saved into the following image.
689 If someone wants more than that they can implement it.
690 I also don't handle comments that take more than one block.
693 comment = mymalloc(*Extension+1);
694 memcpy(comment, Extension+1, *Extension);
695 comment[*Extension] = '\0';
698 while (Extension != NULL) {
699 if (DGifGetExtensionNext(GifFile, &Extension) == GIF_ERROR) {
701 i_push_error(0, "reading next block of extension");
702 free_images(results, *count);
703 DGifCloseFile(GifFile);
708 case TERMINATE_RECORD_TYPE:
710 default: /* Should be trapped by DGifGetRecordType. */
713 } while (RecordType != TERMINATE_RECORD_TYPE);
717 i_tags_add(&(results[*count-1]->tags), "gif_comment", 0, comment,
725 if (DGifCloseFile(GifFile) == GIF_ERROR) {
727 i_push_error(0, "Closing GIF file object");
728 free_images(results, *count);
736 =item i_readgif_multi(int fd, int *count)
741 i_readgif_multi(int fd, int *count) {
742 GifFileType *GifFile;
746 mm_log((1,"i_readgif_multi(fd %d, &count %p)\n", fd, count));
748 if ((GifFile = DGifOpenFileHandle(fd)) == NULL) {
750 i_push_error(0, "Cannot create giflib file object");
751 mm_log((1,"i_readgif: Unable to open file\n"));
755 return i_readgif_multi_low(GifFile, count);
759 =item i_readgif_multi_scalar(char *data, int length, int *count)
764 i_readgif_multi_scalar(char *data, int length, int *count) {
766 GifFileType *GifFile;
767 struct gif_scalar_info gsi;
775 mm_log((1,"i_readgif_multi_scalar(data %p, length %d, &count %p)\n",
776 data, length, count));
778 if ((GifFile = DGifOpen( (void*) &gsi, my_gif_inputfunc )) == NULL) {
780 i_push_error(0, "Cannot create giflib callback object");
781 mm_log((1,"i_readgif_multi_scalar: Unable to open scalar datasource.\n"));
785 return i_readgif_multi_low(GifFile, count);
792 =item i_readgif_callback(i_read_callback_t cb, char *userdata, int **colour_table, int *colours)
794 Read a GIF file into an Imager RGB file, the data of the GIF file is
795 retreived by callin the user supplied callback function.
797 This function is only used with giflib 4 and higher.
803 i_readgif_multi_callback(i_read_callback_t cb, char *userdata, int *count) {
805 GifFileType *GifFile;
808 i_gen_read_data *gci = i_gen_read_data_new(cb, userdata);
812 mm_log((1,"i_readgif_multi_callback(callback %p, userdata %p, count %p)\n", cb, userdata, count));
813 if ((GifFile = DGifOpen( (void*) gci, gif_read_callback )) == NULL) {
815 i_push_error(0, "Cannot create giflib callback object");
816 mm_log((1,"i_readgif_callback: Unable to open callback datasource.\n"));
821 result = i_readgif_multi_low(GifFile, count);
822 free_gen_read_data(gci);
831 =item i_writegif(i_img *im, int fd, int max_colors, int pixdev, int fixedlen, i_color fixed[])
833 Write I<img> to the file handle I<fd>. The resulting GIF will use a
834 maximum of 1<<I<max_colours> colours, with the first I<fixedlen>
835 colours taken from I<fixed>.
837 Returns non-zero on success.
843 i_writegif(i_img *im, int fd, int max_colors, int pixdev, int fixedlen, i_color fixed[]) {
848 memset(&quant, 0, sizeof(quant));
849 memset(&opts, 0, sizeof(opts));
850 quant.make_colors = mc_addi;
851 quant.mc_colors = colors;
852 quant.mc_size = 1<<max_colors;
853 quant.mc_count = fixedlen;
854 memcpy(colors, fixed, fixedlen * sizeof(i_color));
855 quant.translate = pt_perturb;
856 quant.perturb = pixdev;
857 return i_writegif_gen(&quant, fd, &im, 1, &opts);
861 =item i_writegifmc(i_img *im, int fd, int max_colors)
863 Write I<img> to the file handle I<fd>. The resulting GIF will use a
864 maximum of 1<<I<max_colours> colours.
866 Returns non-zero on success.
872 i_writegifmc(i_img *im, int fd, int max_colors) {
877 memset(&quant, 0, sizeof(quant));
878 memset(&opts, 0, sizeof(opts));
879 quant.make_colors = mc_none; /* ignored for pt_giflib */
880 quant.mc_colors = colors;
881 quant.mc_size = 1 << max_colors;
883 quant.translate = pt_giflib;
884 return i_writegif_gen(&quant, fd, &im, 1, &opts);
889 =item i_readgif_scalar(char *data, int length, int **colour_table, int *colours)
891 Reads a GIF file from an in memory copy of the file. This can be used
892 if you get the 'file' from some source other than an actual file (or
893 some other file handle).
895 This function is only available with giflib 4 and higher.
900 i_readgif_scalar(char *data, int length, int **colour_table, int *colours) {
902 GifFileType *GifFile;
903 struct gif_scalar_info gsi;
911 mm_log((1,"i_readgif_scalar(char* data, int length, colour_table %p, colours %p)\n", data, length, colour_table, colours));
912 if ((GifFile = DGifOpen( (void*) &gsi, my_gif_inputfunc )) == NULL) {
914 i_push_error(0, "Cannot create giflib callback object");
915 mm_log((1,"i_readgif_scalar: Unable to open scalar datasource.\n"));
919 return i_readgif_low(GifFile, colour_table, colours);
928 =item gif_read_callback(GifFileType *gft, GifByteType *buf, int length)
930 Internal. The reader callback wrapper passed to giflib.
932 This function is only used with giflib 4 and higher.
938 gif_read_callback(GifFileType *gft, GifByteType *buf, int length) {
939 return i_gen_reader((i_gen_read_data *)gft->UserData, (char*)buf, length);
946 =item i_readgif_callback(i_read_callback_t cb, char *userdata, int **colour_table, int *colours)
948 Read a GIF file into an Imager RGB file, the data of the GIF file is
949 retreived by callin the user supplied callback function.
951 This function is only used with giflib 4 and higher.
957 i_readgif_callback(i_read_callback_t cb, char *userdata, int **colour_table, int *colours) {
959 GifFileType *GifFile;
962 i_gen_read_data *gci = i_gen_read_data_new(cb, userdata);
966 mm_log((1,"i_readgif_callback(callback %p, userdata %p, colour_table %p, colours %p)\n", cb, userdata, colour_table, colours));
967 if ((GifFile = DGifOpen( (void*) gci, gif_read_callback )) == NULL) {
969 i_push_error(0, "Cannot create giflib callback object");
970 mm_log((1,"i_readgif_callback: Unable to open callback datasource.\n"));
975 result = i_readgif_low(GifFile, colour_table, colours);
976 free_gen_read_data(gci);
985 =item do_write(GifFileType *gf, i_gif_opts *opts, i_img *img, i_palidx *data)
987 Internal. Low level image write function. Writes in interlace if
988 that was requested in the GIF options.
990 Returns non-zero on success.
995 do_write(GifFileType *gf, i_gif_opts *opts, i_img *img, i_palidx *data) {
996 if (opts->interlace) {
998 for (i = 0; i < 4; ++i) {
999 for (j = InterlacedOffset[i]; j < img->ysize; j += InterlacedJumps[i]) {
1000 if (EGifPutLine(gf, data+j*img->xsize, img->xsize) == GIF_ERROR) {
1002 i_push_error(0, "Could not save image data:");
1003 mm_log((1, "Error in EGifPutLine\n"));
1012 for (y = 0; y < img->ysize; ++y) {
1013 if (EGifPutLine(gf, data, img->xsize) == GIF_ERROR) {
1015 i_push_error(0, "Could not save image data:");
1016 mm_log((1, "Error in EGifPutLine\n"));
1028 =item do_gce(GifFileType *gf, int index, i_gif_opts *opts, int want_trans, int trans_index)
1030 Internal. Writes the GIF graphics control extension, if necessary.
1032 Returns non-zero on success.
1036 static int do_gce(GifFileType *gf, int index, i_gif_opts *opts, int want_trans, int trans_index)
1038 unsigned char gce[4] = {0};
1042 gce[3] = trans_index;
1045 if (index < opts->delay_count) {
1046 gce[1] = opts->delays[index] % 256;
1047 gce[2] = opts->delays[index] / 256;
1050 if (index < opts->user_input_count) {
1051 if (opts->user_input_flags[index])
1055 if (index < opts->disposal_count) {
1056 gce[0] |= (opts->disposal[index] & 3) << 2;
1060 if (EGifPutExtension(gf, 0xF9, sizeof(gce), gce) == GIF_ERROR) {
1062 i_push_error(0, "Could not save GCE");
1069 =item do_ns_loop(GifFileType *gf, i_gif_opts *opts)
1071 Internal. Add the Netscape2.0 loop extension block, if requested.
1073 The code for this function is currently "#if 0"ed out since the giflib
1074 extension writing code currently doesn't seem to support writing
1075 application extension blocks.
1079 static int do_ns_loop(GifFileType *gf, i_gif_opts *opts)
1081 /* EGifPutExtension() doesn't appear to handle application
1082 extension blocks in any way
1083 Since giflib wraps the fd with a FILE * (and puts that in its
1084 private data), we can't do an end-run and write the data
1086 There's no open interface that takes a FILE * either, so we
1087 can't workaround it that way either.
1088 If giflib's callback interface wasn't broken by default, I'd
1089 force file writes to use callbacks, but it is broken by default.
1092 /* yes this was another attempt at supporting the loop extension */
1093 if (opts->loop_count) {
1094 unsigned char nsle[12] = "NETSCAPE2.0";
1095 unsigned char subblock[3];
1096 if (EGifPutExtension(gf, 0xFF, 11, nsle) == GIF_ERROR) {
1098 i_push_error(0, "writing loop extension");
1102 subblock[1] = opts->loop_count % 256;
1103 subblock[2] = opts->loop_count / 256;
1104 if (EGifPutExtension(gf, 0, 3, subblock) == GIF_ERROR) {
1106 i_push_error(0, "writing loop extention sub-block");
1109 if (EGifPutExtension(gf, 0, 0, subblock) == GIF_ERROR) {
1111 i_push_error(0, "writing loop extension terminator");
1120 =item make_gif_map(i_quantize *quant, i_gif_opts *opts, int want_trans)
1122 Create a giflib color map object from an Imager color map.
1127 static ColorMapObject *make_gif_map(i_quantize *quant, i_gif_opts *opts,
1129 GifColorType colors[256];
1131 int size = quant->mc_count;
1133 ColorMapObject *map;
1135 for (i = 0; i < quant->mc_count; ++i) {
1136 colors[i].Red = quant->mc_colors[i].rgb.r;
1137 colors[i].Green = quant->mc_colors[i].rgb.g;
1138 colors[i].Blue = quant->mc_colors[i].rgb.b;
1141 colors[size].Red = opts->tran_color.rgb.r;
1142 colors[size].Green = opts->tran_color.rgb.g;
1143 colors[size].Blue = opts->tran_color.rgb.b;
1147 while (map_size < size)
1149 /* giflib spews for 1 colour maps, reasonable, I suppose */
1153 map = MakeMapObject(map_size, colors);
1154 mm_log((1, "XXX map is at %p and colors at %p\n", map, map->Colors));
1157 i_push_error(0, "Could not create color map object");
1164 =item gif_set_version(i_quantize *quant, i_gif_opts *opts)
1166 We need to call EGifSetGifVersion() before opening the file - put that
1169 Unfortunately giflib 4.1.0 crashes when we use this. Internally
1170 giflib 4.1.0 has code:
1172 static char *GifVersionPrefix = GIF87_STAMP;
1174 and the code that sets the version internally does:
1176 strncpy(&GifVersionPrefix[3], Version, 3);
1178 which is very broken.
1180 Failing to set the correct GIF version doesn't seem to cause a problem
1186 static void gif_set_version(i_quantize *quant, i_gif_opts *opts) {
1187 /* the following crashed giflib
1188 the EGifSetGifVersion() is seriously borked in giflib
1189 it's less borked in the ungiflib beta, but we don't have a mechanism
1191 if (opts->delay_count
1192 || opts->user_input_count
1193 || opts->disposal_count
1195 || quant->transp != tr_none)
1196 EGifSetGifVersion("89a");
1198 EGifSetGifVersion("87a");
1203 in_palette(i_color *c, i_quantize *quant, int size) {
1206 for (i = 0; i < size; ++i) {
1207 if (c->channel[0] == quant->mc_colors[i].channel[0]
1208 && c->channel[1] == quant->mc_colors[i].channel[1]
1209 && c->channel[2] == quant->mc_colors[i].channel[2]) {
1218 =item has_common_palette(imgs, count, quant, want_trans)
1220 Tests if all the given images are paletted and have a common palette,
1221 if they do it builds that palette.
1223 A possible improvement might be to eliminate unused colors in the
1228 has_common_palette(i_img **imgs, int count, i_quantize *quant, int want_trans,
1230 int size = quant->mc_count;
1236 /* we try to build a common palette here, if we can manage that, then
1237 that's the palette we use */
1238 for (imgn = 0; imgn < count; ++imgn) {
1239 if (imgs[imgn]->type != i_palette_type)
1242 if (opts->eliminate_unused) {
1243 i_palidx *line = mymalloc(sizeof(i_palidx) * imgs[imgn]->xsize);
1245 memset(used, 0, sizeof(used));
1247 for (y = 0; y < imgs[imgn]->ysize; ++y) {
1248 i_gpal(imgs[imgn], 0, imgs[imgn]->xsize, y, line);
1249 for (x = 0; x < imgs[imgn]->xsize; ++x)
1256 /* assume all are in use */
1257 memset(used, 1, sizeof(used));
1260 for (i = 0; i < i_colorcount(imgs[imgn]); ++i) {
1263 i_getcolors(imgs[imgn], i, &c, 1);
1265 if (in_palette(&c, quant, size) < 0) {
1266 if (size < quant->mc_size) {
1267 quant->mc_colors[size++] = c;
1270 /* oops, too many colors */
1278 quant->mc_count = size;
1284 quant_paletted(i_quantize *quant, i_img *img) {
1285 i_palidx *data = mymalloc(sizeof(i_palidx) * img->xsize * img->ysize);
1287 i_palidx trans[256];
1291 /* build a translation table */
1292 for (i = 0; i < i_colorcount(img); ++i) {
1294 i_getcolors(img, i, &c, 1);
1295 trans[i] = in_palette(&c, quant, quant->mc_count);
1298 for (y = 0; y < img->ysize; ++y) {
1299 i_gpal(img, 0, img->xsize, y, data+img->xsize * y);
1300 for (x = 0; x < img->xsize; ++x) {
1310 =item i_writegif_low(i_quantize *quant, GifFileType *gf, i_img **imgs, int count, i_gif_opts *opts)
1312 Internal. Low-level function that does the high-level GIF processing
1315 Returns non-zero on success.
1321 i_writegif_low(i_quantize *quant, GifFileType *gf, i_img **imgs, int count,
1323 unsigned char *result;
1325 ColorMapObject *map;
1326 int scrw = 0, scrh = 0;
1327 int imgn, orig_count, orig_size;
1331 mm_log((1, "i_writegif_low(quant %p, gf %p, imgs %p, count %d, opts %p)\n",
1332 quant, gf, imgs, count, opts));
1334 /**((char *)0) = 1;*/
1335 /* sanity is nice */
1336 if (quant->mc_size > 256)
1337 quant->mc_size = 256;
1338 if (quant->mc_count > quant->mc_size)
1339 quant->mc_count = quant->mc_size;
1341 for (imgn = 0; imgn < count; ++imgn) {
1342 if (imgn < opts->position_count) {
1343 if (imgs[imgn]->xsize + opts->positions[imgn].x > scrw)
1344 scrw = imgs[imgn]->xsize + opts->positions[imgn].x;
1345 if (imgs[imgn]->ysize + opts->positions[imgn].y > scrw)
1346 scrh = imgs[imgn]->ysize + opts->positions[imgn].y;
1349 if (imgs[imgn]->xsize > scrw)
1350 scrw = imgs[imgn]->xsize;
1351 if (imgs[imgn]->ysize > scrh)
1352 scrh = imgs[imgn]->ysize;
1357 i_push_error(0, "No images provided to write");
1358 return 0; /* what are you smoking? */
1361 orig_count = quant->mc_count;
1362 orig_size = quant->mc_size;
1364 if (opts->each_palette) {
1365 int want_trans = quant->transp != tr_none
1366 && imgs[0]->channels == 4;
1368 /* if the caller gives us too many colours we can't do transparency */
1369 if (want_trans && quant->mc_count == 256)
1371 /* if they want transparency but give us a big size, make it smaller
1372 to give room for a transparency colour */
1373 if (want_trans && quant->mc_size == 256)
1376 /* we always generate a global palette - this lets systems with a
1377 broken giflib work */
1378 if (has_common_palette(imgs, 1, quant, want_trans, opts)) {
1379 result = quant_paletted(quant, imgs[0]);
1382 quant_makemap(quant, imgs, 1);
1383 result = quant_translate(quant, imgs[0]);
1386 trans_index = quant->mc_count;
1387 quant_transparent(quant, result, imgs[0], trans_index);
1390 if ((map = make_gif_map(quant, opts, want_trans)) == NULL) {
1393 mm_log((1, "Error in MakeMapObject."));
1398 while (quant->mc_size > (1 << color_bits))
1401 if (EGifPutScreenDesc(gf, scrw, scrh, color_bits, 0, map) == GIF_ERROR) {
1403 i_push_error(0, "Could not save screen descriptor");
1407 mm_log((1, "Error in EGifPutScreenDesc."));
1412 if (!do_ns_loop(gf, opts))
1415 if (!do_gce(gf, 0, opts, want_trans, trans_index)) {
1420 if (opts->position_count) {
1421 posx = opts->positions[0].x;
1422 posy = opts->positions[0].y;
1426 if (EGifPutImageDesc(gf, posx, posy, imgs[0]->xsize, imgs[0]->ysize,
1427 opts->interlace, NULL) == GIF_ERROR) {
1429 i_push_error(0, "Could not save image descriptor");
1431 mm_log((1, "Error in EGifPutImageDesc."));
1434 if (!do_write(gf, opts, imgs[0], result)) {
1439 for (imgn = 1; imgn < count; ++imgn) {
1440 quant->mc_count = orig_count;
1441 quant->mc_size = orig_size;
1442 want_trans = quant->transp != tr_none
1443 && imgs[0]->channels == 4;
1444 /* if the caller gives us too many colours we can't do transparency */
1445 if (want_trans && quant->mc_count == 256)
1447 /* if they want transparency but give us a big size, make it smaller
1448 to give room for a transparency colour */
1449 if (want_trans && quant->mc_size == 256)
1452 if (has_common_palette(imgs+imgn, 1, quant, want_trans, opts)) {
1453 result = quant_paletted(quant, imgs[imgn]);
1456 quant_makemap(quant, imgs+imgn, 1);
1457 result = quant_translate(quant, imgs[imgn]);
1460 quant_transparent(quant, result, imgs[imgn], quant->mc_count);
1461 trans_index = quant->mc_count;
1464 if (!do_gce(gf, imgn, opts, want_trans, quant->mc_count)) {
1469 if ((map = make_gif_map(quant, opts, want_trans)) == NULL) {
1472 mm_log((1, "Error in MakeMapObject."));
1475 if (imgn < opts->position_count) {
1476 posx = opts->positions[imgn].x;
1477 posy = opts->positions[imgn].y;
1481 if (EGifPutImageDesc(gf, posx, posy, imgs[imgn]->xsize,
1482 imgs[imgn]->ysize, opts->interlace,
1483 map) == GIF_ERROR) {
1485 i_push_error(0, "Could not save image descriptor");
1489 mm_log((1, "Error in EGifPutImageDesc."));
1494 if (!do_write(gf, opts, imgs[imgn], result)) {
1504 int do_quant_paletted = 0;
1506 /* get a palette entry for the transparency iff we have an image
1507 with an alpha channel */
1509 for (imgn = 0; imgn < count; ++imgn) {
1510 if (imgs[imgn]->channels == 4) {
1515 want_trans = want_trans && quant->transp != tr_none
1516 && quant->mc_count < 256;
1517 if (want_trans && quant->mc_size == 256)
1520 /* handle the first image separately - since we allow giflib
1521 conversion and giflib doesn't give us a separate function to build
1524 /* produce a colour map */
1525 if (has_common_palette(imgs, count, quant, want_trans, opts)) {
1526 result = quant_paletted(quant, imgs[0]);
1527 ++do_quant_paletted;
1530 quant_makemap(quant, imgs, count);
1531 result = quant_translate(quant, imgs[0]);
1534 if ((map = make_gif_map(quant, opts, want_trans)) == NULL) {
1537 mm_log((1, "Error in MakeMapObject"));
1541 while (quant->mc_count > (1 << color_bits))
1544 if (EGifPutScreenDesc(gf, scrw, scrh, color_bits, 0, map) == GIF_ERROR) {
1546 i_push_error(0, "Could not save screen descriptor");
1550 mm_log((1, "Error in EGifPutScreenDesc."));
1555 if (!do_ns_loop(gf, opts))
1558 if (!do_gce(gf, 0, opts, want_trans, quant->mc_count)) {
1563 if (opts->position_count) {
1564 posx = opts->positions[0].x;
1565 posy = opts->positions[0].y;
1569 if (EGifPutImageDesc(gf, posx, posy, imgs[0]->xsize, imgs[0]->ysize,
1570 opts->interlace, NULL) == GIF_ERROR) {
1572 i_push_error(0, "Could not save image descriptor");
1574 mm_log((1, "Error in EGifPutImageDesc."));
1577 if (want_trans && imgs[0]->channels == 4)
1578 quant_transparent(quant, result, imgs[0], quant->mc_count);
1580 if (!do_write(gf, opts, imgs[0], result)) {
1587 for (imgn = 1; imgn < count; ++imgn) {
1589 if (do_quant_paletted)
1590 result = quant_paletted(quant, imgs[imgn]);
1592 result = quant_translate(quant, imgs[imgn]);
1593 local_trans = want_trans && imgs[imgn]->channels == 4;
1595 quant_transparent(quant, result, imgs[imgn], quant->mc_count);
1596 if (!do_gce(gf, imgn, opts, local_trans, quant->mc_count)) {
1601 if (imgn < opts->position_count) {
1602 posx = opts->positions[imgn].x;
1603 posy = opts->positions[imgn].y;
1607 if (EGifPutImageDesc(gf, posx, posy,
1608 imgs[imgn]->xsize, imgs[imgn]->ysize,
1609 opts->interlace, NULL) == GIF_ERROR) {
1611 i_push_error(0, "Could not save image descriptor");
1614 mm_log((1, "Error in EGifPutImageDesc."));
1617 if (!do_write(gf, opts, imgs[imgn], result)) {
1625 if (EGifCloseFile(gf) == GIF_ERROR) {
1627 i_push_error(0, "Could not close GIF file");
1628 mm_log((1, "Error in EGifCloseFile\n"));
1636 =item i_writegif_gen(i_quantize *quant, int fd, i_img **imgs, int count, i_gif_opts *opts)
1638 General high-level function to write a GIF to a file.
1640 Writes the GIF images to the specified file handle using the options
1641 in quant and opts. See L<image.h/i_quantize> and
1642 L<image.h/i_gif_opts>.
1644 Returns non-zero on success.
1650 i_writegif_gen(i_quantize *quant, int fd, i_img **imgs, int count,
1655 mm_log((1, "i_writegif_gen(quant %p, fd %d, imgs %p, count %d, opts %p)\n",
1656 quant, fd, imgs, count, opts));
1658 gif_set_version(quant, opts);
1660 if ((gf = EGifOpenFileHandle(fd)) == NULL) {
1662 i_push_error(0, "Cannot create GIF file object");
1663 mm_log((1, "Error in EGifOpenFileHandle, unable to write image.\n"));
1667 return i_writegif_low(quant, gf, imgs, count, opts);
1670 #if IM_GIFMAJOR >= 4
1673 =item gif_writer_callback(GifFileType *gf, const GifByteType *data, int size)
1675 Internal. Wrapper for the user write callback function.
1680 static int gif_writer_callback(GifFileType *gf, const GifByteType *data, int size)
1682 i_gen_write_data *gwd = (i_gen_write_data *)gf->UserData;
1684 return i_gen_writer(gwd, (char*)data, size) ? size : 0;
1690 =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)
1692 General high-level function to write a GIF using callbacks to send
1695 Returns non-zero on success.
1701 i_writegif_callback(i_quantize *quant, i_write_callback_t cb, char *userdata,
1702 int maxlength, i_img **imgs, int count, i_gif_opts *opts)
1704 #if IM_GIFMAJOR >= 4
1706 i_gen_write_data *gwd = i_gen_write_data_new(cb, userdata, maxlength);
1707 /* giflib declares this incorrectly as EgifOpen */
1708 extern GifFileType *EGifOpen(void *userData, OutputFunc writeFunc);
1713 mm_log((1, "i_writegif_callback(quant %p, i_write_callback_t %p, userdata $p, maxlength %d, imgs %p, count %d, opts %p)\n",
1714 quant, cb, userdata, maxlength, imgs, count, opts));
1716 if ((gf = EGifOpen(gwd, &gif_writer_callback)) == NULL) {
1718 i_push_error(0, "Cannot create GIF file object");
1719 mm_log((1, "Error in EGifOpenFileHandle, unable to write image.\n"));
1720 free_gen_write_data(gwd, 0);
1724 result = i_writegif_low(quant, gf, imgs, count, opts);
1725 return free_gen_write_data(gwd, result);
1732 =item gif_error_msg(int code)
1734 Grabs the most recent giflib error code from GifLastError() and
1735 returns a string that describes that error.
1737 The returned pointer points to a static buffer, either from a literal
1738 C string or a static buffer.
1742 static char const *gif_error_msg(int code) {
1743 static char msg[80];
1746 case E_GIF_ERR_OPEN_FAILED: /* should not see this */
1747 return "Failed to open given file";
1749 case E_GIF_ERR_WRITE_FAILED:
1750 return "Write failed";
1752 case E_GIF_ERR_HAS_SCRN_DSCR: /* should not see this */
1753 return "Screen descriptor already passed to giflib";
1755 case E_GIF_ERR_HAS_IMAG_DSCR: /* should not see this */
1756 return "Image descriptor already passed to giflib";
1758 case E_GIF_ERR_NO_COLOR_MAP: /* should not see this */
1759 return "Neither global nor local color map set";
1761 case E_GIF_ERR_DATA_TOO_BIG: /* should not see this */
1762 return "Too much pixel data passed to giflib";
1764 case E_GIF_ERR_NOT_ENOUGH_MEM:
1765 return "Out of memory";
1767 case E_GIF_ERR_DISK_IS_FULL:
1768 return "Disk is full";
1770 case E_GIF_ERR_CLOSE_FAILED: /* should not see this */
1771 return "File close failed";
1773 case E_GIF_ERR_NOT_WRITEABLE: /* should not see this */
1774 return "File not writable";
1776 case D_GIF_ERR_OPEN_FAILED:
1777 return "Failed to open file";
1779 case D_GIF_ERR_READ_FAILED:
1780 return "Failed to read from file";
1782 case D_GIF_ERR_NOT_GIF_FILE:
1783 return "File is not a GIF file";
1785 case D_GIF_ERR_NO_SCRN_DSCR:
1786 return "No screen descriptor detected - invalid file";
1788 case D_GIF_ERR_NO_IMAG_DSCR:
1789 return "No image descriptor detected - invalid file";
1791 case D_GIF_ERR_NO_COLOR_MAP:
1792 return "No global or local color map found";
1794 case D_GIF_ERR_WRONG_RECORD:
1795 return "Wrong record type detected - invalid file?";
1797 case D_GIF_ERR_DATA_TOO_BIG:
1798 return "Data in file too big for image";
1800 case D_GIF_ERR_NOT_ENOUGH_MEM:
1801 return "Out of memory";
1803 case D_GIF_ERR_CLOSE_FAILED:
1804 return "Close failed";
1806 case D_GIF_ERR_NOT_READABLE:
1807 return "File not opened for read";
1809 case D_GIF_ERR_IMAGE_DEFECT:
1810 return "Defective image";
1812 case D_GIF_ERR_EOF_TOO_SOON:
1813 return "Unexpected EOF - invalid file";
1816 sprintf(msg, "Unknown giflib error code %d", code);
1822 =item gif_push_error()
1824 Utility function that takes the current GIF error code, converts it to
1825 an error message and pushes it on the error stack.
1830 static void gif_push_error(void) {
1831 int code = GifLastError(); /* clears saved error */
1833 i_push_error(code, gif_error_msg(code));
1839 The Netscape loop extension isn't implemented. Giflib's extension
1840 writing code doesn't seem to support writing named extensions in this
1843 A bug in giflib is tickled by the i_writegif_callback(). This isn't a
1844 problem on ungiflib, but causes a SEGV on giflib. A patch is provided
1847 The GIF file tag (GIF87a vs GIF89a) currently isn't set. Using the
1848 supplied interface in giflib 4.1.0 causes a SEGV in
1849 EGifSetGifVersion(). See L<gif_set_version> for an explanation.
1853 Arnar M. Hrafnkelsson, addi@umich.edu