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