]> git.imager.perl.org - imager.git/blobdiff - gif.c
Fixed missing myfree() in bmp.c.
[imager.git] / gif.c
diff --git a/gif.c b/gif.c
index 5d82b41f28ad14dbf6c83c7b2a3b7d784da1724b..bb981c73af555361184fe12ac156b451c7d8abd7 100644 (file)
--- a/gif.c
+++ b/gif.c
@@ -177,7 +177,7 @@ i_readgif_low(GifFileType *GifFile, int **colour_table, int *colours) {
 
   Size = GifFile->SWidth * sizeof(GifPixelType); 
   
-  GifRow = (GifRowType) mymalloc(Size);
+  GifRow = mymalloc(Size);
 
   for (i = 0; i < GifFile->SWidth; i++) GifRow[i] = GifFile->SBackGroundColor;
   
@@ -190,6 +190,7 @@ i_readgif_low(GifFileType *GifFile, int **colour_table, int *colours) {
        myfree(*colour_table);
        *colour_table = NULL;
       }
+      myfree(GifRow);
       i_img_destroy(im);
       DGifCloseFile(GifFile);
       return NULL;
@@ -204,6 +205,7 @@ i_readgif_low(GifFileType *GifFile, int **colour_table, int *colours) {
          myfree(*colour_table);
          *colour_table = NULL;
        }
+       myfree(GifRow);
        i_img_destroy(im);
        DGifCloseFile(GifFile);
        return NULL;
@@ -221,6 +223,7 @@ i_readgif_low(GifFileType *GifFile, int **colour_table, int *colours) {
        mm_log((1, "Going in with no colormap\n"));
        i_push_error(0, "Image does not have a local or a global color map");
        /* we can't have allocated a colour table here */
+       myfree(GifRow);
        i_img_destroy(im);
        DGifCloseFile(GifFile);
        return NULL;
@@ -240,9 +243,10 @@ i_readgif_low(GifFileType *GifFile, int **colour_table, int *colours) {
          myfree(*colour_table);
          *colour_table = NULL;
        }
+       myfree(GifRow);
        i_img_destroy(im);
        DGifCloseFile(GifFile);
-       return(0);
+       return NULL;
       }
       if (GifFile->Image.Interlace) {
 
@@ -255,6 +259,7 @@ i_readgif_low(GifFileType *GifFile, int **colour_table, int *colours) {
              myfree(*colour_table);
              *colour_table = NULL;
            }
+           myfree(GifRow);
            i_img_destroy(im);
            DGifCloseFile(GifFile);
            return NULL;
@@ -279,6 +284,7 @@ i_readgif_low(GifFileType *GifFile, int **colour_table, int *colours) {
              myfree(*colour_table);
              *colour_table = NULL;
            }
+           myfree(GifRow);
            i_img_destroy(im);
            DGifCloseFile(GifFile);
            return NULL;
@@ -304,6 +310,7 @@ i_readgif_low(GifFileType *GifFile, int **colour_table, int *colours) {
          myfree(*colour_table);
          *colour_table = NULL;
        }
+       myfree(GifRow);
        i_img_destroy(im);
        DGifCloseFile(GifFile);
        return NULL;
@@ -316,6 +323,7 @@ i_readgif_low(GifFileType *GifFile, int **colour_table, int *colours) {
            myfree(*colour_table);
            *colour_table = NULL;
          }
+         myfree(GifRow);
          i_img_destroy(im);
          DGifCloseFile(GifFile);
          return NULL;
@@ -471,7 +479,7 @@ standard.
 
 i_img **i_readgif_multi_low(GifFileType *GifFile, int *count) {
   i_img *img;
-  int i, j, Size, Row, Col, Width, Height, ExtCode, Count, x;
+  int i, j, Size, Width, Height, ExtCode, Count, x;
   int ImageNum = 0, BackGround = 0, ColorMapSize = 0;
   ColorMapObject *ColorMap;
  
@@ -542,6 +550,7 @@ i_img **i_readgif_multi_low(GifFileType *GifFile, int *count) {
         channels = 4;
       img = i_img_pal_new(Width, Height, channels, 256);
       /* populate the palette of the new image */
+      mm_log((1, "ColorMapSize %d\n", ColorMapSize));
       for (i = 0; i < ColorMapSize; ++i) {
         i_color col;
         col.rgba.r = ColorMap->Colors[i].Red;
@@ -580,7 +589,6 @@ i_img **i_readgif_multi_low(GifFileType *GifFile, int *count) {
       if (GifFile->Image.ColorMap) {
         i_tags_addn(&img->tags, "gif_localmap", 0, 1);
       }
-      
       if (got_gce) {
         if (trans_index >= 0)
           i_tags_addn(&img->tags, "gif_trans_index", 0, trans_index);
@@ -598,7 +606,8 @@ i_img **i_readgif_multi_low(GifFileType *GifFile, int *count) {
       }
 
       ImageNum++;
-      mm_log((1,"i_readgif_multi: Image %d at (%d, %d) [%dx%d]: \n",ImageNum, Col, Row, Width, Height));
+      mm_log((1,"i_readgif_multi_low: Image %d at (%d, %d) [%dx%d]: \n",
+             ImageNum, GifFile->Image.Left, GifFile->Image.Top, Width, Height));
 
       if (GifFile->Image.Left + GifFile->Image.Width > GifFile->SWidth ||
          GifFile->Image.Top + GifFile->Image.Height > GifFile->SHeight) {
@@ -607,6 +616,7 @@ i_img **i_readgif_multi_low(GifFileType *GifFile, int *count) {
        DGifCloseFile(GifFile);
        return(0);
       }
+            
       if (GifFile->Image.Interlace) {
        for (Count = i = 0; i < 4; i++) {
           for (j = InterlacedOffset[i]; j < Height; 
@@ -926,7 +936,7 @@ This function is only used with giflib 4 and higher.
 
 static int
 gif_read_callback(GifFileType *gft, GifByteType *buf, int length) {
-  return i_gen_reader((i_gen_read_data *)gft->UserData, buf, length);
+  return i_gen_reader((i_gen_read_data *)gft->UserData, (char*)buf, length);
 }
 
 #endif
@@ -1189,6 +1199,113 @@ static void gif_set_version(i_quantize *quant, i_gif_opts *opts) {
   */
 }
 
+static int 
+in_palette(i_color *c, i_quantize *quant, int size) {
+  int i;
+
+  for (i = 0; i < size; ++i) {
+    if (c->channel[0] == quant->mc_colors[i].channel[0]
+        && c->channel[1] == quant->mc_colors[i].channel[1]
+        && c->channel[2] == quant->mc_colors[i].channel[2]) {
+      return i;
+    }
+  }
+
+  return -1;
+}
+
+/*
+=item has_common_palette(imgs, count, quant, want_trans)
+
+Tests if all the given images are paletted and have a common palette,
+if they do it builds that palette.
+
+A possible improvement might be to eliminate unused colors in the
+images palettes.
+
+=cut */
+static int
+has_common_palette(i_img **imgs, int count, i_quantize *quant, int want_trans,
+                   i_gif_opts *opts) {
+  int size = quant->mc_count;
+  int i, j;
+  int imgn;
+  int x, y;
+  char used[256];
+
+  /* we try to build a common palette here, if we can manage that, then
+     that's the palette we use */
+  for (imgn = 0; imgn < count; ++imgn) {
+    if (imgs[imgn]->type != i_palette_type)
+      return 0;
+
+    if (opts->eliminate_unused) {
+      i_palidx *line = mymalloc(sizeof(i_palidx) * imgs[imgn]->xsize);
+      int x, y;
+      memset(used, 0, sizeof(used));
+
+      for (y = 0; y < imgs[imgn]->ysize; ++y) {
+        i_gpal(imgs[imgn], 0, imgs[imgn]->xsize, y, line);
+        for (x = 0; x < imgs[imgn]->xsize; ++x)
+          used[line[x]] = 1;
+      }
+
+      myfree(line);
+    }
+    else {
+      /* assume all are in use */
+      memset(used, 1, sizeof(used));
+    }
+
+    for (i = 0; i < i_colorcount(imgs[imgn]); ++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;
+          }
+        }
+      }
+    }
+  }
+
+  quant->mc_count = size;
+
+  return 1;
+}
+
+static i_palidx *
+quant_paletted(i_quantize *quant, i_img *img) {
+  i_palidx *data = mymalloc(sizeof(i_palidx) * img->xsize * img->ysize);
+  i_palidx *p = data;
+  i_palidx trans[256];
+  int i;
+  int x, y;
+
+  /* build a translation table */
+  for (i = 0; i < i_colorcount(img); ++i) {
+    i_color c;
+    i_getcolors(img, i, &c, 1);
+    trans[i] = in_palette(&c, quant, quant->mc_count);
+  }
+
+  for (y = 0; y < img->ysize; ++y) {
+    i_gpal(img, 0, img->xsize, y, data+img->xsize * y);
+    for (x = 0; x < img->xsize; ++x) {
+      *p = trans[*p];
+      ++p;
+    }
+  }
+
+  return data;
+}
+
 /*
 =item i_writegif_low(i_quantize *quant, GifFileType *gf, i_img **imgs, int count, i_gif_opts *opts)
 
@@ -1209,6 +1326,7 @@ i_writegif_low(i_quantize *quant, GifFileType *gf, i_img **imgs, int count,
   int scrw = 0, scrh = 0;
   int imgn, orig_count, orig_size;
   int posx, posy;
+  int trans_index;
 
   mm_log((1, "i_writegif_low(quant %p, gf  %p, imgs %p, count %d, opts %p)\n", 
          quant, gf, imgs, count, opts));
@@ -1224,7 +1342,7 @@ i_writegif_low(i_quantize *quant, GifFileType *gf, i_img **imgs, int count,
     if (imgn < opts->position_count) {
       if (imgs[imgn]->xsize + opts->positions[imgn].x > scrw)
        scrw = imgs[imgn]->xsize + opts->positions[imgn].x;
-      if (imgs[imgn]->ysize + opts->positions[imgn].y > scrw)
+      if (imgs[imgn]->ysize + opts->positions[imgn].y > scrh)
        scrh = imgs[imgn]->ysize + opts->positions[imgn].y;
     }
     else {
@@ -1257,12 +1375,18 @@ i_writegif_low(i_quantize *quant, GifFileType *gf, i_img **imgs, int count,
 
     /* we always generate a global palette - this lets systems with a 
        broken giflib work */
-    quant_makemap(quant, imgs, 1);
-    result = quant_translate(quant, imgs[0]);
+    if (has_common_palette(imgs, 1, quant, want_trans, opts)) {
+      result = quant_paletted(quant, imgs[0]);
+    }
+    else {
+      quant_makemap(quant, imgs, 1);
+      result = quant_translate(quant, imgs[0]);
+    }
+    if (want_trans) {
+      trans_index = quant->mc_count;
+      quant_transparent(quant, result, imgs[0], trans_index);
+    }
 
-    if (want_trans)
-      quant_transparent(quant, result, imgs[0], quant->mc_count);
-    
     if ((map = make_gif_map(quant, opts, want_trans)) == NULL) {
       myfree(result);
       EGifCloseFile(gf);
@@ -1288,7 +1412,7 @@ i_writegif_low(i_quantize *quant, GifFileType *gf, i_img **imgs, int count,
     if (!do_ns_loop(gf, opts))
       return 0;
 
-    if (!do_gce(gf, 0, opts, want_trans, quant->mc_count)) {
+    if (!do_gce(gf, 0, opts, want_trans, trans_index)) {
       myfree(result);
       EGifCloseFile(gf);
       return 0;
@@ -1312,6 +1436,7 @@ i_writegif_low(i_quantize *quant, GifFileType *gf, i_img **imgs, int count,
       myfree(result);
       return 0;
     }
+    myfree(result);
     for (imgn = 1; imgn < count; ++imgn) {
       quant->mc_count = orig_count;
       quant->mc_size = orig_size;
@@ -1325,11 +1450,18 @@ i_writegif_low(i_quantize *quant, GifFileType *gf, i_img **imgs, int count,
       if (want_trans && quant->mc_size == 256)
        --quant->mc_size;
 
-      quant_makemap(quant, imgs+imgn, 1);
-      result = quant_translate(quant, imgs[imgn]);
-      if (want_trans)
-       quant_transparent(quant, result, imgs[imgn], quant->mc_count);
-      
+      if (has_common_palette(imgs+imgn, 1, quant, want_trans, opts)) {
+        result = quant_paletted(quant, imgs[imgn]);
+      }
+      else {
+        quant_makemap(quant, imgs+imgn, 1);
+        result = quant_translate(quant, imgs[imgn]);
+      }
+      if (want_trans) {
+        quant_transparent(quant, result, imgs[imgn], quant->mc_count);
+        trans_index = quant->mc_count;
+      }
+
       if (!do_gce(gf, imgn, opts, want_trans, quant->mc_count)) {
        myfree(result);
        EGifCloseFile(gf);
@@ -1370,6 +1502,7 @@ i_writegif_low(i_quantize *quant, GifFileType *gf, i_img **imgs, int count,
   }
   else {
     int want_trans;
+    int do_quant_paletted = 0;
 
     /* get a palette entry for the transparency iff we have an image
        with an alpha channel */
@@ -1390,8 +1523,14 @@ i_writegif_low(i_quantize *quant, GifFileType *gf, i_img **imgs, int count,
        the colormap. */
      
     /* produce a colour map */
-    quant_makemap(quant, imgs, count);
-    result = quant_translate(quant, imgs[0]);
+    if (has_common_palette(imgs, count, quant, want_trans, opts)) {
+      result = quant_paletted(quant, imgs[0]);
+      ++do_quant_paletted;
+    }
+    else {
+      quant_makemap(quant, imgs, count);
+      result = quant_translate(quant, imgs[0]);
+    }
 
     if ((map = make_gif_map(quant, opts, want_trans)) == NULL) {
       myfree(result);
@@ -1448,7 +1587,10 @@ i_writegif_low(i_quantize *quant, GifFileType *gf, i_img **imgs, int count,
 
     for (imgn = 1; imgn < count; ++imgn) {
       int local_trans;
-      result = quant_translate(quant, imgs[imgn]);
+      if (do_quant_paletted)
+        result = quant_paletted(quant, imgs[imgn]);
+      else
+        result = quant_translate(quant, imgs[imgn]);
       local_trans = want_trans && imgs[imgn]->channels == 4;
       if (local_trans)
        quant_transparent(quant, result, imgs[imgn], quant->mc_count);
@@ -1540,7 +1682,7 @@ static int gif_writer_callback(GifFileType *gf, const GifByteType *data, int siz
 {
   i_gen_write_data *gwd = (i_gen_write_data *)gf->UserData;
 
-  return i_gen_writer(gwd, data, size) ? size : 0;
+  return i_gen_writer(gwd, (char*)data, size) ? size : 0;
 }
 
 #endif