]> git.imager.perl.org - imager.git/blob - gif.c
had broken handing for the giflib version
[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 #if 0
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 
692      directly to the fd.
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.
697   */
698   if (opts->loop_count) {
699     unsigned char nsle[15] = "NETSCAPE2.0";
700     nsle[11] = 3;
701     nsle[12] = 1;
702     nsle[13] = opts->loop_count % 256;
703     nsle[14] = opts->loop_count / 256;
704     return EGifPutExtension(gf, 0xFF, sizeof(nsle), nsle) != GIF_ERROR;
705   }
706 #endif
707   return 1;
708 }
709
710 /*
711 =item make_gif_map(i_quantize *quant, i_gif_opts *opts, int want_trans)
712
713 Create a giflib color map object from an Imager color map.
714
715 =cut
716 */
717
718 static ColorMapObject *make_gif_map(i_quantize *quant, i_gif_opts *opts,
719                                     int want_trans) {
720   GifColorType colors[256];
721   int i;
722   int size = quant->mc_count;
723   int map_size;
724   ColorMapObject *map;
725
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;
730   }
731   if (want_trans) {
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;
735     ++size;
736   }
737   map_size = 1;
738   while (map_size < size)
739     map_size <<= 1;
740   /* giflib spews for 1 colour maps, reasonable, I suppose */
741   if (map_size == 1)
742     map_size = 2;
743   map = MakeMapObject(map_size, colors);
744   if (!map) {
745     gif_push_error();
746     i_push_error(0, "Could not create color map object");
747     return NULL;
748   }
749   return map;
750 }
751
752 /*
753 =item gif_set_version(i_quantize *quant, i_gif_opts *opts)
754
755 We need to call EGifSetGifVersion() before opening the file - put that
756 common code here.
757
758 Unfortunately giflib 4.1.0 crashes when we use this.  Internally
759 giflib 4.1.0 has code:
760
761   static char *GifVersionPrefix = GIF87_STAMP;
762
763 and the code that sets the version internally does:
764
765   strncpy(&GifVersionPrefix[3], Version, 3);
766
767 which is very broken.
768
769 Failing to set the correct GIF version doesn't seem to cause a problem
770 with readers.
771
772 =cut
773 */
774
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
779      to distinguish them
780      if (opts->delay_count
781      || opts->user_input_count
782      || opts->disposal_count
783      || opts->loop_count
784      || quant->transp != tr_none)
785      EGifSetGifVersion("89a");
786      else
787      EGifSetGifVersion("87a");
788   */
789 }
790
791 /*
792 =item i_writegif_low(i_quantize *quant, GifFileType *gf, i_img **imgs, int count, i_gif_opts *opts)
793
794 Internal.  Low-level function that does the high-level GIF processing
795 :)
796
797 Returns non-zero on success.
798
799 =cut
800 */
801
802 static undef_int
803 i_writegif_low(i_quantize *quant, GifFileType *gf, i_img **imgs, int count,
804                i_gif_opts *opts) {
805   unsigned char *result;
806   int color_bits;
807   ColorMapObject *map;
808   int scrw = 0, scrh = 0;
809   int imgn, orig_count, orig_size;
810   int posx, posy;
811
812   mm_log((1, "i_writegif_low(quant %p, gf  %p, imgs %p, count %d, opts %p)\n", 
813           quant, gf, imgs, count, opts));
814
815   /**((char *)0) = 1;*/
816   /* sanity is nice */
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;
821
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;
828     }
829     else {
830       if (imgs[imgn]->xsize > scrw)
831         scrw = imgs[imgn]->xsize;
832       if (imgs[imgn]->ysize > scrh)
833         scrh = imgs[imgn]->ysize;
834     }
835   }
836
837   if (count <= 0) {
838     i_push_error(0, "No images provided to write");
839     return 0; /* what are you smoking? */
840   }
841
842   orig_count = quant->mc_count;
843   orig_size = quant->mc_size;
844
845   if (opts->each_palette) {
846     int want_trans = quant->transp != tr_none 
847       && imgs[0]->channels == 4;
848
849     /* if the caller gives us too many colours we can't do transparency */
850     if (want_trans && quant->mc_count == 256)
851       want_trans = 0;
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)
855       --quant->mc_size;
856
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]);
861
862     if (want_trans)
863       quant_transparent(quant, result, imgs[0], quant->mc_count);
864     
865     if ((map = make_gif_map(quant, opts, want_trans)) == NULL) {
866       myfree(result);
867       EGifCloseFile(gf);
868       mm_log((1, "Error in MakeMapObject."));
869       return 0;
870     }
871
872     color_bits = 1;
873     while (quant->mc_size > (1 << color_bits))
874       ++color_bits;
875   
876     if (EGifPutScreenDesc(gf, scrw, scrh, color_bits, 0, map) == GIF_ERROR) {
877       gif_push_error();
878       i_push_error(0, "Could not save screen descriptor");
879       FreeMapObject(map);
880       myfree(result);
881       EGifCloseFile(gf);
882       mm_log((1, "Error in EGifPutScreenDesc."));
883       return 0;
884     }
885     FreeMapObject(map);
886
887     if (!do_ns_loop(gf, opts))
888       return 0;
889
890     if (!do_gce(gf, 0, opts, want_trans, quant->mc_count)) {
891       myfree(result);
892       EGifCloseFile(gf);
893       return 0;
894     }
895     if (opts->position_count) {
896       posx = opts->positions[0].x;
897       posy = opts->positions[0].y;
898     }
899     else
900       posx = posy = 0;
901     if (EGifPutImageDesc(gf, posx, posy, imgs[0]->xsize, imgs[0]->ysize, 
902                          opts->interlace, NULL) == GIF_ERROR) {
903       gif_push_error();
904       i_push_error(0, "Could not save image descriptor");
905       EGifCloseFile(gf);
906       mm_log((1, "Error in EGifPutImageDesc."));
907       return 0;
908     }
909     if (!do_write(gf, opts, imgs[0], result)) {
910       EGifCloseFile(gf);
911       myfree(result);
912       return 0;
913     }
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)
921         want_trans = 0;
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)
925         --quant->mc_size;
926
927       quant_makemap(quant, imgs+imgn, 1);
928       result = quant_translate(quant, imgs[imgn]);
929       if (want_trans)
930         quant_transparent(quant, result, imgs[imgn], quant->mc_count);
931       
932       if (!do_gce(gf, imgn, opts, want_trans, quant->mc_count)) {
933         myfree(result);
934         EGifCloseFile(gf);
935         return 0;
936       }
937       if ((map = make_gif_map(quant, opts, want_trans)) == NULL) {
938         myfree(result);
939         EGifCloseFile(gf);
940         mm_log((1, "Error in MakeMapObject."));
941         return 0;
942       }
943       if (imgn < opts->position_count) {
944         posx = opts->positions[imgn].x;
945         posy = opts->positions[imgn].y;
946       }
947       else
948         posx = posy = 0;
949       if (EGifPutImageDesc(gf, posx, posy, imgs[imgn]->xsize, 
950                            imgs[imgn]->ysize, opts->interlace, 
951                            map) == GIF_ERROR) {
952         gif_push_error();
953         i_push_error(0, "Could not save image descriptor");
954         myfree(result);
955         FreeMapObject(map);
956         EGifCloseFile(gf);
957         mm_log((1, "Error in EGifPutImageDesc."));
958         return 0;
959       }
960       FreeMapObject(map);
961       
962       if (!do_write(gf, opts, imgs[imgn], result)) {
963         EGifCloseFile(gf);
964         myfree(result);
965         return 0;
966       }
967       myfree(result);
968     }
969   }
970   else {
971     int want_trans;
972
973     /* get a palette entry for the transparency iff we have an image
974        with an alpha channel */
975     want_trans = 0;
976     for (imgn = 0; imgn < count; ++imgn) {
977       if (imgs[imgn]->channels == 4) {
978         ++want_trans;
979         break;
980       }
981     }
982     want_trans = want_trans && quant->transp != tr_none 
983       && quant->mc_count < 256;
984     if (want_trans && quant->mc_size == 256)
985       --quant->mc_size;
986
987     /* handle the first image separately - since we allow giflib
988        conversion and giflib doesn't give us a separate function to build
989        the colormap. */
990      
991     /* produce a colour map */
992     quant_makemap(quant, imgs, count);
993     result = quant_translate(quant, imgs[0]);
994
995     if ((map = make_gif_map(quant, opts, want_trans)) == NULL) {
996       myfree(result);
997       EGifCloseFile(gf);
998       mm_log((1, "Error in MakeMapObject"));
999       return 0;
1000     }
1001     color_bits = 1;
1002     while (quant->mc_count > (1 << color_bits))
1003       ++color_bits;
1004
1005     if (EGifPutScreenDesc(gf, scrw, scrh, color_bits, 0, map) == GIF_ERROR) {
1006       gif_push_error();
1007       i_push_error(0, "Could not save screen descriptor");
1008       FreeMapObject(map);
1009       myfree(result);
1010       EGifCloseFile(gf);
1011       mm_log((1, "Error in EGifPutScreenDesc."));
1012       return 0;
1013     }
1014     FreeMapObject(map);
1015
1016     if (!do_ns_loop(gf, opts))
1017       return 0;
1018
1019     if (!do_gce(gf, 0, opts, want_trans, quant->mc_count)) {
1020       myfree(result);
1021       EGifCloseFile(gf);
1022       return 0;
1023     }
1024     if (opts->position_count) {
1025       posx = opts->positions[0].x;
1026       posy = opts->positions[0].y;
1027     }
1028     else
1029       posx = posy = 0;
1030     if (EGifPutImageDesc(gf, posx, posy, imgs[0]->xsize, imgs[0]->ysize, 
1031                          opts->interlace, NULL) == GIF_ERROR) {
1032       gif_push_error();
1033       i_push_error(0, "Could not save image descriptor");
1034       EGifCloseFile(gf);
1035       mm_log((1, "Error in EGifPutImageDesc."));
1036       return 0;
1037     }
1038     if (want_trans && imgs[0]->channels == 4) 
1039       quant_transparent(quant, result, imgs[0], quant->mc_count);
1040
1041     if (!do_write(gf, opts, imgs[0], result)) {
1042       EGifCloseFile(gf);
1043       myfree(result);
1044       return 0;
1045     }
1046     myfree(result);
1047
1048     for (imgn = 1; imgn < count; ++imgn) {
1049       int local_trans;
1050       result = quant_translate(quant, imgs[imgn]);
1051       local_trans = want_trans && imgs[imgn]->channels == 4;
1052       if (local_trans)
1053         quant_transparent(quant, result, imgs[imgn], quant->mc_count);
1054       if (!do_gce(gf, imgn, opts, local_trans, quant->mc_count)) {
1055         myfree(result);
1056         EGifCloseFile(gf);
1057         return 0;
1058       }
1059       if (imgn < opts->position_count) {
1060         posx = opts->positions[imgn].x;
1061         posy = opts->positions[imgn].y;
1062       }
1063       else
1064         posx = posy = 0;
1065       if (EGifPutImageDesc(gf, posx, posy, 
1066                            imgs[imgn]->xsize, imgs[imgn]->ysize, 
1067                            opts->interlace, NULL) == GIF_ERROR) {
1068         gif_push_error();
1069         i_push_error(0, "Could not save image descriptor");
1070         myfree(result);
1071         EGifCloseFile(gf);
1072         mm_log((1, "Error in EGifPutImageDesc."));
1073         return 0;
1074       }
1075       if (!do_write(gf, opts, imgs[imgn], result)) {
1076         EGifCloseFile(gf);
1077         myfree(result);
1078         return 0;
1079       }
1080       myfree(result);
1081     }
1082   }
1083   if (EGifCloseFile(gf) == GIF_ERROR) {
1084     gif_push_error();
1085     i_push_error(0, "Could not close GIF file");
1086     mm_log((1, "Error in EGifCloseFile\n"));
1087     return 0;
1088   }
1089
1090   return 1;
1091 }
1092
1093 /*
1094 =item i_writegif_gen(i_quantize *quant, int fd, i_img **imgs, int count, i_gif_opts *opts)
1095
1096 General high-level function to write a GIF to a file.
1097
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>.
1101
1102 Returns non-zero on success.
1103
1104 =cut
1105 */
1106
1107 undef_int
1108 i_writegif_gen(i_quantize *quant, int fd, i_img **imgs, int count, 
1109                i_gif_opts *opts) {
1110   GifFileType *gf;
1111
1112   i_clear_error();
1113   mm_log((1, "i_writegif_gen(quant %p, fd %d, imgs %p, count %d, opts %p)\n", 
1114           quant, fd, imgs, count, opts));
1115
1116   gif_set_version(quant, opts);
1117
1118   if ((gf = EGifOpenFileHandle(fd)) == NULL) {
1119     gif_push_error();
1120     i_push_error(0, "Cannot create GIF file object");
1121     mm_log((1, "Error in EGifOpenFileHandle, unable to write image.\n"));
1122     return 0;
1123   }
1124
1125   return i_writegif_low(quant, gf, imgs, count, opts);
1126 }
1127
1128 #if IM_GIFMAJOR >= 4
1129
1130 /*
1131 =item gif_writer_callback(GifFileType *gf, const GifByteType *data, int size)
1132
1133 Internal.  Wrapper for the user write callback function.
1134
1135 =cut
1136 */
1137
1138 static int gif_writer_callback(GifFileType *gf, const GifByteType *data, int size)
1139 {
1140   i_gen_write_data *gwd = (i_gen_write_data *)gf->UserData;
1141
1142   return i_gen_writer(gwd, data, size) ? size : 0;
1143 }
1144
1145 #endif
1146
1147 /*
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)
1149
1150 General high-level function to write a GIF using callbacks to send
1151 back the data.
1152
1153 Returns non-zero on success.
1154
1155 =cut
1156 */
1157
1158 undef_int
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)
1161 {
1162 #if IM_GIFMAJOR >= 4
1163   GifFileType *gf;
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);
1167   int result;
1168
1169   i_clear_error();
1170
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));
1173   
1174   if ((gf = EGifOpen(gwd, &gif_writer_callback)) == NULL) {
1175     gif_push_error();
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);
1179     return 0;
1180   }
1181
1182   result = i_writegif_low(quant, gf, imgs, count, opts);
1183   return free_gen_write_data(gwd, result);
1184 #else
1185   return 0;
1186 #endif
1187 }
1188
1189 /*
1190 =item gif_error_msg(int code)
1191
1192 Grabs the most recent giflib error code from GifLastError() and 
1193 returns a string that describes that error.
1194
1195 The returned pointer points to a static buffer, either from a literal
1196 C string or a static buffer.
1197
1198 =cut */
1199
1200 static char const *gif_error_msg(int code) {
1201   static char msg[80];
1202
1203   switch (code) {
1204   case E_GIF_ERR_OPEN_FAILED: /* should not see this */
1205     return "Failed to open given file";
1206     
1207   case E_GIF_ERR_WRITE_FAILED:
1208     return "Write failed";
1209
1210   case E_GIF_ERR_HAS_SCRN_DSCR: /* should not see this */
1211     return "Screen descriptor already passed to giflib";
1212
1213   case E_GIF_ERR_HAS_IMAG_DSCR: /* should not see this */
1214     return "Image descriptor already passed to giflib";
1215     
1216   case E_GIF_ERR_NO_COLOR_MAP: /* should not see this */
1217     return "Neither global nor local color map set";
1218
1219   case E_GIF_ERR_DATA_TOO_BIG: /* should not see this */
1220     return "Too much pixel data passed to giflib";
1221
1222   case E_GIF_ERR_NOT_ENOUGH_MEM:
1223     return "Out of memory";
1224     
1225   case E_GIF_ERR_DISK_IS_FULL:
1226     return "Disk is full";
1227     
1228   case E_GIF_ERR_CLOSE_FAILED: /* should not see this */
1229     return "File close failed";
1230  
1231   case E_GIF_ERR_NOT_WRITEABLE: /* should not see this */
1232     return "File not writable";
1233
1234   case D_GIF_ERR_OPEN_FAILED:
1235     return "Failed to open file";
1236     
1237   case D_GIF_ERR_READ_FAILED:
1238     return "Failed to read from file";
1239
1240   case D_GIF_ERR_NOT_GIF_FILE:
1241     return "File is not a GIF file";
1242
1243   case D_GIF_ERR_NO_SCRN_DSCR:
1244     return "No screen descriptor detected - invalid file";
1245
1246   case D_GIF_ERR_NO_IMAG_DSCR:
1247     return "No image descriptor detected - invalid file";
1248
1249   case D_GIF_ERR_NO_COLOR_MAP:
1250     return "No global or local color map found";
1251
1252   case D_GIF_ERR_WRONG_RECORD:
1253     return "Wrong record type detected - invalid file?";
1254
1255   case D_GIF_ERR_DATA_TOO_BIG:
1256     return "Data in file too big for image";
1257
1258   case D_GIF_ERR_NOT_ENOUGH_MEM:
1259     return "Out of memory";
1260
1261   case D_GIF_ERR_CLOSE_FAILED:
1262     return "Close failed";
1263
1264   case D_GIF_ERR_NOT_READABLE:
1265     return "File not opened for read";
1266
1267   case D_GIF_ERR_IMAGE_DEFECT:
1268     return "Defective image";
1269
1270   case D_GIF_ERR_EOF_TOO_SOON:
1271     return "Unexpected EOF - invalid file";
1272
1273   default:
1274     sprintf(msg, "Unknown giflib error code %d", code);
1275     return msg;
1276   }
1277 }
1278
1279 /*
1280 =item gif_push_error()
1281
1282 Utility function that takes the current GIF error code, converts it to
1283 an error message and pushes it on the error stack.
1284
1285 =cut
1286 */
1287
1288 static void gif_push_error() {
1289   int code = GifLastError(); /* clears saved error */
1290
1291   i_push_error(code, gif_error_msg(code));
1292 }
1293
1294 /*
1295 =head1 BUGS
1296
1297 The Netscape loop extension isn't implemented.  Giflib's extension
1298 writing code doesn't seem to support writing named extensions in this 
1299 form.
1300
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
1303 in t/t10formats.t
1304
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.
1308
1309 =head1 AUTHOR
1310
1311 Arnar M. Hrafnkelsson, addi@umich.edu
1312
1313 =head1 SEE ALSO
1314
1315 perl(1), Imager(3)
1316
1317 =cut
1318
1319 */