]> git.imager.perl.org - imager.git/blobdiff - quant.c
- correct documentation of default of raw image interleave read
[imager.git] / quant.c
diff --git a/quant.c b/quant.c
index 2c11a5580bc98dec1ceffbdfcbfc924d7d70fe22..52942d10c3d3e31642fbefd995a8389c4b3d51ab 100644 (file)
--- a/quant.c
+++ b/quant.c
@@ -2,10 +2,11 @@
    currently only used by gif.c, but maybe we'll support producing 
    8-bit (or bigger indexed) png files at some point
 */
-#include "image.h"
+#include "imager.h"
 
 static void makemap_addi(i_quantize *, i_img **imgs, int count);
 static void makemap_mediancut(i_quantize *, i_img **imgs, int count);
+static void makemap_mono(i_quantize *);
 
 static
 void
@@ -26,8 +27,20 @@ setcol(i_color *cl,unsigned char r,unsigned char g,unsigned char b,unsigned char
    handle multiple colour maps.
 */
 
+/*
+=item i_quant_makemap(quant, imgs, count)
+
+=category Image quantization
+
+Analyzes the I<count> images in I<imgs> according to the rules in
+I<quant> to build a color map (optimal or not depending on
+quant->make_colors).
+
+=cut
+*/
+
 void
-quant_makemap(i_quantize *quant, i_img **imgs, int count) {
+i_quant_makemap(i_quantize *quant, i_img **imgs, int count) {
 
   if (quant->translate == pt_giflib) {
     /* giflib does it's own color table generation */
@@ -50,7 +63,7 @@ quant_makemap(i_quantize *quant, i_img **imgs, int count) {
       for (r = 0; r < 256; r+=0x33)
        for (g = 0; g < 256; g+=0x33)
          for (b = 0; b < 256; b += 0x33)
-           setcol(quant->mc_colors+i++, r, g, b, 0);
+           setcol(quant->mc_colors+i++, r, g, b, 255);
       quant->mc_count = i;
     }
     break;
@@ -59,6 +72,10 @@ quant_makemap(i_quantize *quant, i_img **imgs, int count) {
     makemap_mediancut(quant, imgs, count);
     break;
 
+  case mc_mono:
+    makemap_mono(quant);
+    break;
+
   case mc_addi:
   default:
     makemap_addi(quant, imgs, count);
@@ -66,22 +83,49 @@ quant_makemap(i_quantize *quant, i_img **imgs, int count) {
   }
 }
 
-#ifdef HAVE_LIBGIF
-static void translate_giflib(i_quantize *, i_img *, i_palidx *);
-#endif
 static void translate_closest(i_quantize *, i_img *, i_palidx *);
 static void translate_errdiff(i_quantize *, i_img *, i_palidx *);
 static void translate_addi(i_quantize *, i_img *, i_palidx *);
 
-/* Quantize the image given the palette in quant.
+/*
+=item i_quant_translate(quant, img)
+
+=category Image quantization
 
-   The giflib quantizer ignores the palette.
+Quantize the image given the palette in quant.
+
+On success returns a pointer to a memory block of img->xsize *
+img->ysize i_palidx entries.
+
+On failure returns NULL.
+
+You should call myfree() on the returned block when you're done with
+it.
+
+This function will fail if the supplied palette contains no colors.
+
+=cut
 */
-i_palidx *quant_translate(i_quantize *quant, i_img *img) {
+i_palidx *
+i_quant_translate(i_quantize *quant, i_img *img) {
   i_palidx *result;
+  int bytes;
+
   mm_log((1, "quant_translate(quant %p, img %p)\n", quant, img));
 
-  result = mymalloc(img->xsize * img->ysize);
+  /* there must be at least one color in the paletted (though even that
+     isn't very useful */
+  if (quant->mc_count == 0) {
+    i_push_error(0, "no colors available for translation");
+    return NULL;
+  }
+
+  bytes = img->xsize * img->ysize;
+  if (bytes / img->ysize != img->xsize) {
+    i_push_error(0, "integer overflow calculating memory allocation");
+    return NULL;
+  }
+  result = mymalloc(bytes);
 
   switch (quant->translate) {
   case pt_closest:
@@ -102,162 +146,6 @@ i_palidx *quant_translate(i_quantize *quant, i_img *img) {
   return result;
 }
 
-#ifdef HAVE_LIBGIF_THIS_NOT_USED
-
-#include "gif_lib.h"
-
-#define GET_RGB(im, x, y, ri, gi, bi, col) \
-        i_gpix((im),(x),(y),&(col)); (ri)=(col).rgb.r; \
-        if((im)->channels==3) { (bi)=(col).rgb.b; (gi)=(col).rgb.g; }
-
-static int 
-quant_replicate(i_img *im, i_palidx *output, i_quantize *quant);
-
-
-/* Use the gif_lib quantization functions to quantize the image */
-static void translate_giflib(i_quantize *quant, i_img *img, i_palidx *out) {
-  int x,y,ColorMapSize,colours_in;
-  unsigned long Size;
-  int i;
-
-  GifByteType *RedBuffer = NULL, *GreenBuffer = NULL, *BlueBuffer = NULL;
-  GifByteType *RedP, *GreenP, *BlueP;
-  ColorMapObject *OutputColorMap = NULL;
-  
-  i_color col;
-
-  mm_log((1,"translate_giflib(quant %p, img %p, out %p)\n", quant, img, out));
-  
-  /*if (!(im->channels==1 || im->channels==3)) { fprintf(stderr,"Unable to write gif, improper colorspace.\n"); exit(3); }*/
-  
-  ColorMapSize = quant->mc_size;
-  
-  Size = ((long) img->xsize) * img->ysize * sizeof(GifByteType);
-  
-  
-  if ((OutputColorMap = MakeMapObject(ColorMapSize, NULL)) == NULL)
-    m_fatal(0,"Failed to allocate memory for Output colormap.");
-  /*  if ((OutputBuffer = (GifByteType *) mymalloc(im->xsize * im->ysize * sizeof(GifByteType))) == NULL)
-      m_fatal(0,"Failed to allocate memory for output buffer.");*/
-  
-  /* ******************************************************* */
-  /* count the number of colours in the image */
-  colours_in=i_count_colors(img, OutputColorMap->ColorCount);
-  
-  if(colours_in != -1) {                /* less then the number wanted */
-                                        /* so we copy them over as-is */
-    mm_log((2,"image has %d colours, which fits in %d.  Copying\n",
-                    colours_in,ColorMapSize));
-    quant_replicate(img, out, quant);
-    /* saves the colors, so don't fall through */
-    return;
-  } else {
-
-    mm_log((2,"image has %d colours, more then %d.  Quantizing\n",colours_in,ColorMapSize));
-
-    if (img->channels >= 3) {
-      if ((RedBuffer   = (GifByteType *) mymalloc((unsigned int) Size)) == NULL) {
-        m_fatal(0,"Failed to allocate memory required, aborted.");
-        return;
-      }
-      if ((GreenBuffer = (GifByteType *) mymalloc((unsigned int) Size)) == NULL) {
-        m_fatal(0,"Failed to allocate memory required, aborted.");
-        myfree(RedBuffer);
-        return;
-      }
-    
-      if ((BlueBuffer  = (GifByteType *) mymalloc((unsigned int) Size)) == NULL) {
-        m_fatal(0,"Failed to allocate memory required, aborted.");
-        myfree(RedBuffer);
-        myfree(GreenBuffer);
-        return;
-      }
-    
-      RedP = RedBuffer;
-      GreenP = GreenBuffer;
-      BlueP = BlueBuffer;
-    
-      for (y=0; y< img->ysize; y++) for (x=0; x < img->xsize; x++) {
-        i_gpix(img,x,y,&col);
-        *RedP++ = col.rgb.r;
-        *GreenP++ = col.rgb.g;
-        *BlueP++ = col.rgb.b;
-      }
-    
-    } else {
-
-      if ((RedBuffer = (GifByteType *) mymalloc((unsigned int) Size))==NULL) {
-        m_fatal(0,"Failed to allocate memory required, aborted.");
-        return;
-      }
-
-      GreenBuffer=BlueBuffer=RedBuffer;
-      RedP = RedBuffer;
-      for (y=0; y< img->ysize; y++) for (x=0; x < img->xsize; x++) {
-        i_gpix(img,x,y,&col);
-        *RedP++ = col.rgb.r;
-      }
-    }
-
-    if (QuantizeBuffer(img->xsize, img->ysize, &ColorMapSize, RedBuffer, GreenBuffer, BlueBuffer,
-                    out, OutputColorMap->Colors) == GIF_ERROR) {
-        mm_log((1,"Error in QuantizeBuffer, unable to write image.\n"));
-    }
-  }
-
-  myfree(RedBuffer);
-  if (img->channels == 3) { myfree(GreenBuffer); myfree(BlueBuffer); }
-
-  /* copy over the color map */
-  for (i = 0; i < ColorMapSize; ++i) {
-    quant->mc_colors[i].rgb.r = OutputColorMap->Colors[i].Red;
-    quant->mc_colors[i].rgb.g = OutputColorMap->Colors[i].Green;
-    quant->mc_colors[i].rgb.b = OutputColorMap->Colors[i].Blue;
-  }
-  quant->mc_count = ColorMapSize;
-}
-
-static
-int
-quant_replicate(i_img *im, GifByteType *output, i_quantize *quant) {
-  int x, y, alloced, r, g=0, b=0, idx ;
-  i_color col;
-  
-  alloced=0;
-  for(y=0; y<im->ysize; y++) {
-    for(x=0; x<im->xsize; x++) {
-      
-      GET_RGB(im, x,y, r,g,b, col);       
-      
-      for(idx=0; idx<alloced; idx++) {   /* linear search for an index */
-       if(quant->mc_colors[idx].rgb.r==r &&
-          quant->mc_colors[idx].rgb.g==g &&
-          quant->mc_colors[idx].rgb.b==b) {
-         break;
-       }
-      }             
-      
-      if(idx >= alloced) {                /* if we haven't already, we */
-       idx=alloced++;                  /* add the colour to the map */
-       if(quant->mc_size < alloced) {
-         mm_log((1,"Tried to allocate more then %d colours.\n", 
-                 quant->mc_size));
-         return 0;
-       }
-       quant->mc_colors[idx].rgb.r=r;
-       quant->mc_colors[idx].rgb.g=g;
-       quant->mc_colors[idx].rgb.b=b;                
-      }
-      *output=idx;                        /* fill output buffer */
-      output++;                           /* with colour indexes */
-    }
-  }
-  quant->mc_count = alloced;
-  return 1;
-}
-
-#endif
-
 static void translate_closest(i_quantize *quant, i_img *img, i_palidx *out) {
   quant->perturb = 0;
   translate_addi(quant, img, out);
@@ -321,9 +209,11 @@ frand(void) {
   return rand()/(RAND_MAX+1.0);
 }
 
+#ifdef NOTEF
 static
 int
 eucl_d(cvec* cv,i_color *cl) { return PWR2(cv->r-cl->channel[0])+PWR2(cv->g-cl->channel[1])+PWR2(cv->b-cl->channel[2]); }
+#endif
 
 static
 int
@@ -403,6 +293,9 @@ makemap_addi(i_quantize *quant, i_img **imgs, int count) {
   i_sample_t *line;
   const int *sample_indices;
 
+  mm_log((1, "makemap_addi(quant %p { mc_count=%d, mc_colors=%p }, imgs %p, count %d)\n", 
+          quant, quant->mc_count, quant->mc_colors, imgs, count));
+         
   i_mempool_init(&mp);
 
   clr = i_mempool_alloc(&mp, sizeof(cvec) * quant->mc_size);
@@ -416,6 +309,10 @@ makemap_addi(i_quantize *quant, i_img **imgs, int count) {
   }
   /* mymalloc doesn't clear memory, so I think we need this */
   for (; i < quant->mc_size; ++i) {
+    /*clr[i].r = clr[i].g = clr[i].b = 0;*/
+    clr[i].dr = 0;
+    clr[i].dg = 0;
+    clr[i].db = 0;
     clr[i].fixed = 0;
     clr[i].mcount = 0;
   }
@@ -538,6 +435,12 @@ makemap_addi(i_quantize *quant, i_img **imgs, int count) {
   quant->mc_count = cnum;
 #endif
 
+#if 0
+  mm_log((1, "makemap_addi returns - quant.mc_count = %d\n", quant->mc_count));
+  for (i = 0; i < quant->mc_count; ++i)
+    mm_log((5, "  map entry %d: (%d, %d, %d)\n", i, clr[i].r, clr[i].g, clr[i].b));
+#endif
+
   i_mempool_destroy(&mp);
 }
 
@@ -718,7 +621,8 @@ makemap_mediancut(i_quantize *quant, i_img **imgs, int count) {
     color_count = 1;
     
     while (color_count < quant->mc_size) {
-      int max_index, max_ch; /* index/channel with biggest spread */
+      /* initialized to avoid compiler warnings */
+      int max_index = 0, max_ch = 0; /* index/channel with biggest spread */
       int max_size;
       medcut_partition *workpart;
       int cum_total;
@@ -798,6 +702,19 @@ makemap_mediancut(i_quantize *quant, i_img **imgs, int count) {
   i_mempool_destroy(&mp);
 }
 
+static void
+makemap_mono(i_quantize *quant) {
+  quant->mc_colors[0].rgba.r = 0;
+  quant->mc_colors[0].rgba.g = 0;
+  quant->mc_colors[0].rgba.b = 0;
+  quant->mc_colors[0].rgba.a = 255;
+  quant->mc_colors[1].rgba.r = 255;
+  quant->mc_colors[1].rgba.g = 255;
+  quant->mc_colors[1].rgba.b = 255;
+  quant->mc_colors[1].rgba.a = 255;
+  quant->mc_count = 2;
+}
+
 #define pboxjump 32
 
 /* Define one of the following 4 symbols to choose a colour search method
@@ -876,7 +793,7 @@ static int distcomp(void const *a, void const *b) {
    welcome.
  */
 static void hbsetup(i_quantize *quant, hashbox *hb) {
-  long *dists, mind, maxd, cd;
+  long *dists, mind, maxd;
   int cr, cb, cg, hbnum, i;
   i_color cenc;
 #ifdef HB_SORT
@@ -1189,7 +1106,7 @@ static int rand2dist_find(i_color val, i_quantize *quant, i_dists *dists, int in
 #endif
 
 static void translate_addi(i_quantize *quant, i_img *img, i_palidx *out) {
-  int x, y, i, k, bst_idx;
+  int x, y, i, k, bst_idx = 0;
   i_color val;
   int pixdev = quant->perturb;
   CF_VARS;
@@ -1286,9 +1203,7 @@ translate_errdiff(i_quantize *quant, i_img *img, i_palidx *out) {
   int errw;
   int difftotal;
   int x, y, dx, dy;
-  int minr, maxr, ming, maxg, minb, maxb, cr, cg, cb;
-  i_color find;
-  int bst_idx;
+  int bst_idx = 0;
   CF_VARS;
 
   if ((quant->errdiff & ed_mask) == ed_custom) {
@@ -1570,7 +1485,21 @@ static void transparent_threshold(i_quantize *, i_palidx *, i_img *, i_palidx);
 static void transparent_errdiff(i_quantize *, i_palidx *, i_img *, i_palidx);
 static void transparent_ordered(i_quantize *, i_palidx *, i_img *, i_palidx);
 
-void quant_transparent(i_quantize *quant, i_palidx *data, i_img *img,
+/*
+=item i_quant_transparent(quant, data, img, trans_index)
+
+=category Image quantization
+
+Dither the alpha channel on I<img> into the palette indexes in
+I<data>.  Pixels to be transparent are replaced with I<trans_pixel>.
+
+The method used depends on the tr_* members of quant.
+
+=cut
+*/
+
+void 
+i_quant_transparent(i_quantize *quant, i_palidx *data, i_img *img,
                       i_palidx trans_index)
 {
   switch (quant->transp) {