ee998ca5b8d98286b95d72b9f55a40d3418295b5
[imager.git] / gif.c
1 #include "image.h"
2 #include <gif_lib.h>
3
4 /*
5 =head1 NAME
6
7 gif.c - read and write gif files for Imager
8
9 =head1 SYNOPSIS
10
11   i_img *img;
12   i_img *imgs[count];
13   int fd;
14   int *colour_table,
15   int colours;
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
26   i_quantize quant;
27   i_gif_opts opts;
28
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, 
36                                 imgs, count, &opts);
37
38 =head1 DESCRIPTION
39
40 This source file provides the C level interface to reading and writing
41 GIF files for Imager.
42
43 This has been tested with giflib 3 and 4, though you lose the callback
44 functionality with giflib3.
45
46 =head1 REFERENCE
47
48 =over
49
50 =cut
51 */
52
53 static char const *gif_error_msg(int code);
54 static void gif_push_error();
55
56 #if IM_GIFMAJOR >= 4
57
58 /*
59 =item gif_scalar_info
60
61 Internal.  A structure passed to the reader function used for reading
62 GIFs from scalars.
63
64 Used with giflib 4 and later.
65
66 =cut
67 */
68
69 struct gif_scalar_info {
70   char *data;
71   int length;
72   int cpos;
73 };
74
75 /*
76 =item my_gif_inputfunc(GifFileType *gft, GifByteType *buf, int length)
77
78 Internal.  The reader callback passed to giflib.
79
80 Used with giflib 4 and later.
81
82 =cut
83 */
84
85 int
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); */
89
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);
93   gsi->cpos+=length;
94   return length;
95 }
96
97 #endif
98
99 /*
100   This file needs a complete rewrite 
101
102   This file needs a complete rewrite 
103
104   Maybe not anymore, though reading still needs to support reading
105   all those gif properties.
106 */
107
108 /* Make some variables global, so we could access them faster: */
109
110 static int
111     ImageNum = 0,
112     BackGround = 0,
113     ColorMapSize = 0,
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;
117
118 /*
119 =item i_readgif_low(GifFileType *GifFile, int **colour_table, int *colours)
120
121 Internal.  Low-level function for reading a GIF file.  The caller must
122 create the appropriate GifFileType object and pass it in.
123
124 =cut
125 */
126 i_img *
127 i_readgif_low(GifFileType *GifFile, int **colour_table, int *colours) {
128   i_img *im;
129   int i, j, Size, Row, Col, Width, Height, ExtCode, Count, x;
130   GifRecordType RecordType;
131   GifByteType *Extension;
132   
133   GifRowType GifRow;
134   static GifColorType *ColorMapEntry;
135   i_color col;
136
137   /*  unsigned char *Buffer, *BufferP; */
138
139   mm_log((1,"i_readgif_low(GifFile %p, colour_table %p, colours %p)\n", GifFile, colour_table, colours));
140
141   BackGround = GifFile->SBackGroundColor;
142   ColorMap = (GifFile->Image.ColorMap ? GifFile->Image.ColorMap : GifFile->SColorMap);
143   ColorMapSize = ColorMap->ColorCount;
144
145   /* **************************************** */
146   if(colour_table != NULL) {
147     int q;
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."); 
151     
152     memset(*colour_table, 0, sizeof(int *) * ColorMapSize * 3);
153
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;
159     }
160   }
161
162   if(colours != NULL) {
163     *colours = ColorMapSize;
164   }
165   
166   /* **************************************** */
167   im=i_img_empty_ch(NULL,GifFile->SWidth,GifFile->SHeight,3);
168   
169   Size = GifFile->SWidth * sizeof(GifPixelType); 
170   
171   if ((GifRow = (GifRowType) mymalloc(Size)) == NULL)
172     m_fatal(0,"Failed to allocate memory required, aborted."); /* First row. */
173
174   for (i = 0; i < GifFile->SWidth; i++) GifRow[i] = GifFile->SBackGroundColor;
175   
176   /* Scan the content of the GIF file and load the image(s) in: */
177   do {
178     if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR) {
179       gif_push_error();
180       i_push_error(0, "Unable to get record type");
181       if (colour_table)
182         free(colour_table);
183       i_img_destroy(im);
184       DGifCloseFile(GifFile);
185       return NULL;
186     }
187     
188     switch (RecordType) {
189     case IMAGE_DESC_RECORD_TYPE:
190       if (DGifGetImageDesc(GifFile) == GIF_ERROR) {
191         gif_push_error();
192         i_push_error(0, "Unable to get image descriptor");
193         if (colour_table)
194           free(colour_table);
195         i_img_destroy(im);
196         DGifCloseFile(GifFile);
197         return NULL;
198       }
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;
203       ImageNum++;
204       mm_log((1,"i_readgif: Image %d at (%d, %d) [%dx%d]: \n",ImageNum, Col, Row, Width, Height));
205
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);
209         if (colour_table)
210           free(colour_table);
211         i_img_destroy(im);
212         DGifCloseFile(GifFile);
213         return(0);
214       }
215       if (GifFile->Image.Interlace) {
216
217         for (Count = i = 0; i < 4; i++) for (j = Row + InterlacedOffset[i]; j < Row + Height; j += InterlacedJumps[i]) {
218           Count++;
219           if (DGifGetLine(GifFile, &GifRow[Col], Width) == GIF_ERROR) {
220             gif_push_error();
221             i_push_error(0, "Reading GIF line");
222             if (colour_table)
223               free(colour_table);
224             i_img_destroy(im);
225             DGifCloseFile(GifFile);
226             return NULL;
227           }
228           
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;
234             i_ppix(im,x,j,&col);
235           }
236           
237         }
238       }
239       else {
240         for (i = 0; i < Height; i++) {
241           if (DGifGetLine(GifFile, &GifRow[Col], Width) == GIF_ERROR) {
242             gif_push_error();
243             i_push_error(0, "Reading GIF line");
244             if (colour_table)
245               free(colour_table);
246             i_img_destroy(im);
247             DGifCloseFile(GifFile);
248             return NULL;
249           }
250
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);
257           }
258           Row++;
259         }
260       }
261       break;
262     case EXTENSION_RECORD_TYPE:
263       /* Skip any extension blocks in file: */
264       if (DGifGetExtension(GifFile, &ExtCode, &Extension) == GIF_ERROR) {
265         gif_push_error();
266         i_push_error(0, "Reading extension record");
267         if (colour_table)
268           free(colour_table);
269         i_img_destroy(im);
270         DGifCloseFile(GifFile);
271         return NULL;
272       }
273       while (Extension != NULL) {
274         if (DGifGetExtensionNext(GifFile, &Extension) == GIF_ERROR) {
275           gif_push_error();
276           i_push_error(0, "reading next block of extension");
277           if (colour_table)
278             free(colour_table);
279           i_img_destroy(im);
280           DGifCloseFile(GifFile);
281           return NULL;
282         }
283       }
284       break;
285     case TERMINATE_RECORD_TYPE:
286       break;
287     default:                /* Should be traps by DGifGetRecordType. */
288       break;
289     }
290   } while (RecordType != TERMINATE_RECORD_TYPE);
291   
292   myfree(GifRow);
293   
294   if (DGifCloseFile(GifFile) == GIF_ERROR) {
295     gif_push_error();
296     i_push_error(0, "Closing GIF file object");
297     if (colour_table)
298       free(colour_table);
299     i_img_destroy(im);
300     return NULL;
301   }
302   return im;
303 }
304
305 /*
306 =item i_readgif(int fd, int **colour_table, int *colours)
307
308 Reads in a GIF file from a file handle and converts it to an Imager
309 RGB image object.
310
311 Returns the palette for the object in colour_table for colours
312 colours.
313
314 Returns NULL on failure.
315
316 =cut
317 */
318
319 i_img *
320 i_readgif(int fd, int **colour_table, int *colours) {
321   GifFileType *GifFile;
322
323   i_clear_error();
324   
325   mm_log((1,"i_readgif(fd %d, colour_table %p, colours %p)\n", fd, colour_table, colours));
326
327   if ((GifFile = DGifOpenFileHandle(fd)) == NULL) {
328     gif_push_error();
329     i_push_error(0, "Cannot create giflib file object");
330     mm_log((1,"i_readgif: Unable to open file\n"));
331     return NULL;
332   }
333
334   return i_readgif_low(GifFile, colour_table, colours);
335 }
336
337 /*
338 =item i_writegif(i_img *im, int fd, int max_colors, int pixdev, int fixedlen, i_color fixed[])
339
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>.
343
344 Returns non-zero on success.
345
346 =cut
347 */
348
349 undef_int
350 i_writegif(i_img *im, int fd, int max_colors, int pixdev, int fixedlen, i_color fixed[])
351 {
352   i_color colors[256];
353   i_quantize quant;
354   i_gif_opts opts;
355   
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);
366 }
367
368 /*
369 =item i_writegifmc(i_img *im, int fd, int max_colors)
370
371 Write I<img> to the file handle I<fd>.  The resulting GIF will use a
372 maximum of 1<<I<max_colours> colours.
373
374 Returns non-zero on success.
375
376 =cut
377 */
378
379 undef_int
380 i_writegifmc(i_img *im, int fd, int max_colors) {
381   i_color colors[256];
382   i_quantize quant;
383   i_gif_opts opts;
384   
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;
390   quant.mc_count = 0;
391   quant.translate = pt_giflib;
392   return i_writegif_gen(&quant, fd, &im, 1, &opts);
393 }
394
395 #if 1
396
397 undef_int
398 i_writegifex(i_img *im, int fd) {
399   return 0;
400 }
401
402 #else
403
404 /* I don't think this works
405    note that RedBuffer is never allocated - TC
406 */
407
408 undef_int
409 i_writegifex(i_img *im,int fd) {
410   int colors, xsize, ysize, channels;
411   int x,y,ColorMapSize;
412   unsigned long Size;
413
414   struct octt *ct;
415
416   GifByteType *RedBuffer = NULL, *GreenBuffer = NULL, *BlueBuffer = NULL,*OutputBuffer = NULL;
417   ColorMapObject *OutputColorMap = NULL;
418   GifFileType *GifFile;
419   GifByteType *Ptr;
420   
421   i_color val;
422
423   mm_log((1,"i_writegif(0x%x,fd %d)\n",im,fd));
424   
425   if (!(im->channels==1 || im->channels==3)) { fprintf(stderr,"Unable to write gif, improper colorspace.\n"); exit(3); }
426
427   xsize=im->xsize;
428   ysize=im->ysize;
429   channels=im->channels;
430
431   colors=0;
432   ct=octt_new();
433
434   colors=0;
435   for(x=0;x<xsize;x++) for(y=0;y<ysize;y++) {
436     i_gpix(im,x,y,&val);
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 */
440   }
441
442   ColorMapSize = (colors > 256) ? 256 : colors;
443   
444   Size = ((long) im->xsize) * im->ysize * sizeof(GifByteType);
445   
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.");
450   
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"));
454     return(0);
455   }
456
457
458   myfree(RedBuffer);
459   if (im->channels == 3) { myfree(GreenBuffer); myfree(BlueBuffer); }
460   
461   if ((GifFile = EGifOpenFileHandle(fd)) == NULL) {
462     mm_log((1,"Error in EGifOpenFileHandle, unable to write image.\n"));
463     return(0);
464   }
465   
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);
470     return(0);
471   }
472
473   Ptr = OutputBuffer;
474
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);
479       return(0);
480     }
481     
482     Ptr += im->xsize;
483   }
484   
485   if (EGifCloseFile(GifFile) == GIF_ERROR) {
486     mm_log((1,"Error in EGifCloseFile, unable to write image.\n"));
487     return(0);
488   }
489   return(1);
490 }
491
492 #endif
493
494 /*
495 =item i_readgif_scalar(char *data, int length, int **colour_table, int *colours)
496
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).
500
501 This function is only available with giflib 4 and higher.
502
503 =cut
504 */
505 i_img*
506 i_readgif_scalar(char *data, int length, int **colour_table, int *colours) {
507 #if IM_GIFMAJOR >= 4
508   GifFileType *GifFile;
509   struct gif_scalar_info gsi;
510
511   i_clear_error();
512
513   gsi.cpos=0;
514   gsi.length=length;
515   gsi.data=data;
516
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) {
519     gif_push_error();
520     i_push_error(0, "Cannot create giflib callback object");
521     mm_log((1,"i_readgif_scalar: Unable to open scalar datasource.\n"));
522     return NULL;
523   }
524
525   return i_readgif_low(GifFile, colour_table, colours);
526 #else
527   return NULL;
528 #endif
529 }
530
531 #if IM_GIFMAJOR >= 4
532
533 /*
534 =item gif_read_callback(GifFileType *gft, GifByteType *buf, int length)
535
536 Internal.  The reader callback wrapper passed to giflib.
537
538 This function is only used with giflib 4 and higher.
539
540 =cut
541 */
542
543 static int
544 gif_read_callback(GifFileType *gft, GifByteType *buf, int length) {
545   return i_gen_reader((i_gen_read_data *)gft->UserData, buf, length);
546 }
547
548 #endif
549
550
551 /*
552 =item i_readgif_callback(i_read_callback_t cb, char *userdata, int **colour_table, int *colours)
553
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.
556
557 This function is only used with giflib 4 and higher.
558
559 =cut
560 */
561
562 i_img*
563 i_readgif_callback(i_read_callback_t cb, char *userdata, int **colour_table, int *colours) {
564 #if IM_GIFMAJOR >= 4
565   GifFileType *GifFile;
566   i_img *result;
567
568   i_gen_read_data *gci = i_gen_read_data_new(cb, userdata);
569
570   i_clear_error();
571   
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) {
574     gif_push_error();
575     i_push_error(0, "Cannot create giflib callback object");
576     mm_log((1,"i_readgif_callback: Unable to open callback datasource.\n"));
577     myfree(gci);
578     return NULL;
579   }
580
581   result = i_readgif_low(GifFile, colour_table, colours);
582   free_gen_read_data(gci);
583
584   return result;
585 #else
586   return NULL;
587 #endif
588 }
589
590 /*
591 =item do_write(GifFileType *gf, i_gif_opts *opts, i_img *img, i_palidx *data)
592
593 Internal.  Low level image write function.  Writes in interlace if
594 that was requested in the GIF options.
595
596 Returns non-zero on success.
597
598 =cut
599 */
600 static undef_int 
601 do_write(GifFileType *gf, i_gif_opts *opts, i_img *img, i_palidx *data) {
602   if (opts->interlace) {
603     int i, j;
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) {
607           gif_push_error();
608           i_push_error(0, "Could not save image data:");
609           mm_log((1, "Error in EGifPutLine\n"));
610           EGifCloseFile(gf);
611           return 0;
612         }
613       }
614     }
615   }
616   else {
617     int y;
618     for (y = 0; y < img->ysize; ++y) {
619       if (EGifPutLine(gf, data, img->xsize) == GIF_ERROR) {
620         gif_push_error();
621         i_push_error(0, "Could not save image data:");
622         mm_log((1, "Error in EGifPutLine\n"));
623         EGifCloseFile(gf);
624         return 0;
625       }
626       data += img->xsize;
627     }
628   }
629
630   return 1;
631 }
632
633 /*
634 =item do_gce(GifFileType *gf, int index, i_gif_opts *opts, int want_trans, int trans_index)
635
636 Internal. Writes the GIF graphics control extension, if necessary.
637
638 Returns non-zero on success.
639
640 =cut
641 */
642 static int do_gce(GifFileType *gf, int index, i_gif_opts *opts, int want_trans, int trans_index)
643 {
644   unsigned char gce[4] = {0};
645   int want_gce = 0;
646   if (want_trans) {
647     gce[0] |= 1;
648     gce[3] = trans_index;
649     ++want_gce;
650   }
651   if (index < opts->delay_count) {
652     gce[1] = opts->delays[index] % 256;
653     gce[2] = opts->delays[index] / 256;
654     ++want_gce;
655   }
656   if (index < opts->user_input_count) {
657     if (opts->user_input_flags[index])
658       gce[0] |= 2;
659     ++want_gce;
660   }
661   if (index < opts->disposal_count) {
662     gce[0] |= (opts->disposal[index] & 3) << 2;
663     ++want_gce;
664   }
665   if (want_gce) {
666     if (EGifPutExtension(gf, 0xF9, sizeof(gce), gce) == GIF_ERROR) {
667       gif_push_error();
668       i_push_error(0, "Could not save GCE");
669     }
670   }
671   return 1;
672 }
673
674 /*
675 =item do_ns_loop(GifFileType *gf, i_gif_opts *opts)
676
677 Internal.  Add the Netscape2.0 loop extension block, if requested.
678
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.
682
683 =cut
684 */
685 static int do_ns_loop(GifFileType *gf, i_gif_opts *opts)
686 {
687   /* EGifPutExtension() doesn't appear to handle application 
688      extension blocks in any way
689      Since giflib wraps the fd with a FILE * (and puts that in its
690      private data), we can't do an end-run and write the data 
691      directly to the fd.
692      There's no open interface that takes a FILE * either, so we 
693      can't workaround it that way either.
694      If giflib's callback interface wasn't broken by default, I'd 
695      force file writes to use callbacks, but it is broken by default.
696   */
697 #if 0
698   /* yes this was another attempt at supporting the loop extension */
699   if (opts->loop_count) {
700     unsigned char nsle[12] = "NETSCAPE2.0";
701     unsigned char subblock[3];
702     if (EGifPutExtension(gf, 0xFF, 11, nsle) == GIF_ERROR) {
703       gif_push_error();
704       i_push_error(0, "writing loop extension");
705       return 0;
706     }
707     subblock[0] = 1;
708     subblock[1] = opts->loop_count % 256;
709     subblock[2] = opts->loop_count / 256;
710     if (EGifPutExtension(gf, 0, 3, subblock) == GIF_ERROR) {
711       gif_push_error();
712       i_push_error(0, "writing loop extention sub-block");
713       return 0;
714     }
715     if (EGifPutExtension(gf, 0, 0, subblock) == GIF_ERROR) {
716       gif_push_error();
717       i_push_error(0, "writing loop extension terminator");
718       return 0;
719     }
720   }
721 #endif
722   return 1;
723 }
724
725 /*
726 =item make_gif_map(i_quantize *quant, i_gif_opts *opts, int want_trans)
727
728 Create a giflib color map object from an Imager color map.
729
730 =cut
731 */
732
733 static ColorMapObject *make_gif_map(i_quantize *quant, i_gif_opts *opts,
734                                     int want_trans) {
735   GifColorType colors[256];
736   int i;
737   int size = quant->mc_count;
738   int map_size;
739   ColorMapObject *map;
740
741   for (i = 0; i < quant->mc_count; ++i) {
742     colors[i].Red = quant->mc_colors[i].rgb.r;
743     colors[i].Green = quant->mc_colors[i].rgb.g;
744     colors[i].Blue = quant->mc_colors[i].rgb.b;
745   }
746   if (want_trans) {
747     colors[size].Red = opts->tran_color.rgb.r;
748     colors[size].Green = opts->tran_color.rgb.g;
749     colors[size].Blue = opts->tran_color.rgb.b;
750     ++size;
751   }
752   map_size = 1;
753   while (map_size < size)
754     map_size <<= 1;
755   /* giflib spews for 1 colour maps, reasonable, I suppose */
756   if (map_size == 1)
757     map_size = 2;
758   map = MakeMapObject(map_size, colors);
759   if (!map) {
760     gif_push_error();
761     i_push_error(0, "Could not create color map object");
762     return NULL;
763   }
764   return map;
765 }
766
767 /*
768 =item gif_set_version(i_quantize *quant, i_gif_opts *opts)
769
770 We need to call EGifSetGifVersion() before opening the file - put that
771 common code here.
772
773 Unfortunately giflib 4.1.0 crashes when we use this.  Internally
774 giflib 4.1.0 has code:
775
776   static char *GifVersionPrefix = GIF87_STAMP;
777
778 and the code that sets the version internally does:
779
780   strncpy(&GifVersionPrefix[3], Version, 3);
781
782 which is very broken.
783
784 Failing to set the correct GIF version doesn't seem to cause a problem
785 with readers.
786
787 =cut
788 */
789
790 static void gif_set_version(i_quantize *quant, i_gif_opts *opts) {
791   /* the following crashed giflib
792      the EGifSetGifVersion() is seriously borked in giflib
793      it's less borked in the ungiflib beta, but we don't have a mechanism
794      to distinguish them
795      if (opts->delay_count
796      || opts->user_input_count
797      || opts->disposal_count
798      || opts->loop_count
799      || quant->transp != tr_none)
800      EGifSetGifVersion("89a");
801      else
802      EGifSetGifVersion("87a");
803   */
804 }
805
806 /*
807 =item i_writegif_low(i_quantize *quant, GifFileType *gf, i_img **imgs, int count, i_gif_opts *opts)
808
809 Internal.  Low-level function that does the high-level GIF processing
810 :)
811
812 Returns non-zero on success.
813
814 =cut
815 */
816
817 static undef_int
818 i_writegif_low(i_quantize *quant, GifFileType *gf, i_img **imgs, int count,
819                i_gif_opts *opts) {
820   unsigned char *result;
821   int color_bits;
822   ColorMapObject *map;
823   int scrw = 0, scrh = 0;
824   int imgn, orig_count, orig_size;
825   int posx, posy;
826
827   mm_log((1, "i_writegif_low(quant %p, gf  %p, imgs %p, count %d, opts %p)\n", 
828           quant, gf, imgs, count, opts));
829
830   /**((char *)0) = 1;*/
831   /* sanity is nice */
832   if (quant->mc_size > 256) 
833     quant->mc_size = 256;
834   if (quant->mc_count > quant->mc_size)
835     quant->mc_count = quant->mc_size;
836
837   for (imgn = 0; imgn < count; ++imgn) {
838     if (imgn < opts->position_count) {
839       if (imgs[imgn]->xsize + opts->positions[imgn].x > scrw)
840         scrw = imgs[imgn]->xsize + opts->positions[imgn].x;
841       if (imgs[imgn]->ysize + opts->positions[imgn].y > scrw)
842         scrh = imgs[imgn]->ysize + opts->positions[imgn].y;
843     }
844     else {
845       if (imgs[imgn]->xsize > scrw)
846         scrw = imgs[imgn]->xsize;
847       if (imgs[imgn]->ysize > scrh)
848         scrh = imgs[imgn]->ysize;
849     }
850   }
851
852   if (count <= 0) {
853     i_push_error(0, "No images provided to write");
854     return 0; /* what are you smoking? */
855   }
856
857   orig_count = quant->mc_count;
858   orig_size = quant->mc_size;
859
860   if (opts->each_palette) {
861     int want_trans = quant->transp != tr_none 
862       && imgs[0]->channels == 4;
863
864     /* if the caller gives us too many colours we can't do transparency */
865     if (want_trans && quant->mc_count == 256)
866       want_trans = 0;
867     /* if they want transparency but give us a big size, make it smaller
868        to give room for a transparency colour */
869     if (want_trans && quant->mc_size == 256)
870       --quant->mc_size;
871
872     /* we always generate a global palette - this lets systems with a 
873        broken giflib work */
874     quant_makemap(quant, imgs, 1);
875     result = quant_translate(quant, imgs[0]);
876
877     if (want_trans)
878       quant_transparent(quant, result, imgs[0], quant->mc_count);
879     
880     if ((map = make_gif_map(quant, opts, want_trans)) == NULL) {
881       myfree(result);
882       EGifCloseFile(gf);
883       mm_log((1, "Error in MakeMapObject."));
884       return 0;
885     }
886
887     color_bits = 1;
888     while (quant->mc_size > (1 << color_bits))
889       ++color_bits;
890   
891     if (EGifPutScreenDesc(gf, scrw, scrh, color_bits, 0, map) == GIF_ERROR) {
892       gif_push_error();
893       i_push_error(0, "Could not save screen descriptor");
894       FreeMapObject(map);
895       myfree(result);
896       EGifCloseFile(gf);
897       mm_log((1, "Error in EGifPutScreenDesc."));
898       return 0;
899     }
900     FreeMapObject(map);
901
902     if (!do_ns_loop(gf, opts))
903       return 0;
904
905     if (!do_gce(gf, 0, opts, want_trans, quant->mc_count)) {
906       myfree(result);
907       EGifCloseFile(gf);
908       return 0;
909     }
910     if (opts->position_count) {
911       posx = opts->positions[0].x;
912       posy = opts->positions[0].y;
913     }
914     else
915       posx = posy = 0;
916     if (EGifPutImageDesc(gf, posx, posy, imgs[0]->xsize, imgs[0]->ysize, 
917                          opts->interlace, NULL) == GIF_ERROR) {
918       gif_push_error();
919       i_push_error(0, "Could not save image descriptor");
920       EGifCloseFile(gf);
921       mm_log((1, "Error in EGifPutImageDesc."));
922       return 0;
923     }
924     if (!do_write(gf, opts, imgs[0], result)) {
925       EGifCloseFile(gf);
926       myfree(result);
927       return 0;
928     }
929     for (imgn = 1; imgn < count; ++imgn) {
930       quant->mc_count = orig_count;
931       quant->mc_size = orig_size;
932       want_trans = quant->transp != tr_none 
933         && imgs[0]->channels == 4;
934       /* if the caller gives us too many colours we can't do transparency */
935       if (want_trans && quant->mc_count == 256)
936         want_trans = 0;
937       /* if they want transparency but give us a big size, make it smaller
938          to give room for a transparency colour */
939       if (want_trans && quant->mc_size == 256)
940         --quant->mc_size;
941
942       quant_makemap(quant, imgs+imgn, 1);
943       result = quant_translate(quant, imgs[imgn]);
944       if (want_trans)
945         quant_transparent(quant, result, imgs[imgn], quant->mc_count);
946       
947       if (!do_gce(gf, imgn, opts, want_trans, quant->mc_count)) {
948         myfree(result);
949         EGifCloseFile(gf);
950         return 0;
951       }
952       if ((map = make_gif_map(quant, opts, want_trans)) == NULL) {
953         myfree(result);
954         EGifCloseFile(gf);
955         mm_log((1, "Error in MakeMapObject."));
956         return 0;
957       }
958       if (imgn < opts->position_count) {
959         posx = opts->positions[imgn].x;
960         posy = opts->positions[imgn].y;
961       }
962       else
963         posx = posy = 0;
964       if (EGifPutImageDesc(gf, posx, posy, imgs[imgn]->xsize, 
965                            imgs[imgn]->ysize, opts->interlace, 
966                            map) == GIF_ERROR) {
967         gif_push_error();
968         i_push_error(0, "Could not save image descriptor");
969         myfree(result);
970         FreeMapObject(map);
971         EGifCloseFile(gf);
972         mm_log((1, "Error in EGifPutImageDesc."));
973         return 0;
974       }
975       FreeMapObject(map);
976       
977       if (!do_write(gf, opts, imgs[imgn], result)) {
978         EGifCloseFile(gf);
979         myfree(result);
980         return 0;
981       }
982       myfree(result);
983     }
984   }
985   else {
986     int want_trans;
987
988     /* get a palette entry for the transparency iff we have an image
989        with an alpha channel */
990     want_trans = 0;
991     for (imgn = 0; imgn < count; ++imgn) {
992       if (imgs[imgn]->channels == 4) {
993         ++want_trans;
994         break;
995       }
996     }
997     want_trans = want_trans && quant->transp != tr_none 
998       && quant->mc_count < 256;
999     if (want_trans && quant->mc_size == 256)
1000       --quant->mc_size;
1001
1002     /* handle the first image separately - since we allow giflib
1003        conversion and giflib doesn't give us a separate function to build
1004        the colormap. */
1005      
1006     /* produce a colour map */
1007     quant_makemap(quant, imgs, count);
1008     result = quant_translate(quant, imgs[0]);
1009
1010     if ((map = make_gif_map(quant, opts, want_trans)) == NULL) {
1011       myfree(result);
1012       EGifCloseFile(gf);
1013       mm_log((1, "Error in MakeMapObject"));
1014       return 0;
1015     }
1016     color_bits = 1;
1017     while (quant->mc_count > (1 << color_bits))
1018       ++color_bits;
1019
1020     if (EGifPutScreenDesc(gf, scrw, scrh, color_bits, 0, map) == GIF_ERROR) {
1021       gif_push_error();
1022       i_push_error(0, "Could not save screen descriptor");
1023       FreeMapObject(map);
1024       myfree(result);
1025       EGifCloseFile(gf);
1026       mm_log((1, "Error in EGifPutScreenDesc."));
1027       return 0;
1028     }
1029     FreeMapObject(map);
1030
1031     if (!do_ns_loop(gf, opts))
1032       return 0;
1033
1034     if (!do_gce(gf, 0, opts, want_trans, quant->mc_count)) {
1035       myfree(result);
1036       EGifCloseFile(gf);
1037       return 0;
1038     }
1039     if (opts->position_count) {
1040       posx = opts->positions[0].x;
1041       posy = opts->positions[0].y;
1042     }
1043     else
1044       posx = posy = 0;
1045     if (EGifPutImageDesc(gf, posx, posy, imgs[0]->xsize, imgs[0]->ysize, 
1046                          opts->interlace, NULL) == GIF_ERROR) {
1047       gif_push_error();
1048       i_push_error(0, "Could not save image descriptor");
1049       EGifCloseFile(gf);
1050       mm_log((1, "Error in EGifPutImageDesc."));
1051       return 0;
1052     }
1053     if (want_trans && imgs[0]->channels == 4) 
1054       quant_transparent(quant, result, imgs[0], quant->mc_count);
1055
1056     if (!do_write(gf, opts, imgs[0], result)) {
1057       EGifCloseFile(gf);
1058       myfree(result);
1059       return 0;
1060     }
1061     myfree(result);
1062
1063     for (imgn = 1; imgn < count; ++imgn) {
1064       int local_trans;
1065       result = quant_translate(quant, imgs[imgn]);
1066       local_trans = want_trans && imgs[imgn]->channels == 4;
1067       if (local_trans)
1068         quant_transparent(quant, result, imgs[imgn], quant->mc_count);
1069       if (!do_gce(gf, imgn, opts, local_trans, quant->mc_count)) {
1070         myfree(result);
1071         EGifCloseFile(gf);
1072         return 0;
1073       }
1074       if (imgn < opts->position_count) {
1075         posx = opts->positions[imgn].x;
1076         posy = opts->positions[imgn].y;
1077       }
1078       else
1079         posx = posy = 0;
1080       if (EGifPutImageDesc(gf, posx, posy, 
1081                            imgs[imgn]->xsize, imgs[imgn]->ysize, 
1082                            opts->interlace, NULL) == GIF_ERROR) {
1083         gif_push_error();
1084         i_push_error(0, "Could not save image descriptor");
1085         myfree(result);
1086         EGifCloseFile(gf);
1087         mm_log((1, "Error in EGifPutImageDesc."));
1088         return 0;
1089       }
1090       if (!do_write(gf, opts, imgs[imgn], result)) {
1091         EGifCloseFile(gf);
1092         myfree(result);
1093         return 0;
1094       }
1095       myfree(result);
1096     }
1097   }
1098   if (EGifCloseFile(gf) == GIF_ERROR) {
1099     gif_push_error();
1100     i_push_error(0, "Could not close GIF file");
1101     mm_log((1, "Error in EGifCloseFile\n"));
1102     return 0;
1103   }
1104
1105   return 1;
1106 }
1107
1108 /*
1109 =item i_writegif_gen(i_quantize *quant, int fd, i_img **imgs, int count, i_gif_opts *opts)
1110
1111 General high-level function to write a GIF to a file.
1112
1113 Writes the GIF images to the specified file handle using the options
1114 in quant and opts.  See L<image.h/i_quantize> and
1115 L<image.h/i_gif_opts>.
1116
1117 Returns non-zero on success.
1118
1119 =cut
1120 */
1121
1122 undef_int
1123 i_writegif_gen(i_quantize *quant, int fd, i_img **imgs, int count, 
1124                i_gif_opts *opts) {
1125   GifFileType *gf;
1126
1127   i_clear_error();
1128   mm_log((1, "i_writegif_gen(quant %p, fd %d, imgs %p, count %d, opts %p)\n", 
1129           quant, fd, imgs, count, opts));
1130
1131   gif_set_version(quant, opts);
1132
1133   if ((gf = EGifOpenFileHandle(fd)) == NULL) {
1134     gif_push_error();
1135     i_push_error(0, "Cannot create GIF file object");
1136     mm_log((1, "Error in EGifOpenFileHandle, unable to write image.\n"));
1137     return 0;
1138   }
1139
1140   return i_writegif_low(quant, gf, imgs, count, opts);
1141 }
1142
1143 #if IM_GIFMAJOR >= 4
1144
1145 /*
1146 =item gif_writer_callback(GifFileType *gf, const GifByteType *data, int size)
1147
1148 Internal.  Wrapper for the user write callback function.
1149
1150 =cut
1151 */
1152
1153 static int gif_writer_callback(GifFileType *gf, const GifByteType *data, int size)
1154 {
1155   i_gen_write_data *gwd = (i_gen_write_data *)gf->UserData;
1156
1157   return i_gen_writer(gwd, data, size) ? size : 0;
1158 }
1159
1160 #endif
1161
1162 /*
1163 =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)
1164
1165 General high-level function to write a GIF using callbacks to send
1166 back the data.
1167
1168 Returns non-zero on success.
1169
1170 =cut
1171 */
1172
1173 undef_int
1174 i_writegif_callback(i_quantize *quant, i_write_callback_t cb, char *userdata,
1175                     int maxlength, i_img **imgs, int count, i_gif_opts *opts)
1176 {
1177 #if IM_GIFMAJOR >= 4
1178   GifFileType *gf;
1179   i_gen_write_data *gwd = i_gen_write_data_new(cb, userdata, maxlength);
1180   /* giflib declares this incorrectly as EgifOpen */
1181   extern GifFileType *EGifOpen(void *userData, OutputFunc writeFunc);
1182   int result;
1183
1184   i_clear_error();
1185
1186   mm_log((1, "i_writegif_callback(quant %p, i_write_callback_t %p, userdata $p, maxlength %d, imgs %p, count %d, opts %p)\n", 
1187           quant, cb, userdata, maxlength, imgs, count, opts));
1188   
1189   if ((gf = EGifOpen(gwd, &gif_writer_callback)) == NULL) {
1190     gif_push_error();
1191     i_push_error(0, "Cannot create GIF file object");
1192     mm_log((1, "Error in EGifOpenFileHandle, unable to write image.\n"));
1193     free_gen_write_data(gwd, 0);
1194     return 0;
1195   }
1196
1197   result = i_writegif_low(quant, gf, imgs, count, opts);
1198   return free_gen_write_data(gwd, result);
1199 #else
1200   return 0;
1201 #endif
1202 }
1203
1204 /*
1205 =item gif_error_msg(int code)
1206
1207 Grabs the most recent giflib error code from GifLastError() and 
1208 returns a string that describes that error.
1209
1210 The returned pointer points to a static buffer, either from a literal
1211 C string or a static buffer.
1212
1213 =cut */
1214
1215 static char const *gif_error_msg(int code) {
1216   static char msg[80];
1217
1218   switch (code) {
1219   case E_GIF_ERR_OPEN_FAILED: /* should not see this */
1220     return "Failed to open given file";
1221     
1222   case E_GIF_ERR_WRITE_FAILED:
1223     return "Write failed";
1224
1225   case E_GIF_ERR_HAS_SCRN_DSCR: /* should not see this */
1226     return "Screen descriptor already passed to giflib";
1227
1228   case E_GIF_ERR_HAS_IMAG_DSCR: /* should not see this */
1229     return "Image descriptor already passed to giflib";
1230     
1231   case E_GIF_ERR_NO_COLOR_MAP: /* should not see this */
1232     return "Neither global nor local color map set";
1233
1234   case E_GIF_ERR_DATA_TOO_BIG: /* should not see this */
1235     return "Too much pixel data passed to giflib";
1236
1237   case E_GIF_ERR_NOT_ENOUGH_MEM:
1238     return "Out of memory";
1239     
1240   case E_GIF_ERR_DISK_IS_FULL:
1241     return "Disk is full";
1242     
1243   case E_GIF_ERR_CLOSE_FAILED: /* should not see this */
1244     return "File close failed";
1245  
1246   case E_GIF_ERR_NOT_WRITEABLE: /* should not see this */
1247     return "File not writable";
1248
1249   case D_GIF_ERR_OPEN_FAILED:
1250     return "Failed to open file";
1251     
1252   case D_GIF_ERR_READ_FAILED:
1253     return "Failed to read from file";
1254
1255   case D_GIF_ERR_NOT_GIF_FILE:
1256     return "File is not a GIF file";
1257
1258   case D_GIF_ERR_NO_SCRN_DSCR:
1259     return "No screen descriptor detected - invalid file";
1260
1261   case D_GIF_ERR_NO_IMAG_DSCR:
1262     return "No image descriptor detected - invalid file";
1263
1264   case D_GIF_ERR_NO_COLOR_MAP:
1265     return "No global or local color map found";
1266
1267   case D_GIF_ERR_WRONG_RECORD:
1268     return "Wrong record type detected - invalid file?";
1269
1270   case D_GIF_ERR_DATA_TOO_BIG:
1271     return "Data in file too big for image";
1272
1273   case D_GIF_ERR_NOT_ENOUGH_MEM:
1274     return "Out of memory";
1275
1276   case D_GIF_ERR_CLOSE_FAILED:
1277     return "Close failed";
1278
1279   case D_GIF_ERR_NOT_READABLE:
1280     return "File not opened for read";
1281
1282   case D_GIF_ERR_IMAGE_DEFECT:
1283     return "Defective image";
1284
1285   case D_GIF_ERR_EOF_TOO_SOON:
1286     return "Unexpected EOF - invalid file";
1287
1288   default:
1289     sprintf(msg, "Unknown giflib error code %d", code);
1290     return msg;
1291   }
1292 }
1293
1294 /*
1295 =item gif_push_error()
1296
1297 Utility function that takes the current GIF error code, converts it to
1298 an error message and pushes it on the error stack.
1299
1300 =cut
1301 */
1302
1303 static void gif_push_error() {
1304   int code = GifLastError(); /* clears saved error */
1305
1306   i_push_error(code, gif_error_msg(code));
1307 }
1308
1309 /*
1310 =head1 BUGS
1311
1312 The Netscape loop extension isn't implemented.  Giflib's extension
1313 writing code doesn't seem to support writing named extensions in this 
1314 form.
1315
1316 A bug in giflib is tickled by the i_writegif_callback().  This isn't a
1317 problem on ungiflib, but causes a SEGV on giflib.  A patch is provided
1318 in t/t10formats.t
1319
1320 The GIF file tag (GIF87a vs GIF89a) currently isn't set.  Using the
1321 supplied interface in giflib 4.1.0 causes a SEGV in
1322 EGifSetGifVersion().  See L<gif_set_version> for an explanation.
1323
1324 =head1 AUTHOR
1325
1326 Arnar M. Hrafnkelsson, addi@umich.edu
1327
1328 =head1 SEE ALSO
1329
1330 perl(1), Imager(3)
1331
1332 =cut
1333
1334 */