1 /* quant.c - provides general image quantization
2 currently only used by gif.c, but maybe we'll support producing
3 8-bit (or bigger indexed) png files at some point
7 static void makemap_addi(i_quantize *, i_img **imgs, int count);
8 static void makemap_mediancut(i_quantize *, i_img **imgs, int count);
12 setcol(i_color *cl,unsigned char r,unsigned char g,unsigned char b,unsigned char a) {
21 /* make a colour map overwrites mc_existing/mc_count in quant Note
22 that i_makemap will be called once for each image if mc_perimage is
23 set and the format support multiple colour maps per image.
25 This means we don't need any special processing at this level to
26 handle multiple colour maps.
30 quant_makemap(i_quantize *quant, i_img **imgs, int count) {
32 if (quant->translate == pt_giflib) {
33 /* giflib does it's own color table generation */
34 /* previously we used giflib's quantizer, but it didn't handle multiple
35 images, which made it hard to build a global color map
36 We've implemented our own median cut code so we can ignore
38 makemap_mediancut(quant, imgs, count);
42 switch (quant->make_colors & mc_mask) {
44 /* use user's specified map */
50 for (r = 0; r < 256; r+=0x33)
51 for (g = 0; g < 256; g+=0x33)
52 for (b = 0; b < 256; b += 0x33)
53 setcol(quant->mc_colors+i++, r, g, b, 255);
59 makemap_mediancut(quant, imgs, count);
64 makemap_addi(quant, imgs, count);
70 static void translate_giflib(i_quantize *, i_img *, i_palidx *);
72 static void translate_closest(i_quantize *, i_img *, i_palidx *);
73 static void translate_errdiff(i_quantize *, i_img *, i_palidx *);
74 static void translate_addi(i_quantize *, i_img *, i_palidx *);
76 /* Quantize the image given the palette in quant.
78 The giflib quantizer ignores the palette.
80 i_palidx *quant_translate(i_quantize *quant, i_img *img) {
82 mm_log((1, "quant_translate(quant %p, img %p)\n", quant, img));
84 /* there must be at least one color in the paletted (though even that
86 if (quant->mc_count == 0) {
87 i_push_error(0, "no colors available for translation");
91 result = mymalloc(img->xsize * img->ysize);
93 switch (quant->translate) {
96 translate_closest(quant, img, result);
100 translate_errdiff(quant, img, result);
105 translate_addi(quant, img, result);
112 #ifdef HAVE_LIBGIF_THIS_NOT_USED
116 #define GET_RGB(im, x, y, ri, gi, bi, col) \
117 i_gpix((im),(x),(y),&(col)); (ri)=(col).rgb.r; \
118 if((im)->channels==3) { (bi)=(col).rgb.b; (gi)=(col).rgb.g; }
121 quant_replicate(i_img *im, i_palidx *output, i_quantize *quant);
124 /* Use the gif_lib quantization functions to quantize the image */
125 static void translate_giflib(i_quantize *quant, i_img *img, i_palidx *out) {
126 int x,y,ColorMapSize,colours_in;
130 GifByteType *RedBuffer = NULL, *GreenBuffer = NULL, *BlueBuffer = NULL;
131 GifByteType *RedP, *GreenP, *BlueP;
132 ColorMapObject *OutputColorMap = NULL;
136 mm_log((1,"translate_giflib(quant %p, img %p, out %p)\n", quant, img, out));
138 /*if (!(im->channels==1 || im->channels==3)) { fprintf(stderr,"Unable to write gif, improper colorspace.\n"); exit(3); }*/
140 ColorMapSize = quant->mc_size;
142 Size = ((long) img->xsize) * img->ysize * sizeof(GifByteType);
145 if ((OutputColorMap = MakeMapObject(ColorMapSize, NULL)) == NULL)
146 m_fatal(0,"Failed to allocate memory for Output colormap.");
147 /* if ((OutputBuffer = (GifByteType *) mymalloc(im->xsize * im->ysize * sizeof(GifByteType))) == NULL)
148 m_fatal(0,"Failed to allocate memory for output buffer.");*/
150 /* ******************************************************* */
151 /* count the number of colours in the image */
152 colours_in=i_count_colors(img, OutputColorMap->ColorCount);
154 if(colours_in != -1) { /* less then the number wanted */
155 /* so we copy them over as-is */
156 mm_log((2,"image has %d colours, which fits in %d. Copying\n",
157 colours_in,ColorMapSize));
158 quant_replicate(img, out, quant);
159 /* saves the colors, so don't fall through */
163 mm_log((2,"image has %d colours, more then %d. Quantizing\n",colours_in,ColorMapSize));
165 if (img->channels >= 3) {
166 if ((RedBuffer = (GifByteType *) mymalloc((unsigned int) Size)) == NULL) {
167 m_fatal(0,"Failed to allocate memory required, aborted.");
170 if ((GreenBuffer = (GifByteType *) mymalloc((unsigned int) Size)) == NULL) {
171 m_fatal(0,"Failed to allocate memory required, aborted.");
176 if ((BlueBuffer = (GifByteType *) mymalloc((unsigned int) Size)) == NULL) {
177 m_fatal(0,"Failed to allocate memory required, aborted.");
184 GreenP = GreenBuffer;
187 for (y=0; y< img->ysize; y++) for (x=0; x < img->xsize; x++) {
188 i_gpix(img,x,y,&col);
190 *GreenP++ = col.rgb.g;
191 *BlueP++ = col.rgb.b;
196 if ((RedBuffer = (GifByteType *) mymalloc((unsigned int) Size))==NULL) {
197 m_fatal(0,"Failed to allocate memory required, aborted.");
201 GreenBuffer=BlueBuffer=RedBuffer;
203 for (y=0; y< img->ysize; y++) for (x=0; x < img->xsize; x++) {
204 i_gpix(img,x,y,&col);
209 if (QuantizeBuffer(img->xsize, img->ysize, &ColorMapSize, RedBuffer, GreenBuffer, BlueBuffer,
210 out, OutputColorMap->Colors) == GIF_ERROR) {
211 mm_log((1,"Error in QuantizeBuffer, unable to write image.\n"));
216 if (img->channels == 3) { myfree(GreenBuffer); myfree(BlueBuffer); }
218 /* copy over the color map */
219 for (i = 0; i < ColorMapSize; ++i) {
220 quant->mc_colors[i].rgb.r = OutputColorMap->Colors[i].Red;
221 quant->mc_colors[i].rgb.g = OutputColorMap->Colors[i].Green;
222 quant->mc_colors[i].rgb.b = OutputColorMap->Colors[i].Blue;
224 quant->mc_count = ColorMapSize;
229 quant_replicate(i_img *im, GifByteType *output, i_quantize *quant) {
230 int x, y, alloced, r, g=0, b=0, idx ;
234 for(y=0; y<im->ysize; y++) {
235 for(x=0; x<im->xsize; x++) {
237 GET_RGB(im, x,y, r,g,b, col);
239 for(idx=0; idx<alloced; idx++) { /* linear search for an index */
240 if(quant->mc_colors[idx].rgb.r==r &&
241 quant->mc_colors[idx].rgb.g==g &&
242 quant->mc_colors[idx].rgb.b==b) {
247 if(idx >= alloced) { /* if we haven't already, we */
248 idx=alloced++; /* add the colour to the map */
249 if(quant->mc_size < alloced) {
250 mm_log((1,"Tried to allocate more then %d colours.\n",
254 quant->mc_colors[idx].rgb.r=r;
255 quant->mc_colors[idx].rgb.g=g;
256 quant->mc_colors[idx].rgb.b=b;
258 *output=idx; /* fill output buffer */
259 output++; /* with colour indexes */
262 quant->mc_count = alloced;
268 static void translate_closest(i_quantize *quant, i_img *img, i_palidx *out) {
270 translate_addi(quant, img, out);
273 #define PWR2(x) ((x)*(x))
275 typedef int (*cmpfunc)(const void*, const void*);
298 static void prescan(i_img **im,int count, int cnum, cvec *clr, i_sample_t *line);
299 static void reorder(pbox prescan[512]);
300 static int pboxcmp(const pbox *a,const pbox *b);
301 static void boxcenter(int box,cvec *cv);
302 static float frandn(void);
303 static void boxrand(int box,cvec *cv);
304 static void bbox(int box,int *r0,int *r1,int *g0,int *g1,int *b0,int *b1);
305 static void cr_hashindex(cvec clr[256],int cnum,hashbox hb[512]);
306 static int mindist(int boxnum,cvec *cv);
307 static int maxdist(int boxnum,cvec *cv);
309 /* Some of the simpler functions are kept here to aid the compiler -
310 maybe some of them will be inlined. */
313 pixbox(i_color *ic) { return ((ic->channel[0] & 224)<<1)+ ((ic->channel[1]&224)>>2) + ((ic->channel[2] &224) >> 5); }
316 pixbox_ch(i_sample_t *chans) { return ((chans[0] & 224)<<1)+ ((chans[1]&224)>>2) + ((chans[2] &224) >> 5); }
320 if (in>255) { return 255; }
321 else if (in>0) return in;
328 return rand()/(RAND_MAX+1.0);
333 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]); }
337 eucl_d_ch(cvec* cv,i_sample_t *chans) {
338 return PWR2(cv->r - chans[0]) + PWR2(cv->g - chans[1])
339 + PWR2(cv->b - chans[2]);
344 ceucl_d(i_color *c1, i_color *c2) { return PWR2(c1->channel[0]-c2->channel[0])+PWR2(c1->channel[1]-c2->channel[1])+PWR2(c1->channel[2]-c2->channel[2]); }
347 gray_samples[] = { 0, 0, 0 };
351 This quantization algorithm and implementation routines are by Arnar
352 M. Hrafnkelson. In case any new ideas are here they are mine since
353 this was written from scratch.
355 The algorithm uses local means in the following way:
357 For each point in the colormap we find which image points
358 have that point as it's closest point. We calculate the mean
359 of those points and in the next iteration it will be the new
360 entry in the colormap.
362 In order to speed this process up (i.e. nearest neighbor problem) We
363 divied the r,g,b space up in equally large 512 boxes. The boxes are
364 numbered from 0 to 511. Their numbering is so that for a given vector
365 it is known that it belongs to the box who is formed by concatenating the
366 3 most significant bits from each component of the RGB triplet.
368 For each box we find the list of points from the colormap who might be
369 closest to any given point within the box. The exact solution
370 involves finding the Voronoi map (or the dual the Delauny
371 triangulation) and has many issues including numerical stability.
373 So we use this approximation:
375 1. Find which point has the shortest maximum distance to the box.
376 2. Find all points that have a shorter minimum distance than that to the box
378 This is a very simple task and is not computationally heavy if one
379 takes into account that the minimum distances from a pixel to a box is
380 always found by checking if it's inside the box or is closest to some
381 side or a corner. Finding the maximum distance is also either a side
384 This approach results 2-3 times more than the actual points needed but
385 is still a good gain over the complete space. Usually when one has a
386 256 Colorcolor map a search over 30 is often obtained.
388 A bit of an enhancement to this approach is to keep a seperate list
389 for each side of the cube, but this will require even more memory.
391 Arnar M. Hrafnkelsson (addi@umich.edu);
395 Extracted from gifquant.c, removed dependencies on gif_lib,
396 and added support for multiple images.
397 starting from 1nov2000 by TonyC <tony@develop-help.com>.
402 makemap_addi(i_quantize *quant, i_img **imgs, int count) {
404 int cnum, i, x, y, bst_idx=0, ld, cd, iter, currhb, img_num;
411 const int *sample_indices;
413 mm_log((1, "makemap_addi(quant %p { mc_count=%d, mc_colors=%p }, imgs %p, count %d)\n",
414 quant, quant->mc_count, quant->mc_colors, imgs, count));
418 clr = i_mempool_alloc(&mp, sizeof(cvec) * quant->mc_size);
419 hb = i_mempool_alloc(&mp, sizeof(hashbox) * 512);
420 for (i=0; i < quant->mc_count; ++i) {
421 clr[i].r = quant->mc_colors[i].rgb.r;
422 clr[i].g = quant->mc_colors[i].rgb.g;
423 clr[i].b = quant->mc_colors[i].rgb.b;
427 /* mymalloc doesn't clear memory, so I think we need this */
428 for (; i < quant->mc_size; ++i) {
429 /*clr[i].r = clr[i].g = clr[i].b = 0;*/
436 cnum = quant->mc_size;
439 for (img_num = 0; img_num < count; ++img_num) {
440 if (imgs[img_num]->xsize > maxwidth)
441 maxwidth = imgs[img_num]->xsize;
443 line = i_mempool_alloc(&mp, 3 * maxwidth * sizeof(*line));
445 prescan(imgs, count, cnum, clr, line);
446 cr_hashindex(clr, cnum, hb);
448 for(iter=0;iter<3;iter++) {
451 for (img_num = 0; img_num < count; ++img_num) {
452 i_img *im = imgs[img_num];
453 sample_indices = im->channels >= 3 ? NULL : gray_samples;
454 for(y=0;y<im->ysize;y++) {
455 i_gsamp(im, 0, im->xsize, y, line, sample_indices, 3);
457 for(x=0;x<im->xsize;x++) {
459 /*i_gpix(im,x,y,&val);*/
460 currhb=pixbox_ch(val);
461 /* printf("box = %d \n",currhb); */
462 for(i=0;i<hb[currhb].cnt;i++) {
463 /* printf("comparing: pix (%d,%d,%d) vec (%d,%d,%d)\n",val.channel[0],val.channel[1],val.channel[2],clr[hb[currhb].vec[i]].r,clr[hb[currhb].vec[i]].g,clr[hb[currhb].vec[i]].b); */
465 cd=eucl_d_ch(&clr[hb[currhb].vec[i]],val);
467 ld=cd; /* shortest distance yet */
468 bst_idx=hb[currhb].vec[i]; /* index of closest vector yet */
472 clr[bst_idx].mcount++;
474 clr[bst_idx].dr+=val[0];
475 clr[bst_idx].dg+=val[1];
476 clr[bst_idx].db+=val[2];
478 val += 3; /* next 3 samples (next pixel) */
485 clr[i].dr/=clr[i].mcount;
486 clr[i].dg/=clr[i].mcount;
487 clr[i].db/=clr[i].mcount;
490 /* for(i=0;i<cnum;i++) printf("vec(%d)=(%d,%d,%d) dest=(%d,%d,%d) matchcount=%d\n",
491 i,clr[i].r,clr[i].g,clr[i].b,clr[i].dr,clr[i].dg,clr[i].db,clr[i].mcount); */
493 /* printf("total error: %.2f\n",sqrt(accerr)); */
495 for(i=0;i<cnum;i++) {
496 if (clr[i].fixed) continue; /* skip reserved colors */
500 clr[i].r=clr[i].r*(1-dlt)+dlt*clr[i].dr;
501 clr[i].g=clr[i].g*(1-dlt)+dlt*clr[i].dg;
502 clr[i].b=clr[i].b*(1-dlt)+dlt*clr[i].db;
504 /* let's try something else */
516 cr_hashindex(clr,cnum,hb);
521 for(i=0;i<cnum;i++) {
522 cd=eucl_d(&clr[i],&val);
530 /* if defined, we only include colours with an mcount or that were
531 supplied in the fixed palette, giving us a smaller output palette */
532 #define ONLY_USE_USED
534 /* transfer the colors back */
536 for (i = 0; i < cnum; ++i) {
537 if (clr[i].fixed || clr[i].used) {
538 /*printf("Adding %d (%d,%d,%d)\n", i, clr[i].r, clr[i].g, clr[i].b);*/
539 quant->mc_colors[quant->mc_count].rgb.r = clr[i].r;
540 quant->mc_colors[quant->mc_count].rgb.g = clr[i].g;
541 quant->mc_colors[quant->mc_count].rgb.b = clr[i].b;
546 /* transfer the colors back */
547 for (i = 0; i < cnum; ++i) {
548 quant->mc_colors[i].rgb.r = clr[i].r;
549 quant->mc_colors[i].rgb.g = clr[i].g;
550 quant->mc_colors[i].rgb.b = clr[i].b;
552 quant->mc_count = cnum;
556 mm_log((1, "makemap_addi returns - quant.mc_count = %d\n", quant->mc_count));
557 for (i = 0; i < quant->mc_count; ++i)
558 mm_log((5, " map entry %d: (%d, %d, %d)\n", i, clr[i].r, clr[i].g, clr[i].b));
561 i_mempool_destroy(&mp);
569 #define MEDIAN_CUT_COLORS 32768
571 #define MED_CUT_INDEX(c) ((((c).rgb.r & 0xF8) << 7) | \
572 (((c).rgb.g & 0xF8) << 2) | (((c).rgb.b & 0xF8) >> 3))
574 #define MED_CUT_GRAY_INDEX(c) ((((c).rgb.r & 0xF8) << 7) | \
575 (((c).rgb.r & 0xF8) << 2) | (((c).rgb.r & 0xF8) >> 3))
577 /* scale these to cover the whole range */
578 #define MED_CUT_RED(index) ((((index) & 0x7C00) >> 10) * 255 / 31)
579 #define MED_CUT_GREEN(index) ((((index) & 0x3E0) >> 5) * 255 / 31)
580 #define MED_CUT_BLUE(index) (((index) & 0x1F) * 255 / 31)
583 i_sample_t min[3]; /* minimum for each channel */
584 i_sample_t max[3]; /* maximum for each channel */
585 i_sample_t width[3]; /* width for each channel */
586 int start, size; /* beginning and size of the partition */
587 int pixels; /* number of pixels represented by this partition */
591 =item calc_part(part, colors)
593 Calculates the new color limits for the given partition.
595 Giflib assumes that the limits for the non-split channels stay the
596 same, but this strikes me as incorrect, especially if the colors tend
599 Of course this could be optimized by not recalculating the channel we
600 just sorted on, but it's not worth the effort right now.
604 static void calc_part(medcut_partition *part, quant_color_entry *colors) {
607 for (ch = 0; ch < 3; ++ch) {
611 for (i = part->start; i < part->start + part->size; ++i) {
612 for (ch = 0; ch < 3; ++ch) {
613 if (part->min[ch] > colors[i].rgb[ch])
614 part->min[ch] = colors[i].rgb[ch];
615 if (part->max[ch] < colors[i].rgb[ch])
616 part->max[ch] = colors[i].rgb[ch];
619 for (ch = 0; ch < 3; ++ch) {
620 part->width[ch] = part->max[ch] - part->min[ch];
624 /* simple functions to sort by each channel - we could use a global, but
628 color_sort_red(void const *left, void const *right) {
629 return ((quant_color_entry *)left)->rgb[0] - ((quant_color_entry *)right)->rgb[0];
633 color_sort_green(void const *left, void const *right) {
634 return ((quant_color_entry *)left)->rgb[1] - ((quant_color_entry *)right)->rgb[1];
638 color_sort_blue(void const *left, void const *right) {
639 return ((quant_color_entry *)left)->rgb[2] - ((quant_color_entry *)right)->rgb[2];
642 static int (*sorters[])(void const *, void const *) =
650 makemap_mediancut(i_quantize *quant, i_img **imgs, int count) {
651 quant_color_entry *colors;
653 int imgn, x, y, i, ch;
658 medcut_partition *parts;
661 /* number of channels we search for the best channel to partition
662 this isn't terribly efficient, but it should work */
665 /*printf("images %d pal size %d\n", count, quant->mc_size);*/
669 colors = i_mempool_alloc(&mp, sizeof(*colors) * MEDIAN_CUT_COLORS);
670 for (i = 0; i < MEDIAN_CUT_COLORS; ++i) {
671 colors[i].rgb[0] = MED_CUT_RED(i);
672 colors[i].rgb[1] = MED_CUT_GREEN(i);
673 colors[i].rgb[2] = MED_CUT_BLUE(i);
678 for (imgn = 0; imgn < count; ++imgn) {
679 if (imgs[imgn]->xsize > max_width)
680 max_width = imgs[imgn]->xsize;
682 line = i_mempool_alloc(&mp, sizeof(i_color) * max_width);
684 /* build the stats */
686 chan_count = 1; /* assume we just have grayscale */
687 for (imgn = 0; imgn < count; ++imgn) {
688 total_pixels += imgs[imgn]->xsize * imgs[imgn]->ysize;
689 for (y = 0; y < imgs[imgn]->ysize; ++y) {
690 i_glin(imgs[imgn], 0, imgs[imgn]->xsize, y, line);
691 if (imgs[imgn]->channels > 2) {
693 for (x = 0; x < imgs[imgn]->xsize; ++x) {
694 ++colors[MED_CUT_INDEX(line[x])].count;
698 /* a gray-scale image, just use the first channel */
699 for (x = 0; x < imgs[imgn]->xsize; ++x) {
700 ++colors[MED_CUT_GRAY_INDEX(line[x])].count;
706 /* eliminate the empty colors */
708 for (in = 0; in < MEDIAN_CUT_COLORS; ++in) {
709 if (colors[in].count) {
710 colors[out++] = colors[in];
713 /*printf("out %d\n", out);
715 for (i = 0; i < out; ++i) {
716 if (colors[i].count) {
717 printf("%d: (%d,%d,%d) -> %d\n", i, colors[i].rgb[0], colors[i].rgb[1],
718 colors[i].rgb[2], colors[i].count);
722 if (out < quant->mc_size) {
723 /* just copy them into the color table */
724 for (i = 0; i < out; ++i) {
725 for (ch = 0; ch < 3; ++ch) {
726 quant->mc_colors[i].channel[ch] = colors[i].rgb[ch];
729 quant->mc_count = out;
732 /* build the starting partition */
733 parts = i_mempool_alloc(&mp, sizeof(*parts) * quant->mc_size);
736 parts[0].pixels = total_pixels;
737 calc_part(parts, colors);
740 while (color_count < quant->mc_size) {
741 int max_index, max_ch; /* index/channel with biggest spread */
743 medcut_partition *workpart;
747 /* find the partition with the most biggest span with more than
750 for (i = 0; i < color_count; ++i) {
751 for (ch = 0; ch < chan_count; ++ch) {
752 if (parts[i].width[ch] > max_size
753 && parts[i].size > 1) {
756 max_size = parts[i].width[ch];
761 /* nothing else we can split */
765 workpart = parts+max_index;
766 /*printf("splitting partition %d (pixels %ld, start %d, size %d)\n", max_index, workpart->pixels, workpart->start, workpart->size);*/
767 qsort(colors + workpart->start, workpart->size, sizeof(*colors),
770 /* find the median or something like it we need to make sure both
771 sides of the split have at least one color in them, so we don't
772 test at the first or last entry */
774 cum_total = colors[i].count;
776 half = workpart->pixels / 2;
777 while (i < workpart->start + workpart->size - 1
778 && cum_total < half) {
779 cum_total += colors[i++].count;
781 /*printf("Split at %d to make %d (half %ld, cumtotal %ld)\n", i, color_count, half, cum_total);*/
783 /* found the spot to split */
784 parts[color_count].start = i;
785 parts[color_count].size = workpart->start + workpart->size - i;
786 workpart->size = i - workpart->start;
787 parts[color_count].pixels = workpart->pixels - cum_total;
788 workpart->pixels = cum_total;
790 /* recalculate the limits */
791 calc_part(workpart, colors);
792 calc_part(parts+color_count, colors);
796 /* fill in the color table - since we could still have partitions
797 that have more than one color, we need to average the colors */
798 for (part_num = 0; part_num < color_count; ++part_num) {
800 medcut_partition *workpart;
802 workpart = parts+part_num;
803 for (ch = 0; ch < 3; ++ch)
806 for (i = workpart->start; i < workpart->start + workpart->size; ++i) {
807 for (ch = 0; ch < 3; ++ch) {
808 sums[ch] += colors[i].rgb[ch] * colors[i].count;
811 for (ch = 0; ch < 3; ++ch) {
812 quant->mc_colors[part_num].channel[ch] = sums[ch] / workpart->pixels;
815 quant->mc_count = color_count;
817 /*printf("out %d colors\n", quant->mc_count);*/
818 i_mempool_destroy(&mp);
823 /* Define one of the following 4 symbols to choose a colour search method
824 The idea is to try these out, including benchmarking, to see which
825 is fastest in a good spread of circumstances.
826 I'd expect IM_CFLINSEARCH to be fastest for very small palettes, and
827 IM_CFHASHBOX for large images with large palettes.
829 Some other possibilities include:
830 - search over entries sorted by luminance
832 Initially I was planning on testing using the macros and then
833 integrating the code directly into each function, but this means if
834 we find a bug at a late stage we will need to update N copies of
835 the same code. Also, keeping the code in the macros means that the
836 code in the translation functions is much more to the point,
837 there's no distracting colour search code to remove attention from
838 what makes _this_ translation function different. It may be
839 advisable to move the setup code into functions at some point, but
840 it should be possible to do this fairly transparently.
842 If IM_CF_COPTS is defined then CFLAGS must have an appropriate
845 Each option needs to define 4 macros:
846 CF_VARS - variables to define in the function
847 CF_SETUP - code to setup for the colour search, eg. allocating and
848 initializing lookup tables
849 CF_FIND - code that looks for the color in val and puts the best
850 matching index in bst_idx
851 CF_CLEANUP - code to clean up, eg. releasing memory
854 /*#define IM_CFLINSEARCH*/
856 /*#define IM_CFSORTCHAN*/
857 /*#define IM_CFRAND2DIST*/
862 /* The original version I wrote for this used the sort.
863 If this is defined then we use a sort to extract the indices for
867 /* assume i is available */
868 #define CF_VARS hashbox *hb = mymalloc(sizeof(hashbox) * 512); \
874 static long *gdists; /* qsort is annoying */
875 /* int might be smaller than long, so we need to do a real compare
876 rather than a subtraction*/
877 static int distcomp(void const *a, void const *b) {
878 long ra = gdists[*(int const *)a];
879 long rb = gdists[*(int const *)b];
890 /* for each hashbox build a list of colours that are in the hb or is closer
892 This is pretty involved. The original gifquant generated the hashbox
893 as part of it's normal processing, but since the map generation is now
894 separated from the translation we need to do this on the spot.
895 Any optimizations, even if they don't produce perfect results would be
898 static void hbsetup(i_quantize *quant, hashbox *hb) {
899 long *dists, mind, maxd, cd;
900 int cr, cb, cg, hbnum, i;
903 int *indices = mymalloc(quant->mc_count * sizeof(int));
906 dists = mymalloc(quant->mc_count * sizeof(long));
907 for (cr = 0; cr < 8; ++cr) {
908 for (cg = 0; cg < 8; ++cg) {
909 for (cb = 0; cb < 8; ++cb) {
910 /* centre of the hashbox */
911 cenc.channel[0] = cr*pboxjump+pboxjump/2;
912 cenc.channel[1] = cg*pboxjump+pboxjump/2;
913 cenc.channel[2] = cb*pboxjump+pboxjump/2;
914 hbnum = pixbox(&cenc);
916 /* order indices in the order of distance from the hashbox */
917 for (i = 0; i < quant->mc_count; ++i) {
921 dists[i] = ceucl_d(&cenc, quant->mc_colors+i);
924 /* it should be possible to do this without a sort
925 but so far I'm too lazy */
927 qsort(indices, quant->mc_count, sizeof(int), distcomp);
928 /* any colors that can match are within mind+diagonal size of
930 mind = dists[indices[0]];
932 maxd = (sqrt(mind)+pboxjump)*(sqrt(mind)+pboxjump);
933 while (i < quant->mc_count && dists[indices[i]] < maxd) {
934 hb[hbnum].vec[hb[hbnum].cnt++] = indices[i++];
937 /* work out the minimum */
939 for (i = 0; i < quant->mc_count; ++i) {
940 if (dists[i] < mind) mind = dists[i];
942 /* transfer any colours that might be closest to a colour in
944 maxd = (sqrt(mind)+pboxjump)*(sqrt(mind)+pboxjump);
945 for (i = 0; i < quant->mc_count; ++i) {
947 hb[hbnum].vec[hb[hbnum].cnt++] = i;
958 #define CF_SETUP hbsetup(quant, hb)
961 currhb = pixbox(&val); \
963 for (i = 0; i < hb[currhb].cnt; ++i) { \
964 cd = ceucl_d(quant->mc_colors+hb[currhb].vec[i], &val); \
965 if (cd < ld) { ld = cd; bst_idx = hb[currhb].vec[i]; } \
968 #define CF_CLEANUP myfree(hb)
972 #ifdef IM_CFLINSEARCH
973 /* as simple as it gets */
974 #define CF_VARS long ld, cd
975 #define CF_SETUP /* none needed */
978 for (i = 0; i < quant->mc_count; ++i) { \
979 cd = ceucl_d(quant->mc_colors+i, &val); \
980 if (cd < ld) { ld = cd; bst_idx = i; } \
986 static int gsortchan;
987 static i_quantize *gquant;
988 static int chansort(void const *a, void const *b) {
989 return gquant->mc_colors[*(int const *)a].channel[gsortchan] -
990 gquant->mc_colors[*(int const *)b].channel[gsortchan];
992 #define CF_VARS int *indices, sortchan, diff; \
994 int vindex[256] /* where to find value i of chan */
996 static void chansetup(i_img *img, i_quantize *quant, int *csortchan,
997 int *vindex, int **cindices) {
998 int *indices, sortchan, chan, i, chval;
999 int chanmins[MAXCHANNELS], chanmaxs[MAXCHANNELS], maxrange;
1001 /* find the channel with the maximum range */
1002 /* the maximum stddev would probably be better */
1003 for (chan = 0; chan < img->channels; ++chan) {
1004 chanmins[chan] = 256; chanmaxs[chan] = 0;
1005 for (i = 0; i < quant->mc_count; ++i) {
1006 if (quant->mc_colors[i].channel[chan] < chanmins[chan])
1007 chanmins[chan] = quant->mc_colors[i].channel[chan];
1008 if (quant->mc_colors[i].channel[chan] > chanmaxs[chan])
1009 chanmaxs[chan] = quant->mc_colors[i].channel[chan];
1013 for (chan = 0; chan < img->channels; ++chan) {
1014 if (chanmaxs[chan]-chanmins[chan] > maxrange) {
1015 maxrange = chanmaxs[chan]-chanmins[chan];
1019 indices = mymalloc(quant->mc_count * sizeof(int)) ;
1020 for (i = 0; i < quant->mc_count; ++i) {
1023 gsortchan = sortchan;
1025 qsort(indices, quant->mc_count, sizeof(int), chansort) ;
1026 /* now a lookup table to find entries faster */
1027 for (chval=0, i=0; i < quant->mc_count; ++i) {
1028 while (chval < 256 &&
1029 chval < quant->mc_colors[indices[i]].channel[sortchan]) {
1030 vindex[chval++] = i;
1033 while (chval < 256) {
1034 vindex[chval++] = quant->mc_count-1;
1036 *csortchan = sortchan;
1037 *cindices = indices;
1041 chansetup(img, quant, &sortchan, vindex, &indices)
1043 int chanfind(i_color val, i_quantize *quant, int *indices, int *vindex,
1045 int i, bst_idx, diff, maxdiff;
1048 i = vindex[val.channel[sortchan]];
1049 bst_idx = indices[i];
1052 maxdiff = quant->mc_count;
1053 while (diff < maxdiff) {
1054 if (i+diff < quant->mc_count) {
1055 cd = ceucl_d(&val, quant->mc_colors+indices[i+diff]);
1057 bst_idx = indices[i+diff];
1063 cd = ceucl_d(&val, quant->mc_colors+indices[i-diff]);
1065 bst_idx = indices[i-diff];
1077 bst_idx = chanfind(val, quant, indices, vindex, sortchan)
1080 #define CF_CLEANUP myfree(indices)
1084 #ifdef IM_CFRAND2DIST
1086 /* This is based on a method described by Addi in the #imager channel
1087 on the 28/2/2001. I was about 1am Sydney time at the time, so I
1088 wasn't at my most cogent. Well, that's my excuse :)
1090 <TonyC> what I have at the moment is: hashboxes, with optimum hash box
1091 filling; simple linear search; and a lookup in the widest channel
1092 (currently the channel with the maximum range)
1093 <Addi> There is one more way that might be simple to implement.
1094 <Addi> You want to hear?
1095 <TonyC> what's that?
1096 <purl> somebody said that was not true
1097 <Addi> For each of the colors in the palette start by creating a
1098 sorted list of the form:
1099 <Addi> [distance, color]
1100 <Addi> Where they are sorted by distance.
1101 <TonyC> distance to where?
1102 <Addi> Where the elements in the lists are the distances and colors of
1103 the other colors in the palette
1105 <Addi> So if you are at color 0
1106 <Addi> ok - now to search for the closest color when you are creating
1107 the final image is done like this:
1108 <Addi> a) pick a random color from the palette
1109 <Addi> b) calculate the distance to it
1110 <Addi> c) only check the vectors that are within double the distance
1111 in the list of the color you picked from the palette.
1112 <Addi> Does that seem logical?
1113 <Addi> Lets imagine that we only have grayscale to make an example:
1114 <Addi> Our palette has 1 4 10 20 as colors.
1115 <Addi> And we want to quantize the color 11
1116 <Addi> lets say we picked 10 randomly
1117 <Addi> the double distance is 2
1118 <Addi> since abs(10-11)*2 is 2
1119 <Addi> And the list at vector 10 is this:
1120 <Addi> [0, 10], [6 4], [9, 1], [10, 20]
1121 <Addi> so we look at the first one (but not the second one since 6 is
1122 at a greater distance than 2.
1123 <Addi> Any of that make sense?
1124 <TonyC> yes, though are you suggesting another random jump to one of
1125 the colours with the possible choices? or an exhaustive search?
1126 <Addi> TonyC: It's possible to come up with a recursive/iterative
1127 enhancement but this is the 'basic' version.
1128 <Addi> Which would do an iterative search.
1129 <Addi> You can come up with conditions where it pays to switch to a new one.
1130 <Addi> And the 'random' start can be switched over to a small tree.
1131 <Addi> So you would have a little index at the start.
1132 <Addi> to get you into the general direction
1133 <Addi> Perhaps just an 8 split.
1134 <Addi> that is - split each dimension in half.
1136 <TonyC> I get the idea
1137 <Addi> But this would seem to be a good approach in our case since we
1138 usually have few codevectors.
1139 <Addi> So we only need 256*256 entries in a table.
1140 <Addi> We could even only index some of them that were deemed as good
1142 <TonyC> I was considering adding paletted output support for PNG and
1143 TIFF at some point, which support 16-bit palettes
1151 typedef struct i_dists {
1159 static int dists_sort(void const *a, void const *b) {
1160 return ((i_dists *)a)->dist - ((i_dists *)b)->dist;
1163 static void rand2dist_setup(i_quantize *quant, i_dists **cdists) {
1165 mymalloc(sizeof(i_dists)*quant->mc_count*quant->mc_count);
1168 for (i = 0; i < quant->mc_count; ++i) {
1169 i_dists *ldists = dists + quant->mc_count * i;
1170 i_color val = quant->mc_colors[i];
1171 for (j = 0; j < quant->mc_count; ++j) {
1172 ldists[j].index = j;
1173 ldists[j].dist = ceucl_d(&val, quant->mc_colors+j);
1175 qsort(ldists, quant->mc_count, sizeof(i_dists), dists_sort);
1181 bst_idx = rand() % quant->mc_count; \
1182 rand2dist_setup(quant, &dists)
1184 static int rand2dist_find(i_color val, i_quantize *quant, i_dists *dists, int index) {
1191 cdists = dists + index * quant->mc_count;
1193 maxld = 8 * ceucl_d(&val, quant->mc_colors+index);
1194 for (i = 0; i < quant->mc_count && cdists[i].dist <= maxld; ++i) {
1195 cd = ceucl_d(&val, quant->mc_colors+cdists[i].index);
1197 bst_idx = cdists[i].index;
1204 #define CF_FIND bst_idx = rand2dist_find(val, quant, dists, bst_idx)
1206 #define CF_CLEANUP myfree(dists)
1211 static void translate_addi(i_quantize *quant, i_img *img, i_palidx *out) {
1212 int x, y, i, k, bst_idx;
1214 int pixdev = quant->perturb;
1219 if (img->channels >= 3) {
1222 for(y=0;y<img->ysize;y++) for(x=0;x<img->xsize;x++) {
1223 i_gpix(img,x,y,&val);
1224 val.channel[0]=g_sat(val.channel[0]+(int)(pixdev*frandn()));
1225 val.channel[1]=g_sat(val.channel[1]+(int)(pixdev*frandn()));
1226 val.channel[2]=g_sat(val.channel[2]+(int)(pixdev*frandn()));
1232 for(y=0;y<img->ysize;y++) for(x=0;x<img->xsize;x++) {
1233 i_gpix(img,x,y,&val);
1242 for(y=0;y<img->ysize;y++) for(x=0;x<img->xsize;x++) {
1243 i_gpix(img,x,y,&val);
1244 val.channel[1] = val.channel[2] =
1245 val.channel[0]=g_sat(val.channel[0]+(int)(pixdev*frandn()));
1251 for(y=0;y<img->ysize;y++) for(x=0;x<img->xsize;x++) {
1252 i_gpix(img,x,y,&val);
1253 val.channel[1] = val.channel[2] = val.channel[0];
1262 static int floyd_map[] =
1268 static int jarvis_map[] =
1275 static int stucki_map[] =
1282 struct errdiff_map {
1284 int width, height, orig;
1287 static struct errdiff_map maps[] =
1289 { floyd_map, 3, 2, 1 },
1290 { jarvis_map, 5, 3, 2 },
1291 { stucki_map, 5, 3, 2 },
1294 typedef struct errdiff_tag {
1298 /* perform an error diffusion dither */
1301 translate_errdiff(i_quantize *quant, i_img *img, i_palidx *out) {
1303 int mapw, maph, mapo;
1309 int minr, maxr, ming, maxg, minb, maxb, cr, cg, cb;
1314 if ((quant->errdiff & ed_mask) == ed_custom) {
1315 map = quant->ed_map;
1316 mapw = quant->ed_width;
1317 maph = quant->ed_height;
1318 mapo = quant->ed_orig;
1321 int index = quant->errdiff & ed_mask;
1322 if (index >= ed_custom) index = ed_floyd;
1323 map = maps[index].map;
1324 mapw = maps[index].width;
1325 maph = maps[index].height;
1326 mapo = maps[index].orig;
1329 errw = img->xsize+mapw;
1330 err = mymalloc(sizeof(*err) * maph * errw);
1331 /*errp = err+mapo;*/
1332 memset(err, 0, sizeof(*err) * maph * errw);
1335 for (i = 0; i < maph * mapw; ++i)
1336 difftotal += map[i];
1338 for (dy = 0; dy < maph; ++dy) {
1339 for (dx = 0; dx < mapw; ++dx) {
1340 printf("%2d", map[dx+dy*mapw]);
1347 for (y = 0; y < img->ysize; ++y) {
1348 for (x = 0; x < img->xsize; ++x) {
1352 i_gpix(img, x, y, &val);
1353 if (img->channels < 3) {
1354 val.channel[1] = val.channel[2] = val.channel[0];
1357 perr.r = perr.r < 0 ? -((-perr.r)/difftotal) : perr.r/difftotal;
1358 perr.g = perr.g < 0 ? -((-perr.g)/difftotal) : perr.g/difftotal;
1359 perr.b = perr.b < 0 ? -((-perr.b)/difftotal) : perr.b/difftotal;
1360 /*printf("x %3d y %3d in(%3d, %3d, %3d) di(%4d,%4d,%4d)\n", x, y, val.channel[0], val.channel[1], val.channel[2], perr.r, perr.g, perr.b);*/
1361 val.channel[0] = g_sat(val.channel[0]-perr.r);
1362 val.channel[1] = g_sat(val.channel[1]-perr.g);
1363 val.channel[2] = g_sat(val.channel[2]-perr.b);
1366 perr.r = quant->mc_colors[bst_idx].channel[0] - val.channel[0];
1367 perr.g = quant->mc_colors[bst_idx].channel[1] - val.channel[1];
1368 perr.b = quant->mc_colors[bst_idx].channel[2] - val.channel[2];
1369 /*printf(" out(%3d, %3d, %3d) er(%4d, %4d, %4d)\n", quant->mc_colors[bst_idx].channel[0], quant->mc_colors[bst_idx].channel[1], quant->mc_colors[bst_idx].channel[2], perr.r, perr.g, perr.b);*/
1370 for (dx = 0; dx < mapw; ++dx) {
1371 for (dy = 0; dy < maph; ++dy) {
1372 err[x+dx+dy*errw].r += perr.r * map[dx+mapw*dy];
1373 err[x+dx+dy*errw].g += perr.g * map[dx+mapw*dy];
1374 err[x+dx+dy*errw].b += perr.b * map[dx+mapw*dy];
1379 /* shift up the error matrix */
1380 for (dy = 0; dy < maph-1; ++dy) {
1381 memcpy(err+dy*errw, err+(dy+1)*errw, sizeof(*err)*errw);
1383 memset(err+(maph-1)*errw, 0, sizeof(*err)*errw);
1388 /* Prescan finds the boxes in the image that have the highest number of colors
1389 and that result is used as the initial value for the vectores */
1392 static void prescan(i_img **imgs,int count, int cnum, cvec *clr, i_sample_t *line) {
1398 for(i=0;i<512;i++) {
1404 /* process each image */
1405 for (i = 0; i < count; ++i) {
1406 i_img *im = imgs[i];
1407 chans = im->channels >= 3 ? NULL : gray_samples;
1408 for(y=0;y<im->ysize;y++) {
1409 i_gsamp(im, 0, im->xsize, y, line, chans, 3);
1411 for(x=0;x<im->xsize;x++) {
1412 prebox[pixbox_ch(val)].pixcnt++;
1417 for(i=0;i<512;i++) prebox[i].pdc=prebox[i].pixcnt;
1418 qsort(prebox,512,sizeof(pbox),(cmpfunc)pboxcmp);
1420 for(i=0;i<cnum;i++) {
1421 /* printf("Color %d\n",i);
1422 for(k=0;k<10;k++) { printf("box=%03d %04d %d %04d \n",prebox[k].boxnum,prebox[k].pixcnt,prebox[k].cand,prebox[k].pdc); }
1427 /* for(k=0;k<cnum;k++) { printf("box=%03d %04d %d %04d \n",prebox[k].boxnum,prebox[k].pixcnt,prebox[k].cand,prebox[k].pdc); } */
1433 /* printf("prebox[%d].cand=%d\n",k,prebox[k].cand); */
1434 if (clr[i].fixed) { i++; continue; } /* reserved go to next */
1435 if (j>=prebox[k].cand) { k++; j=1; } else {
1436 if (prebox[k].cand == 2) boxcenter(prebox[k].boxnum,&(clr[i]));
1437 else boxrand(prebox[k].boxnum,&(clr[i]));
1438 /* printf("(%d,%d) %d %d -> (%d,%d,%d)\n",k,j,prebox[k].boxnum,prebox[k].pixcnt,clr[i].r,clr[i].g,clr[i].b); */
1446 static void reorder(pbox prescan[512]) {
1454 c.pdc=c.pixcnt/(c.cand*c.cand);
1455 /* c.pdc=c.pixcnt/c.cand; */
1456 while(c.pdc < prescan[nidx+1].pdc && nidx < 511) {
1457 prescan[nidx]=prescan[nidx+1];
1464 pboxcmp(const pbox *a,const pbox *b) {
1465 if (a->pixcnt > b->pixcnt) return -1;
1466 if (a->pixcnt < b->pixcnt) return 1;
1471 boxcenter(int box,cvec *cv) {
1472 cv->r=15+((box&448)>>1);
1473 cv->g=15+((box&56)<<2);
1474 cv->b=15+((box&7)<<5);
1478 bbox(int box,int *r0,int *r1,int *g0,int *g1,int *b0,int *b1) {
1488 boxrand(int box,cvec *cv) {
1489 cv->r=6+(rand()%25)+((box&448)>>1);
1490 cv->g=6+(rand()%25)+((box&56)<<2);
1491 cv->b=6+(rand()%25)+((box&7)<<5);
1501 while (w >= 1 || w == 0) {
1502 u1 = 2 * frand() - 1;
1503 u2 = 2 * frand() - 1;
1507 w = sqrt((-2*log(w))/w);
1511 /* Create hash index */
1514 cr_hashindex(cvec clr[256],int cnum,hashbox hb[512]) {
1516 int bx,mind,cd,cumcnt,bst_idx,i;
1517 /* printf("indexing... \n");*/
1520 for(bx=0; bx<512; bx++) {
1522 for(i=0; i<cnum; i++) {
1523 cd = maxdist(bx,&clr[i]);
1524 if (cd < mind) { mind=cd; bst_idx=i; }
1528 for(i=0;i<cnum;i++) if (mindist(bx,&clr[i])<mind) hb[bx].vec[hb[bx].cnt++]=i;
1529 /*printf("box %d -> approx -> %d\n",bx,hb[bx].cnt); */
1530 /* statbox(bx,cnum,clr); */
1534 /* printf("Average search space: %d\n",cumcnt/512); */
1538 maxdist(int boxnum,cvec *cv) {
1539 int r0,r1,g0,g1,b0,b1;
1546 bbox(boxnum,&r0,&r1,&g0,&g1,&b0,&b1);
1548 mr=i_max(abs(b-b0),abs(b-b1));
1549 mg=i_max(abs(g-g0),abs(g-g1));
1550 mb=i_max(abs(r-r0),abs(r-r1));
1552 return PWR2(mr)+PWR2(mg)+PWR2(mb);
1556 mindist(int boxnum,cvec *cv) {
1557 int r0,r1,g0,g1,b0,b1;
1564 bbox(boxnum,&r0,&r1,&g0,&g1,&b0,&b1);
1566 /* printf("box %d, (%d,%d,%d)-(%d,%d,%d) vec (%d,%d,%d) ",boxnum,r0,g0,b0,r1,g1,b1,r,g,b); */
1568 if (r0<=r && r<=r1 && g0<=g && g<=g1 && b0<=b && b<=b1) return 0;
1570 mr=i_min(abs(b-b0),abs(b-b1));
1571 mg=i_min(abs(g-g0),abs(g-g1));
1572 mb=i_min(abs(r-r0),abs(r-r1));
1578 if (r0<=r && r<=r1 && g0<=g && g<=g1) return mb;
1579 if (r0<=r && r<=r1 && b0<=b && b<=b1) return mg;
1580 if (b0<=b && b<=b1 && g0<=g && g<=g1) return mr;
1582 if (r0<=r && r<=r1) return mg+mb;
1583 if (g0<=g && g<=g1) return mr+mb;
1584 if (b0<=b && b<=b1) return mg+mr;
1589 static void transparent_threshold(i_quantize *, i_palidx *, i_img *, i_palidx);
1590 static void transparent_errdiff(i_quantize *, i_palidx *, i_img *, i_palidx);
1591 static void transparent_ordered(i_quantize *, i_palidx *, i_img *, i_palidx);
1593 void quant_transparent(i_quantize *quant, i_palidx *data, i_img *img,
1594 i_palidx trans_index)
1596 switch (quant->transp) {
1601 quant->tr_threshold = 128;
1604 transparent_threshold(quant, data, img, trans_index);
1608 transparent_errdiff(quant, data, img, trans_index);
1612 transparent_ordered(quant, data, img, trans_index);
1618 transparent_threshold(i_quantize *quant, i_palidx *data, i_img *img,
1619 i_palidx trans_index)
1622 i_sample_t *line = mymalloc(img->xsize * sizeof(i_sample_t));
1623 int trans_chan = img->channels > 2 ? 3 : 1;
1625 for (y = 0; y < img->ysize; ++y) {
1626 i_gsamp(img, 0, img->xsize, y, line, &trans_chan, 1);
1627 for (x = 0; x < img->xsize; ++x) {
1628 if (line[x] < quant->tr_threshold)
1629 data[y*img->xsize+x] = trans_index;
1636 transparent_errdiff(i_quantize *quant, i_palidx *data, i_img *img,
1637 i_palidx trans_index)
1641 int mapw, maph, mapo;
1642 int errw, *err, *errp;
1643 int difftotal, out, error;
1644 int x, y, dx, dy, i;
1646 int trans_chan = img->channels > 2 ? 3 : 1;
1648 /* no custom map for transparency (yet) */
1649 index = quant->tr_errdiff & ed_mask;
1650 if (index >= ed_custom) index = ed_floyd;
1651 map = maps[index].map;
1652 mapw = maps[index].width;
1653 maph = maps[index].height;
1654 mapo = maps[index].orig;
1656 errw = img->xsize+mapw-1;
1657 err = mymalloc(sizeof(*err) * maph * errw);
1659 memset(err, 0, sizeof(*err) * maph * errw);
1661 line = mymalloc(img->xsize * sizeof(i_sample_t));
1663 for (i = 0; i < maph * mapw; ++i)
1664 difftotal += map[i];
1665 for (y = 0; y < img->ysize; ++y) {
1666 i_gsamp(img, 0, img->xsize, y, line, &trans_chan, 1);
1667 for (x = 0; x < img->xsize; ++x) {
1668 line[x] = g_sat(line[x]-errp[x]/difftotal);
1669 if (line[x] < 128) {
1671 data[y*img->xsize+x] = trans_index;
1676 error = out - line[x];
1677 for (dx = 0; dx < mapw; ++dx) {
1678 for (dy = 0; dy < maph; ++dy) {
1679 errp[x+dx-mapo+dy*errw] += error * map[dx+mapw*dy];
1683 /* shift up the error matrix */
1684 for (dy = 0; dy < maph-1; ++dy)
1685 memcpy(err+dy*errw, err+(dy+1)*errw, sizeof(*err)*errw);
1686 memset(err+(maph-1)*errw, 0, sizeof(*err)*errw);
1692 /* builtin ordered dither maps */
1693 static unsigned char
1694 orddith_maps[][64] =
1697 this is purely random - it's pretty awful
1699 48, 72, 196, 252, 180, 92, 108, 52,
1700 228, 176, 64, 8, 236, 40, 20, 164,
1701 120, 128, 84, 116, 24, 28, 172, 220,
1702 68, 0, 188, 124, 184, 224, 192, 104,
1703 132, 100, 240, 200, 152, 160, 244, 44,
1704 96, 204, 144, 16, 140, 56, 232, 216,
1705 208, 4, 76, 212, 136, 248, 80, 168,
1706 156, 88, 32, 112, 148, 12, 36, 60,
1710 perl spot.perl '($x-3.5)*($x-3.5)+($y-3.5)*($y-3.5)'
1712 240, 232, 200, 136, 140, 192, 228, 248,
1713 220, 148, 100, 76, 80, 104, 152, 212,
1714 180, 116, 56, 32, 36, 60, 120, 176,
1715 156, 64, 28, 0, 8, 44, 88, 160,
1716 128, 92, 24, 12, 4, 40, 68, 132,
1717 184, 96, 48, 20, 16, 52, 108, 188,
1718 216, 144, 112, 72, 84, 124, 164, 224,
1719 244, 236, 196, 168, 172, 204, 208, 252,
1723 'min(dist(1.5, 1.5),dist(5.5,1.5),dist(1.5,5.5),dist(5.5,5.5))'
1725 196, 72, 104, 220, 200, 80, 112, 224,
1726 76, 4, 24, 136, 84, 8, 32, 144,
1727 108, 28, 52, 168, 116, 36, 56, 176,
1728 216, 140, 172, 244, 228, 148, 180, 248,
1729 204, 92, 124, 236, 192, 68, 96, 208,
1730 88, 12, 44, 156, 64, 0, 16, 128,
1731 120, 40, 60, 188, 100, 20, 48, 160,
1732 232, 152, 184, 252, 212, 132, 164, 240,
1735 perl spot.perl '$y-3'
1737 160, 164, 168, 172, 176, 180, 184, 188,
1738 128, 132, 136, 140, 144, 148, 152, 156,
1739 32, 36, 40, 44, 48, 52, 56, 60,
1740 0, 4, 8, 12, 16, 20, 24, 28,
1741 64, 68, 72, 76, 80, 84, 88, 92,
1742 96, 100, 104, 108, 112, 116, 120, 124,
1743 192, 196, 200, 204, 208, 212, 216, 220,
1744 224, 228, 232, 236, 240, 244, 248, 252,
1747 perl spot.perl '$x-3'
1749 180, 100, 40, 12, 44, 104, 184, 232,
1750 204, 148, 60, 16, 64, 128, 208, 224,
1751 212, 144, 76, 8, 80, 132, 216, 244,
1752 160, 112, 68, 20, 84, 108, 172, 236,
1753 176, 96, 72, 28, 88, 152, 188, 228,
1754 200, 124, 92, 0, 32, 116, 164, 240,
1755 168, 120, 36, 24, 48, 136, 192, 248,
1756 196, 140, 52, 4, 56, 156, 220, 252,
1759 perl spot.perl '$y+$x-7'
1761 248, 232, 224, 192, 140, 92, 52, 28,
1762 240, 220, 196, 144, 108, 60, 12, 64,
1763 216, 180, 148, 116, 76, 20, 80, 128,
1764 204, 152, 104, 44, 16, 72, 100, 160,
1765 164, 96, 68, 24, 56, 112, 168, 176,
1766 124, 40, 8, 36, 88, 136, 184, 212,
1767 84, 4, 32, 120, 156, 188, 228, 236,
1768 0, 48, 132, 172, 200, 208, 244, 252,
1771 perl spot.perl '$y-$x'
1773 0, 32, 116, 172, 184, 216, 236, 252,
1774 56, 8, 72, 132, 136, 200, 228, 240,
1775 100, 36, 12, 40, 92, 144, 204, 220,
1776 168, 120, 60, 16, 44, 96, 156, 176,
1777 180, 164, 112, 48, 28, 52, 128, 148,
1778 208, 192, 152, 88, 84, 20, 64, 104,
1779 232, 224, 196, 140, 108, 68, 24, 76,
1780 248, 244, 212, 188, 160, 124, 80, 4,
1784 good for display, bad for print
1787 0, 128, 32, 192, 8, 136, 40, 200,
1788 224, 64, 160, 112, 232, 72, 168, 120,
1789 48, 144, 16, 208, 56, 152, 24, 216,
1790 176, 96, 240, 80, 184, 104, 248, 88,
1791 12, 140, 44, 204, 4, 132, 36, 196,
1792 236, 76, 172, 124, 228, 68, 164, 116,
1793 60, 156, 28, 220, 52, 148, 20, 212,
1794 188, 108, 252, 92, 180, 100, 244, 84,
1799 transparent_ordered(i_quantize *quant, i_palidx *data, i_img *img,
1800 i_palidx trans_index)
1802 unsigned char *spot;
1805 int trans_chan = img->channels > 2 ? 3 : 1;
1806 if (quant->tr_orddith == od_custom)
1807 spot = quant->tr_custom;
1809 spot = orddith_maps[quant->tr_orddith];
1811 line = mymalloc(img->xsize * sizeof(i_sample_t));
1812 for (y = 0; y < img->ysize; ++y) {
1813 i_gsamp(img, 0, img->xsize, y, line, &trans_chan, 1);
1814 for (x = 0; x < img->xsize; ++x) {
1815 if (line[x] < spot[(x&7)+(y&7)*8])
1816 data[x+y*img->xsize] = trans_index;