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