7 gif.c - read and write gif files for Imager
16 int max_colours; // number of bits per colour
17 int pixdev; // how much noise to add
18 i_color fixed[N]; // fixed palette entries
19 int fixedlen; // number of fixed colours
20 int success; // non-zero on success
21 char *data; // a GIF file in memory
22 int length; // how big data is
23 int reader(char *, char *, int, int);
24 int writer(char *, char *, int);
25 char *userdata; // user's data, whatever it is
29 img = i_readgif(fd, &colour_table, &colours);
30 success = i_writegif(img, fd, max_colours, pixdev, fixedlen, fixed);
31 success = i_writegifmc(img, fd, max_colours);
32 img = i_readgif_scalar(data, length, &colour_table, &colours);
33 img = i_readgif_callback(cb, userdata, &colour_table, &colours);
34 success = i_writegif_gen(&quant, fd, imgs, count, &opts);
35 success = i_writegif_callback(&quant, writer, userdata, maxlength,
40 This source file provides the C level interface to reading and writing
43 This has been tested with giflib 3 and 4, though you lose the callback
44 functionality with giflib3.
53 static char const *gif_error_msg(int code);
54 static void gif_push_error();
61 Internal. A structure passed to the reader function used for reading
64 Used with giflib 4 and later.
69 struct gif_scalar_info {
76 =item my_gif_inputfunc(GifFileType *gft, GifByteType *buf, int length)
78 Internal. The reader callback passed to giflib.
80 Used with giflib 4 and later.
86 my_gif_inputfunc(GifFileType* gft, GifByteType *buf,int length) {
87 struct gif_scalar_info *gsi=(struct gif_scalar_info *)gft->UserData;
88 /* fprintf(stderr,"my_gif_inputfunc: length=%d cpos=%d tlength=%d\n",length,gsi->cpos,gsi->length); */
90 if (gsi->cpos == gsi->length) return 0;
91 if (gsi->cpos+length > gsi->length) length=gsi->length-gsi->cpos; /* Don't read too much */
92 memcpy(buf,gsi->data+gsi->cpos,length);
100 This file needs a complete rewrite
102 This file needs a complete rewrite
104 Maybe not anymore, though reading still needs to support reading
105 all those gif properties.
108 /* Make some variables global, so we could access them faster: */
114 InterlacedOffset[] = { 0, 4, 2, 1 }, /* The way Interlaced image should. */
115 InterlacedJumps[] = { 8, 8, 4, 2 }; /* be read - offsets and jumps... */
116 static ColorMapObject *ColorMap;
119 =item i_readgif_low(GifFileType *GifFile, int **colour_table, int *colours)
121 Internal. Low-level function for reading a GIF file. The caller must
122 create the appropriate GifFileType object and pass it in.
127 i_readgif_low(GifFileType *GifFile, int **colour_table, int *colours) {
129 int i, j, Size, Row, Col, Width, Height, ExtCode, Count, x;
130 GifRecordType RecordType;
131 GifByteType *Extension;
134 static GifColorType *ColorMapEntry;
137 /* unsigned char *Buffer, *BufferP; */
139 mm_log((1,"i_readgif_low(GifFile %p, colour_table %p, colours %p)\n", GifFile, colour_table, colours));
141 BackGround = GifFile->SBackGroundColor;
142 ColorMap = (GifFile->Image.ColorMap ? GifFile->Image.ColorMap : GifFile->SColorMap);
143 ColorMapSize = ColorMap->ColorCount;
145 /* **************************************** */
146 if(colour_table != NULL) {
148 *colour_table=mymalloc(sizeof(int *) * ColorMapSize * 3);
149 if(*colour_table == NULL)
150 m_fatal(0,"Failed to allocate memory for GIF colour table, aborted.");
152 memset(*colour_table, 0, sizeof(int *) * ColorMapSize * 3);
154 for(q=0; q<ColorMapSize; q++) {
155 ColorMapEntry = &ColorMap->Colors[q];
156 (*colour_table)[q*3 + 0]=ColorMapEntry->Red;
157 (*colour_table)[q*3 + 1]=ColorMapEntry->Green;
158 (*colour_table)[q*3 + 2]=ColorMapEntry->Blue;
162 if(colours != NULL) {
163 *colours = ColorMapSize;
166 /* **************************************** */
167 im=i_img_empty_ch(NULL,GifFile->SWidth,GifFile->SHeight,3);
169 Size = GifFile->SWidth * sizeof(GifPixelType);
171 if ((GifRow = (GifRowType) mymalloc(Size)) == NULL)
172 m_fatal(0,"Failed to allocate memory required, aborted."); /* First row. */
174 for (i = 0; i < GifFile->SWidth; i++) GifRow[i] = GifFile->SBackGroundColor;
176 /* Scan the content of the GIF file and load the image(s) in: */
178 if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR) {
180 i_push_error(0, "Unable to get record type");
184 DGifCloseFile(GifFile);
188 switch (RecordType) {
189 case IMAGE_DESC_RECORD_TYPE:
190 if (DGifGetImageDesc(GifFile) == GIF_ERROR) {
192 i_push_error(0, "Unable to get image descriptor");
196 DGifCloseFile(GifFile);
199 Row = GifFile->Image.Top; /* Image Position relative to Screen. */
200 Col = GifFile->Image.Left;
201 Width = GifFile->Image.Width;
202 Height = GifFile->Image.Height;
204 mm_log((1,"i_readgif: Image %d at (%d, %d) [%dx%d]: \n",ImageNum, Col, Row, Width, Height));
206 if (GifFile->Image.Left + GifFile->Image.Width > GifFile->SWidth ||
207 GifFile->Image.Top + GifFile->Image.Height > GifFile->SHeight) {
208 i_push_errorf(0, "Image %d is not confined to screen dimension, aborted.\n",ImageNum);
212 DGifCloseFile(GifFile);
215 if (GifFile->Image.Interlace) {
217 for (Count = i = 0; i < 4; i++) for (j = Row + InterlacedOffset[i]; j < Row + Height; j += InterlacedJumps[i]) {
219 if (DGifGetLine(GifFile, &GifRow[Col], Width) == GIF_ERROR) {
221 i_push_error(0, "Reading GIF line");
225 DGifCloseFile(GifFile);
229 for (x = 0; x < GifFile->SWidth; x++) {
230 ColorMapEntry = &ColorMap->Colors[GifRow[x]];
231 col.rgb.r = ColorMapEntry->Red;
232 col.rgb.g = ColorMapEntry->Green;
233 col.rgb.b = ColorMapEntry->Blue;
240 for (i = 0; i < Height; i++) {
241 if (DGifGetLine(GifFile, &GifRow[Col], Width) == GIF_ERROR) {
243 i_push_error(0, "Reading GIF line");
247 DGifCloseFile(GifFile);
251 for (x = 0; x < GifFile->SWidth; x++) {
252 ColorMapEntry = &ColorMap->Colors[GifRow[x]];
253 col.rgb.r = ColorMapEntry->Red;
254 col.rgb.g = ColorMapEntry->Green;
255 col.rgb.b = ColorMapEntry->Blue;
256 i_ppix(im,x,Row,&col);
262 case EXTENSION_RECORD_TYPE:
263 /* Skip any extension blocks in file: */
264 if (DGifGetExtension(GifFile, &ExtCode, &Extension) == GIF_ERROR) {
266 i_push_error(0, "Reading extension record");
270 DGifCloseFile(GifFile);
273 while (Extension != NULL) {
274 if (DGifGetExtensionNext(GifFile, &Extension) == GIF_ERROR) {
276 i_push_error(0, "reading next block of extension");
280 DGifCloseFile(GifFile);
285 case TERMINATE_RECORD_TYPE:
287 default: /* Should be traps by DGifGetRecordType. */
290 } while (RecordType != TERMINATE_RECORD_TYPE);
294 if (DGifCloseFile(GifFile) == GIF_ERROR) {
296 i_push_error(0, "Closing GIF file object");
306 =item i_readgif(int fd, int **colour_table, int *colours)
308 Reads in a GIF file from a file handle and converts it to an Imager
311 Returns the palette for the object in colour_table for colours
314 Returns NULL on failure.
320 i_readgif(int fd, int **colour_table, int *colours) {
321 GifFileType *GifFile;
325 mm_log((1,"i_readgif(fd %d, colour_table %p, colours %p)\n", fd, colour_table, colours));
327 if ((GifFile = DGifOpenFileHandle(fd)) == NULL) {
329 i_push_error(0, "Cannot create giflib file object");
330 mm_log((1,"i_readgif: Unable to open file\n"));
334 return i_readgif_low(GifFile, colour_table, colours);
338 =item i_writegif(i_img *im, int fd, int max_colors, int pixdev, int fixedlen, i_color fixed[])
340 Write I<img> to the file handle I<fd>. The resulting GIF will use a
341 maximum of 1<<I<max_colours> colours, with the first I<fixedlen>
342 colours taken from I<fixed>.
344 Returns non-zero on success.
350 i_writegif(i_img *im, int fd, int max_colors, int pixdev, int fixedlen, i_color fixed[])
356 memset(&quant, 0, sizeof(quant));
357 memset(&opts, 0, sizeof(opts));
358 quant.make_colors = mc_addi;
359 quant.mc_colors = colors;
360 quant.mc_size = 1<<max_colors;
361 quant.mc_count = fixedlen;
362 memcpy(colors, fixed, fixedlen * sizeof(i_color));
363 quant.translate = pt_perturb;
364 quant.perturb = pixdev;
365 return i_writegif_gen(&quant, fd, &im, 1, &opts);
369 =item i_writegifmc(i_img *im, int fd, int max_colors)
371 Write I<img> to the file handle I<fd>. The resulting GIF will use a
372 maximum of 1<<I<max_colours> colours.
374 Returns non-zero on success.
380 i_writegifmc(i_img *im, int fd, int max_colors) {
385 memset(&quant, 0, sizeof(quant));
386 memset(&opts, 0, sizeof(opts));
387 quant.make_colors = mc_none; /* ignored for pt_giflib */
388 quant.mc_colors = colors;
389 quant.mc_size = 1 << max_colors;
391 quant.translate = pt_giflib;
392 return i_writegif_gen(&quant, fd, &im, 1, &opts);
398 i_writegifex(i_img *im, int fd) {
404 /* I don't think this works
405 note that RedBuffer is never allocated - TC
409 i_writegifex(i_img *im,int fd) {
410 int colors, xsize, ysize, channels;
411 int x,y,ColorMapSize;
416 GifByteType *RedBuffer = NULL, *GreenBuffer = NULL, *BlueBuffer = NULL,*OutputBuffer = NULL;
417 ColorMapObject *OutputColorMap = NULL;
418 GifFileType *GifFile;
423 mm_log((1,"i_writegif(0x%x,fd %d)\n",im,fd));
425 if (!(im->channels==1 || im->channels==3)) { fprintf(stderr,"Unable to write gif, improper colorspace.\n"); exit(3); }
429 channels=im->channels;
435 for(x=0;x<xsize;x++) for(y=0;y<ysize;y++) {
437 colors+=octt_add(ct,val.rgb.r,val.rgb.g,val.rgb.b);
438 /* if (colors > maxc) { octt_delete(ct); }
439 We'll just bite the bullet */
442 ColorMapSize = (colors > 256) ? 256 : colors;
444 Size = ((long) im->xsize) * im->ysize * sizeof(GifByteType);
446 if ((OutputColorMap = MakeMapObject(ColorMapSize, NULL)) == NULL)
447 m_fatal(0,"Failed to allocate memory for Output colormap.");
448 if ((OutputBuffer = (GifByteType *) mymalloc(im->xsize * im->ysize * sizeof(GifByteType))) == NULL)
449 m_fatal(0,"Failed to allocate memory for output buffer.");
451 if (QuantizeBuffer(im->xsize, im->ysize, &ColorMapSize, RedBuffer, GreenBuffer, BlueBuffer,
452 OutputBuffer, OutputColorMap->Colors) == GIF_ERROR) {
453 mm_log((1,"Error in QuantizeBuffer, unable to write image.\n"));
459 if (im->channels == 3) { myfree(GreenBuffer); myfree(BlueBuffer); }
461 if ((GifFile = EGifOpenFileHandle(fd)) == NULL) {
462 mm_log((1,"Error in EGifOpenFileHandle, unable to write image.\n"));
466 if (EGifPutScreenDesc(GifFile,im->xsize, im->ysize, colors, 0,OutputColorMap) == GIF_ERROR ||
467 EGifPutImageDesc(GifFile,0, 0, im->xsize, im->ysize, FALSE, NULL) == GIF_ERROR) {
468 mm_log((1,"Error in EGifOpenFileHandle, unable to write image.\n"));
469 if (GifFile != NULL) EGifCloseFile(GifFile);
475 for (y = 0; y < im->ysize; y++) {
476 if (EGifPutLine(GifFile, Ptr, im->xsize) == GIF_ERROR) {
477 mm_log((1,"Error in EGifOpenFileHandle, unable to write image.\n"));
478 if (GifFile != NULL) EGifCloseFile(GifFile);
485 if (EGifCloseFile(GifFile) == GIF_ERROR) {
486 mm_log((1,"Error in EGifCloseFile, unable to write image.\n"));
495 =item i_readgif_scalar(char *data, int length, int **colour_table, int *colours)
497 Reads a GIF file from an in memory copy of the file. This can be used
498 if you get the 'file' from some source other than an actual file (or
499 some other file handle).
501 This function is only available with giflib 4 and higher.
506 i_readgif_scalar(char *data, int length, int **colour_table, int *colours) {
508 GifFileType *GifFile;
509 struct gif_scalar_info gsi;
517 mm_log((1,"i_readgif_scalar(char* data, int length, colour_table %p, colours %p)\n", data, length, colour_table, colours));
518 if ((GifFile = DGifOpen( (void*) &gsi, my_gif_inputfunc )) == NULL) {
520 i_push_error(0, "Cannot create giflib callback object");
521 mm_log((1,"i_readgif_scalar: Unable to open scalar datasource.\n"));
525 return i_readgif_low(GifFile, colour_table, colours);
534 =item gif_read_callback(GifFileType *gft, GifByteType *buf, int length)
536 Internal. The reader callback wrapper passed to giflib.
538 This function is only used with giflib 4 and higher.
544 gif_read_callback(GifFileType *gft, GifByteType *buf, int length) {
545 return i_gen_reader((i_gen_read_data *)gft->UserData, buf, length);
552 =item i_readgif_callback(i_read_callback_t cb, char *userdata, int **colour_table, int *colours)
554 Read a GIF file into an Imager RGB file, the data of the GIF file is
555 retreived by callin the user supplied callback function.
557 This function is only used with giflib 4 and higher.
563 i_readgif_callback(i_read_callback_t cb, char *userdata, int **colour_table, int *colours) {
565 GifFileType *GifFile;
568 i_gen_read_data *gci = i_gen_read_data_new(cb, userdata);
572 mm_log((1,"i_readgif_callback(callback %p, userdata %p, colour_table %p, colours %p)\n", cb, userdata, colour_table, colours));
573 if ((GifFile = DGifOpen( (void*) gci, gif_read_callback )) == NULL) {
575 i_push_error(0, "Cannot create giflib callback object");
576 mm_log((1,"i_readgif_callback: Unable to open callback datasource.\n"));
581 result = i_readgif_low(GifFile, colour_table, colours);
582 free_gen_read_data(gci);
591 =item do_write(GifFileType *gf, i_gif_opts *opts, i_img *img, i_palidx *data)
593 Internal. Low level image write function. Writes in interlace if
594 that was requested in the GIF options.
596 Returns non-zero on success.
601 do_write(GifFileType *gf, i_gif_opts *opts, i_img *img, i_palidx *data) {
602 if (opts->interlace) {
604 for (i = 0; i < 4; ++i) {
605 for (j = InterlacedOffset[i]; j < img->ysize; j += InterlacedJumps[i]) {
606 if (EGifPutLine(gf, data+j*img->xsize, img->xsize) == GIF_ERROR) {
608 i_push_error(0, "Could not save image data:");
609 mm_log((1, "Error in EGifPutLine\n"));
618 for (y = 0; y < img->ysize; ++y) {
619 if (EGifPutLine(gf, data, img->xsize) == GIF_ERROR) {
621 i_push_error(0, "Could not save image data:");
622 mm_log((1, "Error in EGifPutLine\n"));
634 =item do_gce(GifFileType *gf, int index, i_gif_opts *opts, int want_trans, int trans_index)
636 Internal. Writes the GIF graphics control extension, if necessary.
638 Returns non-zero on success.
642 static int do_gce(GifFileType *gf, int index, i_gif_opts *opts, int want_trans, int trans_index)
644 unsigned char gce[4] = {0};
648 gce[3] = trans_index;
651 if (index < opts->delay_count) {
652 gce[1] = opts->delays[index] % 256;
653 gce[2] = opts->delays[index] / 256;
656 if (index < opts->user_input_count) {
657 if (opts->user_input_flags[index])
661 if (index < opts->disposal_count) {
662 gce[0] |= (opts->disposal[index] & 3) << 2;
666 if (EGifPutExtension(gf, 0xF9, sizeof(gce), gce) == GIF_ERROR) {
668 i_push_error(0, "Could not save GCE");
675 =item do_ns_loop(GifFileType *gf, i_gif_opts *opts)
677 Internal. Add the Netscape2.0 loop extension block, if requested.
679 The code for this function is currently "#if 0"ed out since the giflib
680 extension writing code currently doesn't seem to support writing
681 application extension blocks.
685 static int do_ns_loop(GifFileType *gf, i_gif_opts *opts)
688 /* EGifPutExtension() doesn't appear to handle application
689 extension blocks in any way
690 Since giflib wraps the fd with a FILE * (and puts that in its
691 private data), we can't do an end-run and write the data
693 There's no open interface that takes a FILE * either, so we
694 can't workaround it that way either.
695 If giflib's callback interface wasn't broken by default, I'd
696 force file writes to use callbacks, but it is broken by default.
698 if (opts->loop_count) {
699 unsigned char nsle[15] = "NETSCAPE2.0";
702 nsle[13] = opts->loop_count % 256;
703 nsle[14] = opts->loop_count / 256;
704 return EGifPutExtension(gf, 0xFF, sizeof(nsle), nsle) != GIF_ERROR;
711 =item make_gif_map(i_quantize *quant, i_gif_opts *opts, int want_trans)
713 Create a giflib color map object from an Imager color map.
718 static ColorMapObject *make_gif_map(i_quantize *quant, i_gif_opts *opts,
720 GifColorType colors[256];
722 int size = quant->mc_count;
726 for (i = 0; i < quant->mc_count; ++i) {
727 colors[i].Red = quant->mc_colors[i].rgb.r;
728 colors[i].Green = quant->mc_colors[i].rgb.g;
729 colors[i].Blue = quant->mc_colors[i].rgb.b;
732 colors[size].Red = opts->tran_color.rgb.r;
733 colors[size].Green = opts->tran_color.rgb.g;
734 colors[size].Blue = opts->tran_color.rgb.b;
738 while (map_size < size)
740 /* giflib spews for 1 colour maps, reasonable, I suppose */
743 map = MakeMapObject(map_size, colors);
746 i_push_error(0, "Could not create color map object");
753 =item gif_set_version(i_quantize *quant, i_gif_opts *opts)
755 We need to call EGifSetGifVersion() before opening the file - put that
758 Unfortunately giflib 4.1.0 crashes when we use this. Internally
759 giflib 4.1.0 has code:
761 static char *GifVersionPrefix = GIF87_STAMP;
763 and the code that sets the version internally does:
765 strncpy(&GifVersionPrefix[3], Version, 3);
767 which is very broken.
769 Failing to set the correct GIF version doesn't seem to cause a problem
775 static void gif_set_version(i_quantize *quant, i_gif_opts *opts) {
776 /* the following crashed giflib
777 the EGifSetGifVersion() is seriously borked in giflib
778 it's less borked in the ungiflib beta, but we don't have a mechanism
780 if (opts->delay_count
781 || opts->user_input_count
782 || opts->disposal_count
784 || quant->transp != tr_none)
785 EGifSetGifVersion("89a");
787 EGifSetGifVersion("87a");
792 =item i_writegif_low(i_quantize *quant, GifFileType *gf, i_img **imgs, int count, i_gif_opts *opts)
794 Internal. Low-level function that does the high-level GIF processing
797 Returns non-zero on success.
803 i_writegif_low(i_quantize *quant, GifFileType *gf, i_img **imgs, int count,
805 unsigned char *result;
808 int scrw = 0, scrh = 0;
809 int imgn, orig_count, orig_size;
812 mm_log((1, "i_writegif_low(quant %p, gf %p, imgs %p, count %d, opts %p)\n",
813 quant, gf, imgs, count, opts));
815 /**((char *)0) = 1;*/
817 if (quant->mc_size > 256)
818 quant->mc_size = 256;
819 if (quant->mc_count > quant->mc_size)
820 quant->mc_count = quant->mc_size;
822 for (imgn = 0; imgn < count; ++imgn) {
823 if (imgn < opts->position_count) {
824 if (imgs[imgn]->xsize + opts->positions[imgn].x > scrw)
825 scrw = imgs[imgn]->xsize + opts->positions[imgn].x;
826 if (imgs[imgn]->ysize + opts->positions[imgn].y > scrw)
827 scrh = imgs[imgn]->ysize + opts->positions[imgn].y;
830 if (imgs[imgn]->xsize > scrw)
831 scrw = imgs[imgn]->xsize;
832 if (imgs[imgn]->ysize > scrh)
833 scrh = imgs[imgn]->ysize;
838 i_push_error(0, "No images provided to write");
839 return 0; /* what are you smoking? */
842 orig_count = quant->mc_count;
843 orig_size = quant->mc_size;
845 if (opts->each_palette) {
846 int want_trans = quant->transp != tr_none
847 && imgs[0]->channels == 4;
849 /* if the caller gives us too many colours we can't do transparency */
850 if (want_trans && quant->mc_count == 256)
852 /* if they want transparency but give us a big size, make it smaller
853 to give room for a transparency colour */
854 if (want_trans && quant->mc_size == 256)
857 /* we always generate a global palette - this lets systems with a
858 broken giflib work */
859 quant_makemap(quant, imgs, 1);
860 result = quant_translate(quant, imgs[0]);
863 quant_transparent(quant, result, imgs[0], quant->mc_count);
865 if ((map = make_gif_map(quant, opts, want_trans)) == NULL) {
868 mm_log((1, "Error in MakeMapObject."));
873 while (quant->mc_size > (1 << color_bits))
876 if (EGifPutScreenDesc(gf, scrw, scrh, color_bits, 0, map) == GIF_ERROR) {
878 i_push_error(0, "Could not save screen descriptor");
882 mm_log((1, "Error in EGifPutScreenDesc."));
887 if (!do_ns_loop(gf, opts))
890 if (!do_gce(gf, 0, opts, want_trans, quant->mc_count)) {
895 if (opts->position_count) {
896 posx = opts->positions[0].x;
897 posy = opts->positions[0].y;
901 if (EGifPutImageDesc(gf, posx, posy, imgs[0]->xsize, imgs[0]->ysize,
902 opts->interlace, NULL) == GIF_ERROR) {
904 i_push_error(0, "Could not save image descriptor");
906 mm_log((1, "Error in EGifPutImageDesc."));
909 if (!do_write(gf, opts, imgs[0], result)) {
914 for (imgn = 1; imgn < count; ++imgn) {
915 quant->mc_count = orig_count;
916 quant->mc_size = orig_size;
917 want_trans = quant->transp != tr_none
918 && imgs[0]->channels == 4;
919 /* if the caller gives us too many colours we can't do transparency */
920 if (want_trans && quant->mc_count == 256)
922 /* if they want transparency but give us a big size, make it smaller
923 to give room for a transparency colour */
924 if (want_trans && quant->mc_size == 256)
927 quant_makemap(quant, imgs+imgn, 1);
928 result = quant_translate(quant, imgs[imgn]);
930 quant_transparent(quant, result, imgs[imgn], quant->mc_count);
932 if (!do_gce(gf, imgn, opts, want_trans, quant->mc_count)) {
937 if ((map = make_gif_map(quant, opts, want_trans)) == NULL) {
940 mm_log((1, "Error in MakeMapObject."));
943 if (imgn < opts->position_count) {
944 posx = opts->positions[imgn].x;
945 posy = opts->positions[imgn].y;
949 if (EGifPutImageDesc(gf, posx, posy, imgs[imgn]->xsize,
950 imgs[imgn]->ysize, opts->interlace,
953 i_push_error(0, "Could not save image descriptor");
957 mm_log((1, "Error in EGifPutImageDesc."));
962 if (!do_write(gf, opts, imgs[imgn], result)) {
973 /* get a palette entry for the transparency iff we have an image
974 with an alpha channel */
976 for (imgn = 0; imgn < count; ++imgn) {
977 if (imgs[imgn]->channels == 4) {
982 want_trans = want_trans && quant->transp != tr_none
983 && quant->mc_count < 256;
984 if (want_trans && quant->mc_size == 256)
987 /* handle the first image separately - since we allow giflib
988 conversion and giflib doesn't give us a separate function to build
991 /* produce a colour map */
992 quant_makemap(quant, imgs, count);
993 result = quant_translate(quant, imgs[0]);
995 if ((map = make_gif_map(quant, opts, want_trans)) == NULL) {
998 mm_log((1, "Error in MakeMapObject"));
1002 while (quant->mc_count > (1 << color_bits))
1005 if (EGifPutScreenDesc(gf, scrw, scrh, color_bits, 0, map) == GIF_ERROR) {
1007 i_push_error(0, "Could not save screen descriptor");
1011 mm_log((1, "Error in EGifPutScreenDesc."));
1016 if (!do_ns_loop(gf, opts))
1019 if (!do_gce(gf, 0, opts, want_trans, quant->mc_count)) {
1024 if (opts->position_count) {
1025 posx = opts->positions[0].x;
1026 posy = opts->positions[0].y;
1030 if (EGifPutImageDesc(gf, posx, posy, imgs[0]->xsize, imgs[0]->ysize,
1031 opts->interlace, NULL) == GIF_ERROR) {
1033 i_push_error(0, "Could not save image descriptor");
1035 mm_log((1, "Error in EGifPutImageDesc."));
1038 if (want_trans && imgs[0]->channels == 4)
1039 quant_transparent(quant, result, imgs[0], quant->mc_count);
1041 if (!do_write(gf, opts, imgs[0], result)) {
1048 for (imgn = 1; imgn < count; ++imgn) {
1050 result = quant_translate(quant, imgs[imgn]);
1051 local_trans = want_trans && imgs[imgn]->channels == 4;
1053 quant_transparent(quant, result, imgs[imgn], quant->mc_count);
1054 if (!do_gce(gf, imgn, opts, local_trans, quant->mc_count)) {
1059 if (imgn < opts->position_count) {
1060 posx = opts->positions[imgn].x;
1061 posy = opts->positions[imgn].y;
1065 if (EGifPutImageDesc(gf, posx, posy,
1066 imgs[imgn]->xsize, imgs[imgn]->ysize,
1067 opts->interlace, NULL) == GIF_ERROR) {
1069 i_push_error(0, "Could not save image descriptor");
1072 mm_log((1, "Error in EGifPutImageDesc."));
1075 if (!do_write(gf, opts, imgs[imgn], result)) {
1083 if (EGifCloseFile(gf) == GIF_ERROR) {
1085 i_push_error(0, "Could not close GIF file");
1086 mm_log((1, "Error in EGifCloseFile\n"));
1094 =item i_writegif_gen(i_quantize *quant, int fd, i_img **imgs, int count, i_gif_opts *opts)
1096 General high-level function to write a GIF to a file.
1098 Writes the GIF images to the specified file handle using the options
1099 in quant and opts. See L<image.h/i_quantize> and
1100 L<image.h/i_gif_opts>.
1102 Returns non-zero on success.
1108 i_writegif_gen(i_quantize *quant, int fd, i_img **imgs, int count,
1113 mm_log((1, "i_writegif_gen(quant %p, fd %d, imgs %p, count %d, opts %p)\n",
1114 quant, fd, imgs, count, opts));
1116 gif_set_version(quant, opts);
1118 if ((gf = EGifOpenFileHandle(fd)) == NULL) {
1120 i_push_error(0, "Cannot create GIF file object");
1121 mm_log((1, "Error in EGifOpenFileHandle, unable to write image.\n"));
1125 return i_writegif_low(quant, gf, imgs, count, opts);
1128 #if IM_GIFMAJOR >= 4
1131 =item gif_writer_callback(GifFileType *gf, const GifByteType *data, int size)
1133 Internal. Wrapper for the user write callback function.
1138 static int gif_writer_callback(GifFileType *gf, const GifByteType *data, int size)
1140 i_gen_write_data *gwd = (i_gen_write_data *)gf->UserData;
1142 return i_gen_writer(gwd, data, size) ? size : 0;
1148 =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)
1150 General high-level function to write a GIF using callbacks to send
1153 Returns non-zero on success.
1159 i_writegif_callback(i_quantize *quant, i_write_callback_t cb, char *userdata,
1160 int maxlength, i_img **imgs, int count, i_gif_opts *opts)
1162 #if IM_GIFMAJOR >= 4
1164 i_gen_write_data *gwd = i_gen_write_data_new(cb, userdata, maxlength);
1165 /* giflib declares this incorrectly as EgifOpen */
1166 extern GifFileType *EGifOpen(void *userData, OutputFunc writeFunc);
1171 mm_log((1, "i_writegif_callback(quant %p, i_write_callback_t %p, userdata $p, maxlength %d, imgs %p, count %d, opts %p)\n",
1172 quant, cb, userdata, maxlength, imgs, count, opts));
1174 if ((gf = EGifOpen(gwd, &gif_writer_callback)) == NULL) {
1176 i_push_error(0, "Cannot create GIF file object");
1177 mm_log((1, "Error in EGifOpenFileHandle, unable to write image.\n"));
1178 free_gen_write_data(gwd, 0);
1182 result = i_writegif_low(quant, gf, imgs, count, opts);
1183 return free_gen_write_data(gwd, result);
1190 =item gif_error_msg(int code)
1192 Grabs the most recent giflib error code from GifLastError() and
1193 returns a string that describes that error.
1195 The returned pointer points to a static buffer, either from a literal
1196 C string or a static buffer.
1200 static char const *gif_error_msg(int code) {
1201 static char msg[80];
1204 case E_GIF_ERR_OPEN_FAILED: /* should not see this */
1205 return "Failed to open given file";
1207 case E_GIF_ERR_WRITE_FAILED:
1208 return "Write failed";
1210 case E_GIF_ERR_HAS_SCRN_DSCR: /* should not see this */
1211 return "Screen descriptor already passed to giflib";
1213 case E_GIF_ERR_HAS_IMAG_DSCR: /* should not see this */
1214 return "Image descriptor already passed to giflib";
1216 case E_GIF_ERR_NO_COLOR_MAP: /* should not see this */
1217 return "Neither global nor local color map set";
1219 case E_GIF_ERR_DATA_TOO_BIG: /* should not see this */
1220 return "Too much pixel data passed to giflib";
1222 case E_GIF_ERR_NOT_ENOUGH_MEM:
1223 return "Out of memory";
1225 case E_GIF_ERR_DISK_IS_FULL:
1226 return "Disk is full";
1228 case E_GIF_ERR_CLOSE_FAILED: /* should not see this */
1229 return "File close failed";
1231 case E_GIF_ERR_NOT_WRITEABLE: /* should not see this */
1232 return "File not writable";
1234 case D_GIF_ERR_OPEN_FAILED:
1235 return "Failed to open file";
1237 case D_GIF_ERR_READ_FAILED:
1238 return "Failed to read from file";
1240 case D_GIF_ERR_NOT_GIF_FILE:
1241 return "File is not a GIF file";
1243 case D_GIF_ERR_NO_SCRN_DSCR:
1244 return "No screen descriptor detected - invalid file";
1246 case D_GIF_ERR_NO_IMAG_DSCR:
1247 return "No image descriptor detected - invalid file";
1249 case D_GIF_ERR_NO_COLOR_MAP:
1250 return "No global or local color map found";
1252 case D_GIF_ERR_WRONG_RECORD:
1253 return "Wrong record type detected - invalid file?";
1255 case D_GIF_ERR_DATA_TOO_BIG:
1256 return "Data in file too big for image";
1258 case D_GIF_ERR_NOT_ENOUGH_MEM:
1259 return "Out of memory";
1261 case D_GIF_ERR_CLOSE_FAILED:
1262 return "Close failed";
1264 case D_GIF_ERR_NOT_READABLE:
1265 return "File not opened for read";
1267 case D_GIF_ERR_IMAGE_DEFECT:
1268 return "Defective image";
1270 case D_GIF_ERR_EOF_TOO_SOON:
1271 return "Unexpected EOF - invalid file";
1274 sprintf(msg, "Unknown giflib error code %d", code);
1280 =item gif_push_error()
1282 Utility function that takes the current GIF error code, converts it to
1283 an error message and pushes it on the error stack.
1288 static void gif_push_error() {
1289 int code = GifLastError(); /* clears saved error */
1291 i_push_error(code, gif_error_msg(code));
1297 The Netscape loop extension isn't implemented. Giflib's extension
1298 writing code doesn't seem to support writing named extensions in this
1301 A bug in giflib is tickled by the i_writegif_callback(). This isn't a
1302 problem on ungiflib, but causes a SEGV on giflib. A patch is provided
1305 The GIF file tag (GIF87a vs GIF89a) currently isn't set. Using the
1306 supplied interface in giflib 4.1.0 causes a SEGV in
1307 EGifSetGifVersion(). See L<gif_set_version> for an explanation.
1311 Arnar M. Hrafnkelsson, addi@umich.edu