X-Git-Url: http://git.imager.perl.org/imager.git/blobdiff_plain/18accb2acf8562f8c69d23f7b9523f6194d641c9..e17b7029eb8e9c20f30e5208de1f49d243fa514c:/quant.c diff --git a/quant.c b/quant.c index be67662e..13096ccc 100644 --- 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(C, C, C) + +=category Image quantization + +Analyzes the C images in C according to the rules in +C to build a color map (optimal or not depending on +C<< 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(C, C) + +=category Image quantization - The giflib quantizer ignores the palette. +Quantize the image given the palette in C. + +On success returns a pointer to a memory block of C<< img->xsize * +img->ysize >> C 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; yysize; y++) { - for(x=0; xxsize; x++) { - - GET_RGB(im, x,y, r,g,b, col); - - for(idx=0; idxmc_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) { @@ -1525,9 +1440,9 @@ maxdist(int boxnum,cvec *cv) { bbox(boxnum,&r0,&r1,&g0,&g1,&b0,&b1); - mr=max(abs(b-b0),abs(b-b1)); - mg=max(abs(g-g0),abs(g-g1)); - mb=max(abs(r-r0),abs(r-r1)); + mr=i_max(abs(b-b0),abs(b-b1)); + mg=i_max(abs(g-g0),abs(g-g1)); + mb=i_max(abs(r-r0),abs(r-r1)); return PWR2(mr)+PWR2(mg)+PWR2(mb); } @@ -1547,9 +1462,9 @@ mindist(int boxnum,cvec *cv) { if (r0<=r && r<=r1 && g0<=g && g<=g1 && b0<=b && b<=b1) return 0; - mr=min(abs(b-b0),abs(b-b1)); - mg=min(abs(g-g0),abs(g-g1)); - mb=min(abs(r-r0),abs(r-r1)); + mr=i_min(abs(b-b0),abs(b-b1)); + mg=i_min(abs(g-g0),abs(g-g1)); + mb=i_min(abs(r-r0),abs(r-r1)); mr=PWR2(mr); mg=PWR2(mg); @@ -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(C, C, C, C) + +=category Image quantization + +Dither the alpha channel on C into the palette indexes in +C. Pixels to be transparent are replaced with C. + +The method used depends on the tr_* members of C. + +=cut +*/ + +void +i_quant_transparent(i_quantize *quant, i_palidx *data, i_img *img, i_palidx trans_index) { switch (quant->transp) { @@ -1670,7 +1599,8 @@ transparent_errdiff(i_quantize *quant, i_palidx *data, i_img *img, } /* builtin ordered dither maps */ -unsigned char orddith_maps[][64] = +static unsigned char +orddith_maps[][64] = { { /* random this is purely random - it's pretty awful