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;
415 clr = i_mempool_alloc(&mp, sizeof(cvec) * quant->mc_size);
416 hb = i_mempool_alloc(&mp, sizeof(hashbox) * 512);
417 for (i=0; i < quant->mc_count; ++i) {
418 clr[i].r = quant->mc_colors[i].rgb.r;
419 clr[i].g = quant->mc_colors[i].rgb.g;
420 clr[i].b = quant->mc_colors[i].rgb.b;
424 /* mymalloc doesn't clear memory, so I think we need this */
425 for (; i < quant->mc_size; ++i) {
429 cnum = quant->mc_size;
432 for (img_num = 0; img_num < count; ++img_num) {
433 if (imgs[img_num]->xsize > maxwidth)
434 maxwidth = imgs[img_num]->xsize;
436 line = i_mempool_alloc(&mp, 3 * maxwidth * sizeof(*line));
438 prescan(imgs, count, cnum, clr, line);
439 cr_hashindex(clr, cnum, hb);
441 for(iter=0;iter<3;iter++) {
444 for (img_num = 0; img_num < count; ++img_num) {
445 i_img *im = imgs[img_num];
446 sample_indices = im->channels >= 3 ? NULL : gray_samples;
447 for(y=0;y<im->ysize;y++) {
448 i_gsamp(im, 0, im->xsize, y, line, sample_indices, 3);
450 for(x=0;x<im->xsize;x++) {
452 /*i_gpix(im,x,y,&val);*/
453 currhb=pixbox_ch(val);
454 /* printf("box = %d \n",currhb); */
455 for(i=0;i<hb[currhb].cnt;i++) {
456 /* 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); */
458 cd=eucl_d_ch(&clr[hb[currhb].vec[i]],val);
460 ld=cd; /* shortest distance yet */
461 bst_idx=hb[currhb].vec[i]; /* index of closest vector yet */
465 clr[bst_idx].mcount++;
467 clr[bst_idx].dr+=val[0];
468 clr[bst_idx].dg+=val[1];
469 clr[bst_idx].db+=val[2];
471 val += 3; /* next 3 samples (next pixel) */
478 clr[i].dr/=clr[i].mcount;
479 clr[i].dg/=clr[i].mcount;
480 clr[i].db/=clr[i].mcount;
483 /* for(i=0;i<cnum;i++) printf("vec(%d)=(%d,%d,%d) dest=(%d,%d,%d) matchcount=%d\n",
484 i,clr[i].r,clr[i].g,clr[i].b,clr[i].dr,clr[i].dg,clr[i].db,clr[i].mcount); */
486 /* printf("total error: %.2f\n",sqrt(accerr)); */
488 for(i=0;i<cnum;i++) {
489 if (clr[i].fixed) continue; /* skip reserved colors */
493 clr[i].r=clr[i].r*(1-dlt)+dlt*clr[i].dr;
494 clr[i].g=clr[i].g*(1-dlt)+dlt*clr[i].dg;
495 clr[i].b=clr[i].b*(1-dlt)+dlt*clr[i].db;
497 /* let's try something else */
509 cr_hashindex(clr,cnum,hb);
514 for(i=0;i<cnum;i++) {
515 cd=eucl_d(&clr[i],&val);
523 /* if defined, we only include colours with an mcount or that were
524 supplied in the fixed palette, giving us a smaller output palette */
525 #define ONLY_USE_USED
527 /* transfer the colors back */
529 for (i = 0; i < cnum; ++i) {
530 if (clr[i].fixed || clr[i].used) {
531 /*printf("Adding %d (%d,%d,%d)\n", i, clr[i].r, clr[i].g, clr[i].b);*/
532 quant->mc_colors[quant->mc_count].rgb.r = clr[i].r;
533 quant->mc_colors[quant->mc_count].rgb.g = clr[i].g;
534 quant->mc_colors[quant->mc_count].rgb.b = clr[i].b;
539 /* transfer the colors back */
540 for (i = 0; i < cnum; ++i) {
541 quant->mc_colors[i].rgb.r = clr[i].r;
542 quant->mc_colors[i].rgb.g = clr[i].g;
543 quant->mc_colors[i].rgb.b = clr[i].b;
545 quant->mc_count = cnum;
548 i_mempool_destroy(&mp);
556 #define MEDIAN_CUT_COLORS 32768
558 #define MED_CUT_INDEX(c) ((((c).rgb.r & 0xF8) << 7) | \
559 (((c).rgb.g & 0xF8) << 2) | (((c).rgb.b & 0xF8) >> 3))
561 #define MED_CUT_GRAY_INDEX(c) ((((c).rgb.r & 0xF8) << 7) | \
562 (((c).rgb.r & 0xF8) << 2) | (((c).rgb.r & 0xF8) >> 3))
564 /* scale these to cover the whole range */
565 #define MED_CUT_RED(index) ((((index) & 0x7C00) >> 10) * 255 / 31)
566 #define MED_CUT_GREEN(index) ((((index) & 0x3E0) >> 5) * 255 / 31)
567 #define MED_CUT_BLUE(index) (((index) & 0x1F) * 255 / 31)
570 i_sample_t min[3]; /* minimum for each channel */
571 i_sample_t max[3]; /* maximum for each channel */
572 i_sample_t width[3]; /* width for each channel */
573 int start, size; /* beginning and size of the partition */
574 int pixels; /* number of pixels represented by this partition */
578 =item calc_part(part, colors)
580 Calculates the new color limits for the given partition.
582 Giflib assumes that the limits for the non-split channels stay the
583 same, but this strikes me as incorrect, especially if the colors tend
586 Of course this could be optimized by not recalculating the channel we
587 just sorted on, but it's not worth the effort right now.
591 static void calc_part(medcut_partition *part, quant_color_entry *colors) {
594 for (ch = 0; ch < 3; ++ch) {
598 for (i = part->start; i < part->start + part->size; ++i) {
599 for (ch = 0; ch < 3; ++ch) {
600 if (part->min[ch] > colors[i].rgb[ch])
601 part->min[ch] = colors[i].rgb[ch];
602 if (part->max[ch] < colors[i].rgb[ch])
603 part->max[ch] = colors[i].rgb[ch];
606 for (ch = 0; ch < 3; ++ch) {
607 part->width[ch] = part->max[ch] - part->min[ch];
611 /* simple functions to sort by each channel - we could use a global, but
615 color_sort_red(void const *left, void const *right) {
616 return ((quant_color_entry *)left)->rgb[0] - ((quant_color_entry *)right)->rgb[0];
620 color_sort_green(void const *left, void const *right) {
621 return ((quant_color_entry *)left)->rgb[1] - ((quant_color_entry *)right)->rgb[1];
625 color_sort_blue(void const *left, void const *right) {
626 return ((quant_color_entry *)left)->rgb[2] - ((quant_color_entry *)right)->rgb[2];
629 static int (*sorters[])(void const *, void const *) =
637 makemap_mediancut(i_quantize *quant, i_img **imgs, int count) {
638 quant_color_entry *colors;
640 int imgn, x, y, i, ch;
645 medcut_partition *parts;
648 /* number of channels we search for the best channel to partition
649 this isn't terribly efficient, but it should work */
652 /*printf("images %d pal size %d\n", count, quant->mc_size);*/
656 colors = i_mempool_alloc(&mp, sizeof(*colors) * MEDIAN_CUT_COLORS);
657 for (i = 0; i < MEDIAN_CUT_COLORS; ++i) {
658 colors[i].rgb[0] = MED_CUT_RED(i);
659 colors[i].rgb[1] = MED_CUT_GREEN(i);
660 colors[i].rgb[2] = MED_CUT_BLUE(i);
665 for (imgn = 0; imgn < count; ++imgn) {
666 if (imgs[imgn]->xsize > max_width)
667 max_width = imgs[imgn]->xsize;
669 line = i_mempool_alloc(&mp, sizeof(i_color) * max_width);
671 /* build the stats */
673 chan_count = 1; /* assume we just have grayscale */
674 for (imgn = 0; imgn < count; ++imgn) {
675 total_pixels += imgs[imgn]->xsize * imgs[imgn]->ysize;
676 for (y = 0; y < imgs[imgn]->ysize; ++y) {
677 i_glin(imgs[imgn], 0, imgs[imgn]->xsize, y, line);
678 if (imgs[imgn]->channels > 2) {
680 for (x = 0; x < imgs[imgn]->xsize; ++x) {
681 ++colors[MED_CUT_INDEX(line[x])].count;
685 /* a gray-scale image, just use the first channel */
686 for (x = 0; x < imgs[imgn]->xsize; ++x) {
687 ++colors[MED_CUT_GRAY_INDEX(line[x])].count;
693 /* eliminate the empty colors */
695 for (in = 0; in < MEDIAN_CUT_COLORS; ++in) {
696 if (colors[in].count) {
697 colors[out++] = colors[in];
700 /*printf("out %d\n", out);
702 for (i = 0; i < out; ++i) {
703 if (colors[i].count) {
704 printf("%d: (%d,%d,%d) -> %d\n", i, colors[i].rgb[0], colors[i].rgb[1],
705 colors[i].rgb[2], colors[i].count);
709 if (out < quant->mc_size) {
710 /* just copy them into the color table */
711 for (i = 0; i < out; ++i) {
712 for (ch = 0; ch < 3; ++ch) {
713 quant->mc_colors[i].channel[ch] = colors[i].rgb[ch];
716 quant->mc_count = out;
719 /* build the starting partition */
720 parts = i_mempool_alloc(&mp, sizeof(*parts) * quant->mc_size);
723 parts[0].pixels = total_pixels;
724 calc_part(parts, colors);
727 while (color_count < quant->mc_size) {
728 int max_index, max_ch; /* index/channel with biggest spread */
730 medcut_partition *workpart;
734 /* find the partition with the most biggest span with more than
737 for (i = 0; i < color_count; ++i) {
738 for (ch = 0; ch < chan_count; ++ch) {
739 if (parts[i].width[ch] > max_size
740 && parts[i].size > 1) {
743 max_size = parts[i].width[ch];
748 /* nothing else we can split */
752 workpart = parts+max_index;
753 /*printf("splitting partition %d (pixels %ld, start %d, size %d)\n", max_index, workpart->pixels, workpart->start, workpart->size);*/
754 qsort(colors + workpart->start, workpart->size, sizeof(*colors),
757 /* find the median or something like it we need to make sure both
758 sides of the split have at least one color in them, so we don't
759 test at the first or last entry */
761 cum_total = colors[i].count;
763 half = workpart->pixels / 2;
764 while (i < workpart->start + workpart->size - 1
765 && cum_total < half) {
766 cum_total += colors[i++].count;
768 /*printf("Split at %d to make %d (half %ld, cumtotal %ld)\n", i, color_count, half, cum_total);*/
770 /* found the spot to split */
771 parts[color_count].start = i;
772 parts[color_count].size = workpart->start + workpart->size - i;
773 workpart->size = i - workpart->start;
774 parts[color_count].pixels = workpart->pixels - cum_total;
775 workpart->pixels = cum_total;
777 /* recalculate the limits */
778 calc_part(workpart, colors);
779 calc_part(parts+color_count, colors);
783 /* fill in the color table - since we could still have partitions
784 that have more than one color, we need to average the colors */
785 for (part_num = 0; part_num < color_count; ++part_num) {
787 medcut_partition *workpart;
789 workpart = parts+part_num;
790 for (ch = 0; ch < 3; ++ch)
793 for (i = workpart->start; i < workpart->start + workpart->size; ++i) {
794 for (ch = 0; ch < 3; ++ch) {
795 sums[ch] += colors[i].rgb[ch] * colors[i].count;
798 for (ch = 0; ch < 3; ++ch) {
799 quant->mc_colors[part_num].channel[ch] = sums[ch] / workpart->pixels;
802 quant->mc_count = color_count;
804 /*printf("out %d colors\n", quant->mc_count);*/
805 i_mempool_destroy(&mp);
810 /* Define one of the following 4 symbols to choose a colour search method
811 The idea is to try these out, including benchmarking, to see which
812 is fastest in a good spread of circumstances.
813 I'd expect IM_CFLINSEARCH to be fastest for very small palettes, and
814 IM_CFHASHBOX for large images with large palettes.
816 Some other possibilities include:
817 - search over entries sorted by luminance
819 Initially I was planning on testing using the macros and then
820 integrating the code directly into each function, but this means if
821 we find a bug at a late stage we will need to update N copies of
822 the same code. Also, keeping the code in the macros means that the
823 code in the translation functions is much more to the point,
824 there's no distracting colour search code to remove attention from
825 what makes _this_ translation function different. It may be
826 advisable to move the setup code into functions at some point, but
827 it should be possible to do this fairly transparently.
829 If IM_CF_COPTS is defined then CFLAGS must have an appropriate
832 Each option needs to define 4 macros:
833 CF_VARS - variables to define in the function
834 CF_SETUP - code to setup for the colour search, eg. allocating and
835 initializing lookup tables
836 CF_FIND - code that looks for the color in val and puts the best
837 matching index in bst_idx
838 CF_CLEANUP - code to clean up, eg. releasing memory
841 /*#define IM_CFLINSEARCH*/
843 /*#define IM_CFSORTCHAN*/
844 /*#define IM_CFRAND2DIST*/
849 /* The original version I wrote for this used the sort.
850 If this is defined then we use a sort to extract the indices for
854 /* assume i is available */
855 #define CF_VARS hashbox *hb = mymalloc(sizeof(hashbox) * 512); \
861 static long *gdists; /* qsort is annoying */
862 /* int might be smaller than long, so we need to do a real compare
863 rather than a subtraction*/
864 static int distcomp(void const *a, void const *b) {
865 long ra = gdists[*(int const *)a];
866 long rb = gdists[*(int const *)b];
877 /* for each hashbox build a list of colours that are in the hb or is closer
879 This is pretty involved. The original gifquant generated the hashbox
880 as part of it's normal processing, but since the map generation is now
881 separated from the translation we need to do this on the spot.
882 Any optimizations, even if they don't produce perfect results would be
885 static void hbsetup(i_quantize *quant, hashbox *hb) {
886 long *dists, mind, maxd, cd;
887 int cr, cb, cg, hbnum, i;
890 int *indices = mymalloc(quant->mc_count * sizeof(int));
893 dists = mymalloc(quant->mc_count * sizeof(long));
894 for (cr = 0; cr < 8; ++cr) {
895 for (cg = 0; cg < 8; ++cg) {
896 for (cb = 0; cb < 8; ++cb) {
897 /* centre of the hashbox */
898 cenc.channel[0] = cr*pboxjump+pboxjump/2;
899 cenc.channel[1] = cg*pboxjump+pboxjump/2;
900 cenc.channel[2] = cb*pboxjump+pboxjump/2;
901 hbnum = pixbox(&cenc);
903 /* order indices in the order of distance from the hashbox */
904 for (i = 0; i < quant->mc_count; ++i) {
908 dists[i] = ceucl_d(&cenc, quant->mc_colors+i);
911 /* it should be possible to do this without a sort
912 but so far I'm too lazy */
914 qsort(indices, quant->mc_count, sizeof(int), distcomp);
915 /* any colors that can match are within mind+diagonal size of
917 mind = dists[indices[0]];
919 maxd = (sqrt(mind)+pboxjump)*(sqrt(mind)+pboxjump);
920 while (i < quant->mc_count && dists[indices[i]] < maxd) {
921 hb[hbnum].vec[hb[hbnum].cnt++] = indices[i++];
924 /* work out the minimum */
926 for (i = 0; i < quant->mc_count; ++i) {
927 if (dists[i] < mind) mind = dists[i];
929 /* transfer any colours that might be closest to a colour in
931 maxd = (sqrt(mind)+pboxjump)*(sqrt(mind)+pboxjump);
932 for (i = 0; i < quant->mc_count; ++i) {
934 hb[hbnum].vec[hb[hbnum].cnt++] = i;
945 #define CF_SETUP hbsetup(quant, hb)
948 currhb = pixbox(&val); \
950 for (i = 0; i < hb[currhb].cnt; ++i) { \
951 cd = ceucl_d(quant->mc_colors+hb[currhb].vec[i], &val); \
952 if (cd < ld) { ld = cd; bst_idx = hb[currhb].vec[i]; } \
955 #define CF_CLEANUP myfree(hb)
959 #ifdef IM_CFLINSEARCH
960 /* as simple as it gets */
961 #define CF_VARS long ld, cd
962 #define CF_SETUP /* none needed */
965 for (i = 0; i < quant->mc_count; ++i) { \
966 cd = ceucl_d(quant->mc_colors+i, &val); \
967 if (cd < ld) { ld = cd; bst_idx = i; } \
973 static int gsortchan;
974 static i_quantize *gquant;
975 static int chansort(void const *a, void const *b) {
976 return gquant->mc_colors[*(int const *)a].channel[gsortchan] -
977 gquant->mc_colors[*(int const *)b].channel[gsortchan];
979 #define CF_VARS int *indices, sortchan, diff; \
981 int vindex[256] /* where to find value i of chan */
983 static void chansetup(i_img *img, i_quantize *quant, int *csortchan,
984 int *vindex, int **cindices) {
985 int *indices, sortchan, chan, i, chval;
986 int chanmins[MAXCHANNELS], chanmaxs[MAXCHANNELS], maxrange;
988 /* find the channel with the maximum range */
989 /* the maximum stddev would probably be better */
990 for (chan = 0; chan < img->channels; ++chan) {
991 chanmins[chan] = 256; chanmaxs[chan] = 0;
992 for (i = 0; i < quant->mc_count; ++i) {
993 if (quant->mc_colors[i].channel[chan] < chanmins[chan])
994 chanmins[chan] = quant->mc_colors[i].channel[chan];
995 if (quant->mc_colors[i].channel[chan] > chanmaxs[chan])
996 chanmaxs[chan] = quant->mc_colors[i].channel[chan];
1000 for (chan = 0; chan < img->channels; ++chan) {
1001 if (chanmaxs[chan]-chanmins[chan] > maxrange) {
1002 maxrange = chanmaxs[chan]-chanmins[chan];
1006 indices = mymalloc(quant->mc_count * sizeof(int)) ;
1007 for (i = 0; i < quant->mc_count; ++i) {
1010 gsortchan = sortchan;
1012 qsort(indices, quant->mc_count, sizeof(int), chansort) ;
1013 /* now a lookup table to find entries faster */
1014 for (chval=0, i=0; i < quant->mc_count; ++i) {
1015 while (chval < 256 &&
1016 chval < quant->mc_colors[indices[i]].channel[sortchan]) {
1017 vindex[chval++] = i;
1020 while (chval < 256) {
1021 vindex[chval++] = quant->mc_count-1;
1023 *csortchan = sortchan;
1024 *cindices = indices;
1028 chansetup(img, quant, &sortchan, vindex, &indices)
1030 int chanfind(i_color val, i_quantize *quant, int *indices, int *vindex,
1032 int i, bst_idx, diff, maxdiff;
1035 i = vindex[val.channel[sortchan]];
1036 bst_idx = indices[i];
1039 maxdiff = quant->mc_count;
1040 while (diff < maxdiff) {
1041 if (i+diff < quant->mc_count) {
1042 cd = ceucl_d(&val, quant->mc_colors+indices[i+diff]);
1044 bst_idx = indices[i+diff];
1050 cd = ceucl_d(&val, quant->mc_colors+indices[i-diff]);
1052 bst_idx = indices[i-diff];
1064 bst_idx = chanfind(val, quant, indices, vindex, sortchan)
1067 #define CF_CLEANUP myfree(indices)
1071 #ifdef IM_CFRAND2DIST
1073 /* This is based on a method described by Addi in the #imager channel
1074 on the 28/2/2001. I was about 1am Sydney time at the time, so I
1075 wasn't at my most cogent. Well, that's my excuse :)
1077 <TonyC> what I have at the moment is: hashboxes, with optimum hash box
1078 filling; simple linear search; and a lookup in the widest channel
1079 (currently the channel with the maximum range)
1080 <Addi> There is one more way that might be simple to implement.
1081 <Addi> You want to hear?
1082 <TonyC> what's that?
1083 <purl> somebody said that was not true
1084 <Addi> For each of the colors in the palette start by creating a
1085 sorted list of the form:
1086 <Addi> [distance, color]
1087 <Addi> Where they are sorted by distance.
1088 <TonyC> distance to where?
1089 <Addi> Where the elements in the lists are the distances and colors of
1090 the other colors in the palette
1092 <Addi> So if you are at color 0
1093 <Addi> ok - now to search for the closest color when you are creating
1094 the final image is done like this:
1095 <Addi> a) pick a random color from the palette
1096 <Addi> b) calculate the distance to it
1097 <Addi> c) only check the vectors that are within double the distance
1098 in the list of the color you picked from the palette.
1099 <Addi> Does that seem logical?
1100 <Addi> Lets imagine that we only have grayscale to make an example:
1101 <Addi> Our palette has 1 4 10 20 as colors.
1102 <Addi> And we want to quantize the color 11
1103 <Addi> lets say we picked 10 randomly
1104 <Addi> the double distance is 2
1105 <Addi> since abs(10-11)*2 is 2
1106 <Addi> And the list at vector 10 is this:
1107 <Addi> [0, 10], [6 4], [9, 1], [10, 20]
1108 <Addi> so we look at the first one (but not the second one since 6 is
1109 at a greater distance than 2.
1110 <Addi> Any of that make sense?
1111 <TonyC> yes, though are you suggesting another random jump to one of
1112 the colours with the possible choices? or an exhaustive search?
1113 <Addi> TonyC: It's possible to come up with a recursive/iterative
1114 enhancement but this is the 'basic' version.
1115 <Addi> Which would do an iterative search.
1116 <Addi> You can come up with conditions where it pays to switch to a new one.
1117 <Addi> And the 'random' start can be switched over to a small tree.
1118 <Addi> So you would have a little index at the start.
1119 <Addi> to get you into the general direction
1120 <Addi> Perhaps just an 8 split.
1121 <Addi> that is - split each dimension in half.
1123 <TonyC> I get the idea
1124 <Addi> But this would seem to be a good approach in our case since we
1125 usually have few codevectors.
1126 <Addi> So we only need 256*256 entries in a table.
1127 <Addi> We could even only index some of them that were deemed as good
1129 <TonyC> I was considering adding paletted output support for PNG and
1130 TIFF at some point, which support 16-bit palettes
1138 typedef struct i_dists {
1146 static int dists_sort(void const *a, void const *b) {
1147 return ((i_dists *)a)->dist - ((i_dists *)b)->dist;
1150 static void rand2dist_setup(i_quantize *quant, i_dists **cdists) {
1152 mymalloc(sizeof(i_dists)*quant->mc_count*quant->mc_count);
1155 for (i = 0; i < quant->mc_count; ++i) {
1156 i_dists *ldists = dists + quant->mc_count * i;
1157 i_color val = quant->mc_colors[i];
1158 for (j = 0; j < quant->mc_count; ++j) {
1159 ldists[j].index = j;
1160 ldists[j].dist = ceucl_d(&val, quant->mc_colors+j);
1162 qsort(ldists, quant->mc_count, sizeof(i_dists), dists_sort);
1168 bst_idx = rand() % quant->mc_count; \
1169 rand2dist_setup(quant, &dists)
1171 static int rand2dist_find(i_color val, i_quantize *quant, i_dists *dists, int index) {
1178 cdists = dists + index * quant->mc_count;
1180 maxld = 8 * ceucl_d(&val, quant->mc_colors+index);
1181 for (i = 0; i < quant->mc_count && cdists[i].dist <= maxld; ++i) {
1182 cd = ceucl_d(&val, quant->mc_colors+cdists[i].index);
1184 bst_idx = cdists[i].index;
1191 #define CF_FIND bst_idx = rand2dist_find(val, quant, dists, bst_idx)
1193 #define CF_CLEANUP myfree(dists)
1198 static void translate_addi(i_quantize *quant, i_img *img, i_palidx *out) {
1199 int x, y, i, k, bst_idx;
1201 int pixdev = quant->perturb;
1206 if (img->channels >= 3) {
1209 for(y=0;y<img->ysize;y++) for(x=0;x<img->xsize;x++) {
1210 i_gpix(img,x,y,&val);
1211 val.channel[0]=g_sat(val.channel[0]+(int)(pixdev*frandn()));
1212 val.channel[1]=g_sat(val.channel[1]+(int)(pixdev*frandn()));
1213 val.channel[2]=g_sat(val.channel[2]+(int)(pixdev*frandn()));
1219 for(y=0;y<img->ysize;y++) for(x=0;x<img->xsize;x++) {
1220 i_gpix(img,x,y,&val);
1229 for(y=0;y<img->ysize;y++) for(x=0;x<img->xsize;x++) {
1230 i_gpix(img,x,y,&val);
1231 val.channel[1] = val.channel[2] =
1232 val.channel[0]=g_sat(val.channel[0]+(int)(pixdev*frandn()));
1238 for(y=0;y<img->ysize;y++) for(x=0;x<img->xsize;x++) {
1239 i_gpix(img,x,y,&val);
1240 val.channel[1] = val.channel[2] = val.channel[0];
1249 static int floyd_map[] =
1255 static int jarvis_map[] =
1262 static int stucki_map[] =
1269 struct errdiff_map {
1271 int width, height, orig;
1274 static struct errdiff_map maps[] =
1276 { floyd_map, 3, 2, 1 },
1277 { jarvis_map, 5, 3, 2 },
1278 { stucki_map, 5, 3, 2 },
1281 typedef struct errdiff_tag {
1285 /* perform an error diffusion dither */
1288 translate_errdiff(i_quantize *quant, i_img *img, i_palidx *out) {
1290 int mapw, maph, mapo;
1296 int minr, maxr, ming, maxg, minb, maxb, cr, cg, cb;
1301 if ((quant->errdiff & ed_mask) == ed_custom) {
1302 map = quant->ed_map;
1303 mapw = quant->ed_width;
1304 maph = quant->ed_height;
1305 mapo = quant->ed_orig;
1308 int index = quant->errdiff & ed_mask;
1309 if (index >= ed_custom) index = ed_floyd;
1310 map = maps[index].map;
1311 mapw = maps[index].width;
1312 maph = maps[index].height;
1313 mapo = maps[index].orig;
1316 errw = img->xsize+mapw;
1317 err = mymalloc(sizeof(*err) * maph * errw);
1318 /*errp = err+mapo;*/
1319 memset(err, 0, sizeof(*err) * maph * errw);
1322 for (i = 0; i < maph * mapw; ++i)
1323 difftotal += map[i];
1325 for (dy = 0; dy < maph; ++dy) {
1326 for (dx = 0; dx < mapw; ++dx) {
1327 printf("%2d", map[dx+dy*mapw]);
1334 for (y = 0; y < img->ysize; ++y) {
1335 for (x = 0; x < img->xsize; ++x) {
1339 i_gpix(img, x, y, &val);
1340 if (img->channels < 3) {
1341 val.channel[1] = val.channel[2] = val.channel[0];
1344 perr.r = perr.r < 0 ? -((-perr.r)/difftotal) : perr.r/difftotal;
1345 perr.g = perr.g < 0 ? -((-perr.g)/difftotal) : perr.g/difftotal;
1346 perr.b = perr.b < 0 ? -((-perr.b)/difftotal) : perr.b/difftotal;
1347 /*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);*/
1348 val.channel[0] = g_sat(val.channel[0]-perr.r);
1349 val.channel[1] = g_sat(val.channel[1]-perr.g);
1350 val.channel[2] = g_sat(val.channel[2]-perr.b);
1353 perr.r = quant->mc_colors[bst_idx].channel[0] - val.channel[0];
1354 perr.g = quant->mc_colors[bst_idx].channel[1] - val.channel[1];
1355 perr.b = quant->mc_colors[bst_idx].channel[2] - val.channel[2];
1356 /*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);*/
1357 for (dx = 0; dx < mapw; ++dx) {
1358 for (dy = 0; dy < maph; ++dy) {
1359 err[x+dx+dy*errw].r += perr.r * map[dx+mapw*dy];
1360 err[x+dx+dy*errw].g += perr.g * map[dx+mapw*dy];
1361 err[x+dx+dy*errw].b += perr.b * map[dx+mapw*dy];
1366 /* shift up the error matrix */
1367 for (dy = 0; dy < maph-1; ++dy) {
1368 memcpy(err+dy*errw, err+(dy+1)*errw, sizeof(*err)*errw);
1370 memset(err+(maph-1)*errw, 0, sizeof(*err)*errw);
1375 /* Prescan finds the boxes in the image that have the highest number of colors
1376 and that result is used as the initial value for the vectores */
1379 static void prescan(i_img **imgs,int count, int cnum, cvec *clr, i_sample_t *line) {
1385 for(i=0;i<512;i++) {
1391 /* process each image */
1392 for (i = 0; i < count; ++i) {
1393 i_img *im = imgs[i];
1394 chans = im->channels >= 3 ? NULL : gray_samples;
1395 for(y=0;y<im->ysize;y++) {
1396 i_gsamp(im, 0, im->xsize, y, line, chans, 3);
1398 for(x=0;x<im->xsize;x++) {
1399 prebox[pixbox_ch(val)].pixcnt++;
1404 for(i=0;i<512;i++) prebox[i].pdc=prebox[i].pixcnt;
1405 qsort(prebox,512,sizeof(pbox),(cmpfunc)pboxcmp);
1407 for(i=0;i<cnum;i++) {
1408 /* printf("Color %d\n",i);
1409 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); }
1414 /* 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); } */
1420 /* printf("prebox[%d].cand=%d\n",k,prebox[k].cand); */
1421 if (clr[i].fixed) { i++; continue; } /* reserved go to next */
1422 if (j>=prebox[k].cand) { k++; j=1; } else {
1423 if (prebox[k].cand == 2) boxcenter(prebox[k].boxnum,&(clr[i]));
1424 else boxrand(prebox[k].boxnum,&(clr[i]));
1425 /* 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); */
1433 static void reorder(pbox prescan[512]) {
1441 c.pdc=c.pixcnt/(c.cand*c.cand);
1442 /* c.pdc=c.pixcnt/c.cand; */
1443 while(c.pdc < prescan[nidx+1].pdc && nidx < 511) {
1444 prescan[nidx]=prescan[nidx+1];
1451 pboxcmp(const pbox *a,const pbox *b) {
1452 if (a->pixcnt > b->pixcnt) return -1;
1453 if (a->pixcnt < b->pixcnt) return 1;
1458 boxcenter(int box,cvec *cv) {
1459 cv->r=15+((box&448)>>1);
1460 cv->g=15+((box&56)<<2);
1461 cv->b=15+((box&7)<<5);
1465 bbox(int box,int *r0,int *r1,int *g0,int *g1,int *b0,int *b1) {
1475 boxrand(int box,cvec *cv) {
1476 cv->r=6+(rand()%25)+((box&448)>>1);
1477 cv->g=6+(rand()%25)+((box&56)<<2);
1478 cv->b=6+(rand()%25)+((box&7)<<5);
1488 while (w >= 1 || w == 0) {
1489 u1 = 2 * frand() - 1;
1490 u2 = 2 * frand() - 1;
1494 w = sqrt((-2*log(w))/w);
1498 /* Create hash index */
1501 cr_hashindex(cvec clr[256],int cnum,hashbox hb[512]) {
1503 int bx,mind,cd,cumcnt,bst_idx,i;
1504 /* printf("indexing... \n");*/
1507 for(bx=0; bx<512; bx++) {
1509 for(i=0; i<cnum; i++) {
1510 cd = maxdist(bx,&clr[i]);
1511 if (cd < mind) { mind=cd; bst_idx=i; }
1515 for(i=0;i<cnum;i++) if (mindist(bx,&clr[i])<mind) hb[bx].vec[hb[bx].cnt++]=i;
1516 /*printf("box %d -> approx -> %d\n",bx,hb[bx].cnt); */
1517 /* statbox(bx,cnum,clr); */
1521 /* printf("Average search space: %d\n",cumcnt/512); */
1525 maxdist(int boxnum,cvec *cv) {
1526 int r0,r1,g0,g1,b0,b1;
1533 bbox(boxnum,&r0,&r1,&g0,&g1,&b0,&b1);
1535 mr=i_max(abs(b-b0),abs(b-b1));
1536 mg=i_max(abs(g-g0),abs(g-g1));
1537 mb=i_max(abs(r-r0),abs(r-r1));
1539 return PWR2(mr)+PWR2(mg)+PWR2(mb);
1543 mindist(int boxnum,cvec *cv) {
1544 int r0,r1,g0,g1,b0,b1;
1551 bbox(boxnum,&r0,&r1,&g0,&g1,&b0,&b1);
1553 /* printf("box %d, (%d,%d,%d)-(%d,%d,%d) vec (%d,%d,%d) ",boxnum,r0,g0,b0,r1,g1,b1,r,g,b); */
1555 if (r0<=r && r<=r1 && g0<=g && g<=g1 && b0<=b && b<=b1) return 0;
1557 mr=i_min(abs(b-b0),abs(b-b1));
1558 mg=i_min(abs(g-g0),abs(g-g1));
1559 mb=i_min(abs(r-r0),abs(r-r1));
1565 if (r0<=r && r<=r1 && g0<=g && g<=g1) return mb;
1566 if (r0<=r && r<=r1 && b0<=b && b<=b1) return mg;
1567 if (b0<=b && b<=b1 && g0<=g && g<=g1) return mr;
1569 if (r0<=r && r<=r1) return mg+mb;
1570 if (g0<=g && g<=g1) return mr+mb;
1571 if (b0<=b && b<=b1) return mg+mr;
1576 static void transparent_threshold(i_quantize *, i_palidx *, i_img *, i_palidx);
1577 static void transparent_errdiff(i_quantize *, i_palidx *, i_img *, i_palidx);
1578 static void transparent_ordered(i_quantize *, i_palidx *, i_img *, i_palidx);
1580 void quant_transparent(i_quantize *quant, i_palidx *data, i_img *img,
1581 i_palidx trans_index)
1583 switch (quant->transp) {
1588 quant->tr_threshold = 128;
1591 transparent_threshold(quant, data, img, trans_index);
1595 transparent_errdiff(quant, data, img, trans_index);
1599 transparent_ordered(quant, data, img, trans_index);
1605 transparent_threshold(i_quantize *quant, i_palidx *data, i_img *img,
1606 i_palidx trans_index)
1609 i_sample_t *line = mymalloc(img->xsize * sizeof(i_sample_t));
1610 int trans_chan = img->channels > 2 ? 3 : 1;
1612 for (y = 0; y < img->ysize; ++y) {
1613 i_gsamp(img, 0, img->xsize, y, line, &trans_chan, 1);
1614 for (x = 0; x < img->xsize; ++x) {
1615 if (line[x] < quant->tr_threshold)
1616 data[y*img->xsize+x] = trans_index;
1623 transparent_errdiff(i_quantize *quant, i_palidx *data, i_img *img,
1624 i_palidx trans_index)
1628 int mapw, maph, mapo;
1629 int errw, *err, *errp;
1630 int difftotal, out, error;
1631 int x, y, dx, dy, i;
1633 int trans_chan = img->channels > 2 ? 3 : 1;
1635 /* no custom map for transparency (yet) */
1636 index = quant->tr_errdiff & ed_mask;
1637 if (index >= ed_custom) index = ed_floyd;
1638 map = maps[index].map;
1639 mapw = maps[index].width;
1640 maph = maps[index].height;
1641 mapo = maps[index].orig;
1643 errw = img->xsize+mapw-1;
1644 err = mymalloc(sizeof(*err) * maph * errw);
1646 memset(err, 0, sizeof(*err) * maph * errw);
1648 line = mymalloc(img->xsize * sizeof(i_sample_t));
1650 for (i = 0; i < maph * mapw; ++i)
1651 difftotal += map[i];
1652 for (y = 0; y < img->ysize; ++y) {
1653 i_gsamp(img, 0, img->xsize, y, line, &trans_chan, 1);
1654 for (x = 0; x < img->xsize; ++x) {
1655 line[x] = g_sat(line[x]-errp[x]/difftotal);
1656 if (line[x] < 128) {
1658 data[y*img->xsize+x] = trans_index;
1663 error = out - line[x];
1664 for (dx = 0; dx < mapw; ++dx) {
1665 for (dy = 0; dy < maph; ++dy) {
1666 errp[x+dx-mapo+dy*errw] += error * map[dx+mapw*dy];
1670 /* shift up the error matrix */
1671 for (dy = 0; dy < maph-1; ++dy)
1672 memcpy(err+dy*errw, err+(dy+1)*errw, sizeof(*err)*errw);
1673 memset(err+(maph-1)*errw, 0, sizeof(*err)*errw);
1679 /* builtin ordered dither maps */
1680 static unsigned char
1681 orddith_maps[][64] =
1684 this is purely random - it's pretty awful
1686 48, 72, 196, 252, 180, 92, 108, 52,
1687 228, 176, 64, 8, 236, 40, 20, 164,
1688 120, 128, 84, 116, 24, 28, 172, 220,
1689 68, 0, 188, 124, 184, 224, 192, 104,
1690 132, 100, 240, 200, 152, 160, 244, 44,
1691 96, 204, 144, 16, 140, 56, 232, 216,
1692 208, 4, 76, 212, 136, 248, 80, 168,
1693 156, 88, 32, 112, 148, 12, 36, 60,
1697 perl spot.perl '($x-3.5)*($x-3.5)+($y-3.5)*($y-3.5)'
1699 240, 232, 200, 136, 140, 192, 228, 248,
1700 220, 148, 100, 76, 80, 104, 152, 212,
1701 180, 116, 56, 32, 36, 60, 120, 176,
1702 156, 64, 28, 0, 8, 44, 88, 160,
1703 128, 92, 24, 12, 4, 40, 68, 132,
1704 184, 96, 48, 20, 16, 52, 108, 188,
1705 216, 144, 112, 72, 84, 124, 164, 224,
1706 244, 236, 196, 168, 172, 204, 208, 252,
1710 'min(dist(1.5, 1.5),dist(5.5,1.5),dist(1.5,5.5),dist(5.5,5.5))'
1712 196, 72, 104, 220, 200, 80, 112, 224,
1713 76, 4, 24, 136, 84, 8, 32, 144,
1714 108, 28, 52, 168, 116, 36, 56, 176,
1715 216, 140, 172, 244, 228, 148, 180, 248,
1716 204, 92, 124, 236, 192, 68, 96, 208,
1717 88, 12, 44, 156, 64, 0, 16, 128,
1718 120, 40, 60, 188, 100, 20, 48, 160,
1719 232, 152, 184, 252, 212, 132, 164, 240,
1722 perl spot.perl '$y-3'
1724 160, 164, 168, 172, 176, 180, 184, 188,
1725 128, 132, 136, 140, 144, 148, 152, 156,
1726 32, 36, 40, 44, 48, 52, 56, 60,
1727 0, 4, 8, 12, 16, 20, 24, 28,
1728 64, 68, 72, 76, 80, 84, 88, 92,
1729 96, 100, 104, 108, 112, 116, 120, 124,
1730 192, 196, 200, 204, 208, 212, 216, 220,
1731 224, 228, 232, 236, 240, 244, 248, 252,
1734 perl spot.perl '$x-3'
1736 180, 100, 40, 12, 44, 104, 184, 232,
1737 204, 148, 60, 16, 64, 128, 208, 224,
1738 212, 144, 76, 8, 80, 132, 216, 244,
1739 160, 112, 68, 20, 84, 108, 172, 236,
1740 176, 96, 72, 28, 88, 152, 188, 228,
1741 200, 124, 92, 0, 32, 116, 164, 240,
1742 168, 120, 36, 24, 48, 136, 192, 248,
1743 196, 140, 52, 4, 56, 156, 220, 252,
1746 perl spot.perl '$y+$x-7'
1748 248, 232, 224, 192, 140, 92, 52, 28,
1749 240, 220, 196, 144, 108, 60, 12, 64,
1750 216, 180, 148, 116, 76, 20, 80, 128,
1751 204, 152, 104, 44, 16, 72, 100, 160,
1752 164, 96, 68, 24, 56, 112, 168, 176,
1753 124, 40, 8, 36, 88, 136, 184, 212,
1754 84, 4, 32, 120, 156, 188, 228, 236,
1755 0, 48, 132, 172, 200, 208, 244, 252,
1758 perl spot.perl '$y-$x'
1760 0, 32, 116, 172, 184, 216, 236, 252,
1761 56, 8, 72, 132, 136, 200, 228, 240,
1762 100, 36, 12, 40, 92, 144, 204, 220,
1763 168, 120, 60, 16, 44, 96, 156, 176,
1764 180, 164, 112, 48, 28, 52, 128, 148,
1765 208, 192, 152, 88, 84, 20, 64, 104,
1766 232, 224, 196, 140, 108, 68, 24, 76,
1767 248, 244, 212, 188, 160, 124, 80, 4,
1771 good for display, bad for print
1774 0, 128, 32, 192, 8, 136, 40, 200,
1775 224, 64, 160, 112, 232, 72, 168, 120,
1776 48, 144, 16, 208, 56, 152, 24, 216,
1777 176, 96, 240, 80, 184, 104, 248, 88,
1778 12, 140, 44, 204, 4, 132, 36, 196,
1779 236, 76, 172, 124, 228, 68, 164, 116,
1780 60, 156, 28, 220, 52, 148, 20, 212,
1781 188, 108, 252, 92, 180, 100, 244, 84,
1786 transparent_ordered(i_quantize *quant, i_palidx *data, i_img *img,
1787 i_palidx trans_index)
1789 unsigned char *spot;
1792 int trans_chan = img->channels > 2 ? 3 : 1;
1793 if (quant->tr_orddith == od_custom)
1794 spot = quant->tr_custom;
1796 spot = orddith_maps[quant->tr_orddith];
1798 line = mymalloc(img->xsize * sizeof(i_sample_t));
1799 for (y = 0; y < img->ysize; ++y) {
1800 i_gsamp(img, 0, img->xsize, y, line, &trans_chan, 1);
1801 for (x = 0; x < img->xsize; ++x) {
1802 if (line[x] < spot[(x&7)+(y&7)*8])
1803 data[x+y*img->xsize] = trans_index;