]> git.imager.perl.org - imager.git/blobdiff - GIF/imgif.c
avoid i_push_errorf() and i_fatal() in a few more places
[imager.git] / GIF / imgif.c
index 056141971bc78f794cd36cf18f4b6e049e691bc7..78f6554e4fb4fdf36fd67d64f844da9b0ea10ac7 100644 (file)
@@ -7,11 +7,13 @@
 #endif
 #include <errno.h>
 #include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
 
 /*
 =head1 NAME
 
-gif.c - read and write gif files for Imager
+imgif.c - read and write gif files for Imager
 
 =head1 SYNOPSIS
 
@@ -60,8 +62,6 @@ functionality with giflib3.
 static char const *gif_error_msg(int code);
 static void gif_push_error(void);
 
-static int gif_read_callback(GifFileType *gft, GifByteType *buf, int length);
-
 /* Make some variables global, so we could access them faster: */
 
 static int
@@ -91,11 +91,33 @@ i_colortable_copy(int **colour_table, int *colours, ColorMapObject *colourmap) {
   }
 }
 
-long
+#ifdef GIF_LIB_VERSION
+
+static const
+char gif_version_str[] = GIF_LIB_VERSION;
+
+double
 i_giflib_version(void) {
-  return 10;
+  const char *p = gif_version_str;
+
+  while (*p && (*p < '0' || *p > '9'))
+    ++p;
+
+  if (!*p)
+    return 0;
+
+  return strtod(p, NULL);
 }
 
+#else
+
+double
+i_giflib_version(void) {
+  return GIFLIB_MAJOR + GIFLIB_MINOR * 0.1;
+}
+
+#endif
+
 /*
 =item i_readgif_low(GifFileType *GifFile, int **colour_table, int *colours)
 
@@ -841,7 +863,7 @@ static int
 io_glue_read_cb(GifFileType *gft, GifByteType *buf, int length) {
   io_glue *ig = (io_glue *)gft->UserData;
 
-  return ig->readcb(ig, buf, length);
+  return i_io_read(ig, buf, length);
 }
 
 i_img *
@@ -901,15 +923,14 @@ Returns NULL if the page isn't found.
 
 i_img *
 i_readgif_single_wiol(io_glue *ig, int page) {
-  i_clear_error();
+  GifFileType *GifFile;
 
+  i_clear_error();
   if (page < 0) {
     i_push_error(0, "page must be non-negative");
     return NULL;
   }
 
-  GifFileType *GifFile;
-
   if ((GifFile = DGifOpen((void *)ig, io_glue_read_cb )) == NULL) {
     gif_push_error();
     i_push_error(0, "Cannot create giflib callback object");
@@ -1026,7 +1047,11 @@ static int do_comments(GifFileType *gf, i_img *img) {
     }
     else {
       char buf[50];
+#ifdef IMAGER_SNPRINTF
+      snprintf(buf, sizeof(buf), "%d", img->tags.tags[pos].idata);
+#else
       sprintf(buf, "%d", img->tags.tags[pos].idata);
+#endif
       if (EGifPutComment(gf, buf) == GIF_ERROR) {
         return 0;
       }
@@ -1217,23 +1242,25 @@ in_palette(i_color *c, i_quantize *quant, int size) {
 }
 
 /*
-=item has_common_palette(imgs, count, quant, want_trans)
+=item has_common_palette(imgs, count, quant)
 
-Tests if all the given images are paletted and have a common palette,
-if they do it builds that palette.
+Tests if all the given images are paletted and their colors are in the
+palette produced.
 
-A possible improvement might be to eliminate unused colors in the
-images palettes.
+Previously this would build a consolidated palette from the source,
+but that meant that if the caller supplied a static palette (or
+specified a fixed palette like "webmap") then we wouldn't be
+quantizing to the caller specified palette.
 
 =cut
 */
+
 static int
-has_common_palette(i_img **imgs, int count, i_quantize *quant, 
-                   int want_trans) {
-  int size = quant->mc_count;
+has_common_palette(i_img **imgs, int count, i_quantize *quant) {
   int i;
   int imgn;
   char used[256];
+  int col_count;
 
   /* we try to build a common palette here, if we can manage that, then
      that's the palette we use */
@@ -1265,25 +1292,22 @@ has_common_palette(i_img **imgs, int count, i_quantize *quant,
       memset(used, 1, sizeof(used));
     }
 
-    for (i = 0; i < i_colorcount(imgs[imgn]); ++i) {
+    col_count = i_colorcount(imgs[imgn]);
+    for (i = 0; i < col_count; ++i) {
       i_color c;
       
       i_getcolors(imgs[imgn], i, &c, 1);
       if (used[i]) {
-        if (in_palette(&c, quant, size) < 0) {
-          if (size < quant->mc_size) {
-            quant->mc_colors[size++] = c;
-          }
-          else {
-            /* oops, too many colors */
-            return 0;
-          }
+        if (in_palette(&c, quant, quant->mc_count) < 0) {
+         mm_log((1, "  color not found in palette, no palette shortcut\n"));
+  
+         return 0;
         }
       }
     }
   }
 
-  quant->mc_count = size;
+  mm_log((1, "  all colors found in palette, palette shortcut\n"));
 
   return 1;
 }
@@ -1294,7 +1318,7 @@ quant_paletted(i_quantize *quant, i_img *img) {
   i_palidx *p = data;
   i_palidx trans[256];
   int i;
-  int x, y;
+  i_img_dim x, y;
 
   /* build a translation table */
   for (i = 0; i < i_colorcount(img); ++i) {
@@ -1367,7 +1391,7 @@ i_writegif_low(i_quantize *quant, GifFileType *gf, i_img **imgs, int count) {
   if (!i_tags_get_int(&imgs[0]->tags, "gif_screen_width", 0, &scrw))
     scrw = 0;
   if (!i_tags_get_int(&imgs[0]->tags, "gif_screen_height", 0, &scrh))
-    scrw = 0;
+    scrh = 0;
 
   anylocal = 0;
   localmaps = mymalloc(sizeof(int) * count);
@@ -1375,26 +1399,39 @@ i_writegif_low(i_quantize *quant, GifFileType *gf, i_img **imgs, int count) {
   glob_img_count = 0;
   glob_want_trans = 0;
   for (imgn = 0; imgn < count; ++imgn) {
+    i_img *im = imgs[imgn];
+    if (im->xsize > 0xFFFF || im->ysize > 0xFFFF) {
+      i_push_error(0, "image too large for GIF");
+      return 0;
+    }
+    
     posx = posy = 0;
-    i_tags_get_int(&imgs[imgn]->tags, "gif_left", 0, &posx);
-    i_tags_get_int(&imgs[imgn]->tags, "gif_top", 0, &posy);
-    if (imgs[imgn]->xsize + posx > scrw)
-      scrw = imgs[imgn]->xsize + posx;
-    if (imgs[imgn]->ysize + posy > scrh)
-      scrh = imgs[imgn]->ysize + posy;
-    if (!i_tags_get_int(&imgs[imgn]->tags, "gif_local_map", 0, localmaps+imgn))
+    i_tags_get_int(&im->tags, "gif_left", 0, &posx);
+    if (posx < 0) posx = 0;
+    i_tags_get_int(&im->tags, "gif_top", 0, &posy);
+    if (posy < 0) posy = 0;
+    if (im->xsize + posx > scrw)
+      scrw = im->xsize + posx;
+    if (im->ysize + posy > scrh)
+      scrh = im->ysize + posy;
+    if (!i_tags_get_int(&im->tags, "gif_local_map", 0, localmaps+imgn))
       localmaps[imgn] = 0;
     if (localmaps[imgn])
       anylocal = 1;
     else {
-      if (imgs[imgn]->channels == 4) {
+      if (im->channels == 4) {
         glob_want_trans = 1;
       }
-      glob_imgs[glob_img_count++] = imgs[imgn];
+      glob_imgs[glob_img_count++] = im;
     }
   }
   glob_want_trans = glob_want_trans && quant->transp != tr_none ;
 
+  if (scrw > 0xFFFF || scrh > 0xFFFF) {
+    i_push_error(0, "screen size too large for GIF");
+    return 0;
+  }
+
   orig_count = quant->mc_count;
   orig_size = quant->mc_size;
 
@@ -1412,13 +1449,9 @@ i_writegif_low(i_quantize *quant, GifFileType *gf, i_img **imgs, int count) {
       mm_log((2, "  reserving color for transparency\n"));
       --quant->mc_size;
     }
-    if (has_common_palette(glob_imgs, glob_img_count, quant, want_trans)) {
-      glob_paletted = 1;
-    }
-    else {
-      glob_paletted = 0;
-      i_quant_makemap(quant, glob_imgs, glob_img_count);
-    }
+
+    i_quant_makemap(quant, glob_imgs, glob_img_count);
+    glob_paletted = has_common_palette(glob_imgs, glob_img_count, quant);
     glob_color_count = quant->mc_count;
     quant->mc_colors = orig_colors;
   }
@@ -1439,14 +1472,10 @@ i_writegif_low(i_quantize *quant, GifFileType *gf, i_img **imgs, int count) {
   }
   else {
     want_trans = quant->transp != tr_none && imgs[0]->channels == 4;
-    if (has_common_palette(imgs, 1, quant, want_trans)) {
-      colors_paletted = 1;
-    }
-    else {
-      colors_paletted = 0;
-      i_quant_makemap(quant, imgs, 1);
-    }
+    i_quant_makemap(quant, imgs, 1);
+    colors_paletted = has_common_palette(imgs, 1, quant);
   }
+
   if ((map = make_gif_map(quant, imgs[0], want_trans)) == NULL) {
     myfree(glob_colors);
     myfree(localmaps);
@@ -1513,13 +1542,8 @@ i_writegif_low(i_quantize *quant, GifFileType *gf, i_img **imgs, int count) {
          to give room for a transparency colour */
       if (want_trans && quant->mc_size == 256)
         --quant->mc_size;
-      if (has_common_palette(imgs, 1, quant, want_trans)) {
-        colors_paletted = 1;
-      }
-      else {
-        colors_paletted = 0;
-        i_quant_makemap(quant, imgs, 1);
-      }
+      i_quant_makemap(quant, imgs, 1);
+      colors_paletted = has_common_palette(imgs, 1, quant);
       if ((map = make_gif_map(quant, imgs[0], want_trans)) == NULL) {
        myfree(glob_colors);
        myfree(localmaps);
@@ -1627,7 +1651,7 @@ i_writegif_low(i_quantize *quant, GifFileType *gf, i_img **imgs, int count) {
       if (want_trans && quant->mc_size == 256)
        --quant->mc_size;
 
-      if (has_common_palette(imgs+imgn, 1, quant, want_trans)) {
+      if (has_common_palette(imgs+imgn, 1, quant)) {
         result = quant_paletted(quant, imgs[imgn]);
       }
       else {
@@ -1758,7 +1782,7 @@ static int
 io_glue_write_cb(GifFileType *gft, const GifByteType *data, int length) {
   io_glue *ig = (io_glue *)gft->UserData;
 
-  return ig->writecb(ig, data, length);
+  return i_io_write(ig, data, length);
 }
 
 
@@ -1786,7 +1810,8 @@ i_writegif_wiol(io_glue *ig, i_quantize *quant, i_img **imgs,
   
   result = i_writegif_low(quant, GifFile, imgs, count);
   
-  ig->closecb(ig);
+  if (i_io_close(ig))
+    return 0;
   
   return result;
 }
@@ -1877,7 +1902,11 @@ static char const *gif_error_msg(int code) {
     return "Unexpected EOF - invalid file";
 
   default:
+#ifdef IMAGER_SNPRINTF
+    snprintf(msg, sizeof(msg), "Unknown giflib error code %d", code);
+#else
     sprintf(msg, "Unknown giflib error code %d", code);
+#endif
     return msg;
   }
 }