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, 0);
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 result = mymalloc(img->xsize * img->ysize);
86 switch (quant->translate) {
89 translate_closest(quant, img, result);
93 translate_errdiff(quant, img, result);
98 translate_addi(quant, img, result);
108 #define GET_RGB(im, x, y, ri, gi, bi, col) \
109 i_gpix((im),(x),(y),&(col)); (ri)=(col).rgb.r; \
110 if((im)->channels==3) { (bi)=(col).rgb.b; (gi)=(col).rgb.g; }
113 quant_replicate(i_img *im, i_palidx *output, i_quantize *quant);
115 /* Use the gif_lib quantization functions to quantize the image */
116 static void translate_giflib(i_quantize *quant, i_img *img, i_palidx *out) {
117 int x,y,ColorMapSize,colours_in;
121 GifByteType *RedBuffer = NULL, *GreenBuffer = NULL, *BlueBuffer = NULL;
122 GifByteType *RedP, *GreenP, *BlueP;
123 ColorMapObject *OutputColorMap = NULL;
127 mm_log((1,"translate_giflib(quant %p, img %p, out %p)\n", quant, img, out));
129 /*if (!(im->channels==1 || im->channels==3)) { fprintf(stderr,"Unable to write gif, improper colorspace.\n"); exit(3); }*/
131 ColorMapSize = quant->mc_size;
133 Size = ((long) img->xsize) * img->ysize * sizeof(GifByteType);
136 if ((OutputColorMap = MakeMapObject(ColorMapSize, NULL)) == NULL)
137 m_fatal(0,"Failed to allocate memory for Output colormap.");
138 /* if ((OutputBuffer = (GifByteType *) mymalloc(im->xsize * im->ysize * sizeof(GifByteType))) == NULL)
139 m_fatal(0,"Failed to allocate memory for output buffer.");*/
141 /* ******************************************************* */
142 /* count the number of colours in the image */
143 colours_in=i_count_colors(img, OutputColorMap->ColorCount);
145 if(colours_in != -1) { /* less then the number wanted */
146 /* so we copy them over as-is */
147 mm_log((2,"image has %d colours, which fits in %d. Copying\n",
148 colours_in,ColorMapSize));
149 quant_replicate(img, out, quant);
150 /* saves the colors, so don't fall through */
154 mm_log((2,"image has %d colours, more then %d. Quantizing\n",colours_in,ColorMapSize));
156 if (img->channels >= 3) {
157 if ((RedBuffer = (GifByteType *) mymalloc((unsigned int) Size)) == NULL) {
158 m_fatal(0,"Failed to allocate memory required, aborted.");
161 if ((GreenBuffer = (GifByteType *) mymalloc((unsigned int) Size)) == NULL) {
162 m_fatal(0,"Failed to allocate memory required, aborted.");
167 if ((BlueBuffer = (GifByteType *) mymalloc((unsigned int) Size)) == NULL) {
168 m_fatal(0,"Failed to allocate memory required, aborted.");
175 GreenP = GreenBuffer;
178 for (y=0; y< img->ysize; y++) for (x=0; x < img->xsize; x++) {
179 i_gpix(img,x,y,&col);
181 *GreenP++ = col.rgb.g;
182 *BlueP++ = col.rgb.b;
187 if ((RedBuffer = (GifByteType *) mymalloc((unsigned int) Size))==NULL) {
188 m_fatal(0,"Failed to allocate memory required, aborted.");
192 GreenBuffer=BlueBuffer=RedBuffer;
194 for (y=0; y< img->ysize; y++) for (x=0; x < img->xsize; x++) {
195 i_gpix(img,x,y,&col);
200 if (QuantizeBuffer(img->xsize, img->ysize, &ColorMapSize, RedBuffer, GreenBuffer, BlueBuffer,
201 out, OutputColorMap->Colors) == GIF_ERROR) {
202 mm_log((1,"Error in QuantizeBuffer, unable to write image.\n"));
207 if (img->channels == 3) { myfree(GreenBuffer); myfree(BlueBuffer); }
209 /* copy over the color map */
210 for (i = 0; i < ColorMapSize; ++i) {
211 quant->mc_colors[i].rgb.r = OutputColorMap->Colors[i].Red;
212 quant->mc_colors[i].rgb.g = OutputColorMap->Colors[i].Green;
213 quant->mc_colors[i].rgb.b = OutputColorMap->Colors[i].Blue;
215 quant->mc_count = ColorMapSize;
220 quant_replicate(i_img *im, GifByteType *output, i_quantize *quant) {
221 int x, y, alloced, r, g=0, b=0, idx ;
225 for(y=0; y<im->ysize; y++) {
226 for(x=0; x<im->xsize; x++) {
228 GET_RGB(im, x,y, r,g,b, col);
230 for(idx=0; idx<alloced; idx++) { /* linear search for an index */
231 if(quant->mc_colors[idx].rgb.r==r &&
232 quant->mc_colors[idx].rgb.g==g &&
233 quant->mc_colors[idx].rgb.b==b) {
238 if(idx >= alloced) { /* if we haven't already, we */
239 idx=alloced++; /* add the colour to the map */
240 if(quant->mc_size < alloced) {
241 mm_log((1,"Tried to allocate more then %d colours.\n",
245 quant->mc_colors[idx].rgb.r=r;
246 quant->mc_colors[idx].rgb.g=g;
247 quant->mc_colors[idx].rgb.b=b;
249 *output=idx; /* fill output buffer */
250 output++; /* with colour indexes */
253 quant->mc_count = alloced;
259 static void translate_closest(i_quantize *quant, i_img *img, i_palidx *out) {
261 translate_addi(quant, img, out);
264 #define PWR2(x) ((x)*(x))
266 typedef int (*cmpfunc)(const void*, const void*);
289 static void prescan(i_img **im,int count, int cnum, cvec *clr);
290 static void reorder(pbox prescan[512]);
291 static int pboxcmp(const pbox *a,const pbox *b);
292 static void boxcenter(int box,cvec *cv);
293 static float frandn(void);
294 static void boxrand(int box,cvec *cv);
295 static void bbox(int box,int *r0,int *r1,int *g0,int *g1,int *b0,int *b1);
296 static void cr_hashindex(cvec clr[256],int cnum,hashbox hb[512]);
297 static int mindist(int boxnum,cvec *cv);
298 static int maxdist(int boxnum,cvec *cv);
300 /* Some of the simpler functions are kept here to aid the compiler -
301 maybe some of them will be inlined. */
304 pixbox(i_color *ic) { return ((ic->channel[0] & 224)<<1)+ ((ic->channel[1]&224)>>2) + ((ic->channel[2] &224) >> 5); }
308 if (in>255) { return 255; }
309 else if (in>0) return in;
316 return rand()/(RAND_MAX+1.0);
321 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]); }
325 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]); }
329 This quantization algorithm and implementation routines are by Arnar
330 M. Hrafnkelson. In case any new ideas are here they are mine since
331 this was written from scratch.
333 The algorithm uses local means in the following way:
335 For each point in the colormap we find which image points
336 have that point as it's closest point. We calculate the mean
337 of those points and in the next iteration it will be the new
338 entry in the colormap.
340 In order to speed this process up (i.e. nearest neighbor problem) We
341 divied the r,g,b space up in equally large 512 boxes. The boxes are
342 numbered from 0 to 511. Their numbering is so that for a given vector
343 it is known that it belongs to the box who is formed by concatenating the
344 3 most significant bits from each component of the RGB triplet.
346 For each box we find the list of points from the colormap who might be
347 closest to any given point within the box. The exact solution
348 involves finding the Voronoi map (or the dual the Delauny
349 triangulation) and has many issues including numerical stability.
351 So we use this approximation:
353 1. Find which point has the shortest maximum distance to the box.
354 2. Find all points that have a shorter minimum distance than that to the box
356 This is a very simple task and is not computationally heavy if one
357 takes into account that the minimum distances from a pixel to a box is
358 always found by checking if it's inside the box or is closest to some
359 side or a corner. Finding the maximum distance is also either a side
362 This approach results 2-3 times more than the actual points needed but
363 is still a good gain over the complete space. Usually when one has a
364 256 Colorcolor map a search over 30 is often obtained.
366 A bit of an enhancement to this approach is to keep a seperate list
367 for each side of the cube, but this will require even more memory.
369 Arnar M. Hrafnkelsson (addi@umich.edu);
373 Extracted from gifquant.c, removed dependencies on gif_lib,
374 and added support for multiple images.
375 starting from 1nov2000 by TonyC <tony@develop-help.com>.
380 makemap_addi(i_quantize *quant, i_img **imgs, int count) {
382 int cnum, i, x, y, bst_idx=0, ld, cd, iter, currhb, img_num;
387 clr = (cvec *)mymalloc(sizeof(cvec) * quant->mc_size);
388 hb = mymalloc(sizeof(hashbox) * 512);
389 for (i=0; i < quant->mc_count; ++i) {
390 clr[i].r = quant->mc_colors[i].rgb.r;
391 clr[i].g = quant->mc_colors[i].rgb.g;
392 clr[i].b = quant->mc_colors[i].rgb.b;
396 /* mymalloc doesn't clear memory, so I think we need this */
397 for (; i < quant->mc_size; ++i) {
401 cnum = quant->mc_size;
404 prescan(imgs, count, cnum, clr);
405 cr_hashindex(clr, cnum, hb);
407 for(iter=0;iter<3;iter++) {
410 for (img_num = 0; img_num < count; ++img_num) {
411 i_img *im = imgs[img_num];
412 for(y=0;y<im->ysize;y++) for(x=0;x<im->xsize;x++) {
416 /* printf("box = %d \n",currhb); */
417 for(i=0;i<hb[currhb].cnt;i++) {
418 /* 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); */
420 cd=eucl_d(&clr[hb[currhb].vec[i]],&val);
422 ld=cd; /* shortest distance yet */
423 bst_idx=hb[currhb].vec[i]; /* index of closest vector yet */
427 clr[bst_idx].mcount++;
429 clr[bst_idx].dr+=val.channel[0];
430 clr[bst_idx].dg+=val.channel[1];
431 clr[bst_idx].db+=val.channel[2];
434 for(i=0;i<cnum;i++) if (clr[i].mcount) { clr[i].dr/=clr[i].mcount; clr[i].dg/=clr[i].mcount; clr[i].db/=clr[i].mcount; }
436 /* for(i=0;i<cnum;i++) printf("vec(%d)=(%d,%d,%d) dest=(%d,%d,%d) matchcount=%d\n",
437 i,clr[i].r,clr[i].g,clr[i].b,clr[i].dr,clr[i].dg,clr[i].db,clr[i].mcount); */
439 /* printf("total error: %.2f\n",sqrt(accerr)); */
441 for(i=0;i<cnum;i++) {
442 if (clr[i].fixed) continue; /* skip reserved colors */
446 clr[i].r=clr[i].r*(1-dlt)+dlt*clr[i].dr;
447 clr[i].g=clr[i].g*(1-dlt)+dlt*clr[i].dg;
448 clr[i].b=clr[i].b*(1-dlt)+dlt*clr[i].db;
450 /* let's try something else */
462 cr_hashindex(clr,cnum,hb);
467 for(i=0;i<cnum;i++) {
468 cd=eucl_d(&clr[i],&val);
476 /* if defined, we only include colours with an mcount or that were
477 supplied in the fixed palette, giving us a smaller output palette */
478 #define ONLY_USE_USED
480 /* transfer the colors back */
482 for (i = 0; i < cnum; ++i) {
483 if (clr[i].fixed || clr[i].used) {
484 /*printf("Adding %d (%d,%d,%d)\n", i, clr[i].r, clr[i].g, clr[i].b);*/
485 quant->mc_colors[quant->mc_count].rgb.r = clr[i].r;
486 quant->mc_colors[quant->mc_count].rgb.g = clr[i].g;
487 quant->mc_colors[quant->mc_count].rgb.b = clr[i].b;
492 /* transfer the colors back */
493 for (i = 0; i < cnum; ++i) {
494 quant->mc_colors[i].rgb.r = clr[i].r;
495 quant->mc_colors[i].rgb.g = clr[i].g;
496 quant->mc_colors[i].rgb.b = clr[i].b;
498 quant->mc_count = cnum;
501 /* don't want to keep this */
511 #define MEDIAN_CUT_COLORS 32768
513 #define MED_CUT_INDEX(c) ((((c).rgb.r & 0xF8) << 7) | \
514 (((c).rgb.g & 0xF8) << 2) | (((c).rgb.b & 0xF8) >> 3))
516 /* scale these to cover the whole range */
517 #define MED_CUT_RED(index) ((((index) & 0x7C00) >> 10) * 255 / 31)
518 #define MED_CUT_GREEN(index) ((((index) & 0x3E0) >> 5) * 255 / 31)
519 #define MED_CUT_BLUE(index) (((index) & 0x1F) * 255 / 31)
522 i_sample_t min[3]; /* minimum for each channel */
523 i_sample_t max[3]; /* maximum for each channel */
524 i_sample_t width[3]; /* width for each channel */
525 int start, size; /* beginning and size of the partition */
526 int pixels; /* number of pixels represented by this partition */
530 =item calc_part(part, colors)
532 Calculates the new color limits for the given partition.
534 Giflib assumes that the limits for the non-split channels stay the
535 same, but this strikes me as incorrect, especially if the colors tend
538 Of course this could be optimized by not recalculating the channel we
539 just sorted on, but it's not worth the effort right now.
543 static void calc_part(medcut_partition *part, quant_color_entry *colors) {
546 for (ch = 0; ch < 3; ++ch) {
550 for (i = part->start; i < part->start + part->size; ++i) {
551 for (ch = 0; ch < 3; ++ch) {
552 if (part->min[ch] > colors[i].rgb[ch])
553 part->min[ch] = colors[i].rgb[ch];
554 if (part->max[ch] < colors[i].rgb[ch])
555 part->max[ch] = colors[i].rgb[ch];
558 for (ch = 0; ch < 3; ++ch) {
559 part->width[ch] = part->max[ch] - part->min[ch];
563 /* simple functions to sort by each channel - we could use a global, but
567 color_sort_red(void const *left, void const *right) {
568 return ((quant_color_entry *)left)->rgb[0] - ((quant_color_entry *)right)->rgb[0];
572 color_sort_green(void const *left, void const *right) {
573 return ((quant_color_entry *)left)->rgb[1] - ((quant_color_entry *)right)->rgb[1];
577 color_sort_blue(void const *left, void const *right) {
578 return ((quant_color_entry *)left)->rgb[2] - ((quant_color_entry *)right)->rgb[2];
581 static int (*sorters[])(void const *, void const *) =
589 makemap_mediancut(i_quantize *quant, i_img **imgs, int count) {
590 quant_color_entry *colors;
592 int imgn, x, y, i, ch;
597 medcut_partition *parts;
601 /*printf("images %d pal size %d\n", count, quant->mc_size);*/
605 colors = i_mempool_alloc(&mp, sizeof(*colors) * MEDIAN_CUT_COLORS);
606 for (i = 0; i < MEDIAN_CUT_COLORS; ++i) {
607 colors[i].rgb[0] = MED_CUT_RED(i);
608 colors[i].rgb[1] = MED_CUT_GREEN(i);
609 colors[i].rgb[2] = MED_CUT_BLUE(i);
614 for (imgn = 0; imgn < count; ++imgn) {
615 if (imgs[imgn]->xsize > max_width)
616 max_width = imgs[imgn]->xsize;
618 line = i_mempool_alloc(&mp, sizeof(i_color) * max_width);
620 /* build the stats */
622 for (imgn = 0; imgn < count; ++imgn) {
623 total_pixels += imgs[imgn]->xsize * imgs[imgn]->ysize;
624 for (y = 0; y < imgs[imgn]->ysize; ++y) {
625 i_glin(imgs[imgn], 0, imgs[imgn]->xsize, y, line);
626 for (x = 0; x < imgs[imgn]->xsize; ++x) {
627 ++colors[MED_CUT_INDEX(line[x])].count;
632 /* eliminate the empty colors */
634 for (in = 0; in < MEDIAN_CUT_COLORS; ++in) {
635 if (colors[in].count) {
636 colors[out++] = colors[in];
639 /*printf("out %d\n", out);
641 for (i = 0; i < out; ++i) {
642 if (colors[i].count) {
643 printf("%d: (%d,%d,%d) -> %d\n", i, colors[i].rgb[0], colors[i].rgb[1],
644 colors[i].rgb[2], colors[i].count);
648 if (out < quant->mc_size) {
649 /* just copy them into the color table */
650 for (i = 0; i < out; ++i) {
651 for (ch = 0; ch < 3; ++ch) {
652 quant->mc_colors[i].channel[ch] = colors[i].rgb[ch];
655 quant->mc_count = out;
658 /* build the starting partition */
659 parts = i_mempool_alloc(&mp, sizeof(*parts) * quant->mc_size);
662 parts[0].pixels = total_pixels;
663 calc_part(parts, colors);
666 while (color_count < quant->mc_size) {
667 int max_index, max_ch; /* index/channel with biggest spread */
669 medcut_partition *workpart;
673 /* find the partition with the most biggest span with more than
676 for (i = 0; i < color_count; ++i) {
677 for (ch = 0; ch < 3; ++ch) {
678 if (parts[i].width[ch] > max_size
679 && parts[i].size > 1) {
682 max_size = parts[i].width[ch];
687 /* nothing else we can split */
691 workpart = parts+max_index;
692 /*printf("splitting partition %d (pixels %ld, start %d, size %d)\n", max_index, workpart->pixels, workpart->start, workpart->size);*/
693 qsort(colors + workpart->start, workpart->size, sizeof(*colors),
696 /* find the median or something like it we need to make sure both
697 sides of the split have at least one color in them, so we don't
698 test at the first or last entry */
700 cum_total = colors[i].count;
702 half = workpart->pixels / 2;
703 while (i < workpart->start + workpart->size - 1
704 && cum_total < half) {
705 cum_total += colors[i++].count;
707 /*printf("Split at %d to make %d (half %ld, cumtotal %ld)\n", i, color_count, half, cum_total);*/
709 /* found the spot to split */
710 parts[color_count].start = i;
711 parts[color_count].size = workpart->start + workpart->size - i;
712 workpart->size = i - workpart->start;
713 parts[color_count].pixels = workpart->pixels - cum_total;
714 workpart->pixels = cum_total;
716 /* recalculate the limits */
717 calc_part(workpart, colors);
718 calc_part(parts+color_count, colors);
722 /* fill in the color table - since we could still have partitions
723 that have more than one color, we need to average the colors */
724 for (part_num = 0; part_num < color_count; ++part_num) {
726 medcut_partition *workpart;
728 workpart = parts+part_num;
729 for (ch = 0; ch < 3; ++ch)
732 for (i = workpart->start; i < workpart->start + workpart->size; ++i) {
733 for (ch = 0; ch < 3; ++ch) {
734 sums[ch] += colors[i].rgb[ch] * colors[i].count;
737 for (ch = 0; ch < 3; ++ch) {
738 quant->mc_colors[part_num].channel[ch] = sums[ch] / workpart->pixels;
741 quant->mc_count = color_count;
743 /*printf("out %d colors\n", quant->mc_count);*/
744 i_mempool_destroy(&mp);
749 /* Define one of the following 4 symbols to choose a colour search method
750 The idea is to try these out, including benchmarking, to see which
751 is fastest in a good spread of circumstances.
752 I'd expect IM_CFLINSEARCH to be fastest for very small palettes, and
753 IM_CFHASHBOX for large images with large palettes.
755 Some other possibilities include:
756 - search over entries sorted by luminance
758 Initially I was planning on testing using the macros and then
759 integrating the code directly into each function, but this means if
760 we find a bug at a late stage we will need to update N copies of
761 the same code. Also, keeping the code in the macros means that the
762 code in the translation functions is much more to the point,
763 there's no distracting colour search code to remove attention from
764 what makes _this_ translation function different. It may be
765 advisable to move the setup code into functions at some point, but
766 it should be possible to do this fairly transparently.
768 If IM_CF_COPTS is defined then CFLAGS must have an appropriate
771 Each option needs to define 4 macros:
772 CF_VARS - variables to define in the function
773 CF_SETUP - code to setup for the colour search, eg. allocating and
774 initializing lookup tables
775 CF_FIND - code that looks for the color in val and puts the best
776 matching index in bst_idx
777 CF_CLEANUP - code to clean up, eg. releasing memory
780 /*#define IM_CFLINSEARCH*/
782 /*#define IM_CFSORTCHAN*/
783 /*#define IM_CFRAND2DIST*/
788 /* The original version I wrote for this used the sort.
789 If this is defined then we use a sort to extract the indices for
793 /* assume i is available */
794 #define CF_VARS hashbox *hb = mymalloc(sizeof(hashbox) * 512); \
800 static long *gdists; /* qsort is annoying */
801 /* int might be smaller than long, so we need to do a real compare
802 rather than a subtraction*/
803 static int distcomp(void const *a, void const *b) {
804 long ra = gdists[*(int const *)a];
805 long rb = gdists[*(int const *)b];
816 /* for each hashbox build a list of colours that are in the hb or is closer
818 This is pretty involved. The original gifquant generated the hashbox
819 as part of it's normal processing, but since the map generation is now
820 separated from the translation we need to do this on the spot.
821 Any optimizations, even if they don't produce perfect results would be
824 static void hbsetup(i_quantize *quant, hashbox *hb) {
825 long *dists, mind, maxd, cd;
826 int cr, cb, cg, hbnum, i;
829 int *indices = mymalloc(quant->mc_count * sizeof(int));
832 dists = mymalloc(quant->mc_count * sizeof(long));
833 for (cr = 0; cr < 8; ++cr) {
834 for (cg = 0; cg < 8; ++cg) {
835 for (cb = 0; cb < 8; ++cb) {
836 /* centre of the hashbox */
837 cenc.channel[0] = cr*pboxjump+pboxjump/2;
838 cenc.channel[1] = cg*pboxjump+pboxjump/2;
839 cenc.channel[2] = cb*pboxjump+pboxjump/2;
840 hbnum = pixbox(&cenc);
842 /* order indices in the order of distance from the hashbox */
843 for (i = 0; i < quant->mc_count; ++i) {
847 dists[i] = ceucl_d(&cenc, quant->mc_colors+i);
850 /* it should be possible to do this without a sort
851 but so far I'm too lazy */
853 qsort(indices, quant->mc_count, sizeof(int), distcomp);
854 /* any colors that can match are within mind+diagonal size of
856 mind = dists[indices[0]];
858 maxd = (sqrt(mind)+pboxjump)*(sqrt(mind)+pboxjump);
859 while (i < quant->mc_count && dists[indices[i]] < maxd) {
860 hb[hbnum].vec[hb[hbnum].cnt++] = indices[i++];
863 /* work out the minimum */
865 for (i = 0; i < quant->mc_count; ++i) {
866 if (dists[i] < mind) mind = dists[i];
868 /* transfer any colours that might be closest to a colour in
870 maxd = (sqrt(mind)+pboxjump)*(sqrt(mind)+pboxjump);
871 for (i = 0; i < quant->mc_count; ++i) {
873 hb[hbnum].vec[hb[hbnum].cnt++] = i;
884 #define CF_SETUP hbsetup(quant, hb)
887 currhb = pixbox(&val); \
889 for (i = 0; i < hb[currhb].cnt; ++i) { \
890 cd = ceucl_d(quant->mc_colors+hb[currhb].vec[i], &val); \
891 if (cd < ld) { ld = cd; bst_idx = hb[currhb].vec[i]; } \
894 #define CF_CLEANUP myfree(hb)
898 #ifdef IM_CFLINSEARCH
899 /* as simple as it gets */
900 #define CF_VARS long ld, cd
901 #define CF_SETUP /* none needed */
904 for (i = 0; i < quant->mc_count; ++i) { \
905 cd = ceucl_d(quant->mc_colors+i, &val); \
906 if (cd < ld) { ld = cd; bst_idx = i; } \
912 static int gsortchan;
913 static i_quantize *gquant;
914 static int chansort(void const *a, void const *b) {
915 return gquant->mc_colors[*(int const *)a].channel[gsortchan] -
916 gquant->mc_colors[*(int const *)b].channel[gsortchan];
918 #define CF_VARS int *indices, sortchan, diff; \
920 int vindex[256] /* where to find value i of chan */
922 static void chansetup(i_img *img, i_quantize *quant, int *csortchan,
923 int *vindex, int **cindices) {
924 int *indices, sortchan, chan, i, chval;
925 int chanmins[MAXCHANNELS], chanmaxs[MAXCHANNELS], maxrange;
927 /* find the channel with the maximum range */
928 /* the maximum stddev would probably be better */
929 for (chan = 0; chan < img->channels; ++chan) {
930 chanmins[chan] = 256; chanmaxs[chan] = 0;
931 for (i = 0; i < quant->mc_count; ++i) {
932 if (quant->mc_colors[i].channel[chan] < chanmins[chan])
933 chanmins[chan] = quant->mc_colors[i].channel[chan];
934 if (quant->mc_colors[i].channel[chan] > chanmaxs[chan])
935 chanmaxs[chan] = quant->mc_colors[i].channel[chan];
939 for (chan = 0; chan < img->channels; ++chan) {
940 if (chanmaxs[chan]-chanmins[chan] > maxrange) {
941 maxrange = chanmaxs[chan]-chanmins[chan];
945 indices = mymalloc(quant->mc_count * sizeof(int)) ;
946 for (i = 0; i < quant->mc_count; ++i) {
949 gsortchan = sortchan;
951 qsort(indices, quant->mc_count, sizeof(int), chansort) ;
952 /* now a lookup table to find entries faster */
953 for (chval=0, i=0; i < quant->mc_count; ++i) {
954 while (chval < 256 &&
955 chval < quant->mc_colors[indices[i]].channel[sortchan]) {
959 while (chval < 256) {
960 vindex[chval++] = quant->mc_count-1;
962 *csortchan = sortchan;
967 chansetup(img, quant, &sortchan, vindex, &indices)
969 int chanfind(i_color val, i_quantize *quant, int *indices, int *vindex,
971 int i, bst_idx, diff, maxdiff;
974 i = vindex[val.channel[sortchan]];
975 bst_idx = indices[i];
978 maxdiff = quant->mc_count;
979 while (diff < maxdiff) {
980 if (i+diff < quant->mc_count) {
981 cd = ceucl_d(&val, quant->mc_colors+indices[i+diff]);
983 bst_idx = indices[i+diff];
989 cd = ceucl_d(&val, quant->mc_colors+indices[i-diff]);
991 bst_idx = indices[i-diff];
1003 bst_idx = chanfind(val, quant, indices, vindex, sortchan)
1006 #define CF_CLEANUP myfree(indices)
1010 #ifdef IM_CFRAND2DIST
1012 /* This is based on a method described by Addi in the #imager channel
1013 on the 28/2/2001. I was about 1am Sydney time at the time, so I
1014 wasn't at my most cogent. Well, that's my excuse :)
1016 <TonyC> what I have at the moment is: hashboxes, with optimum hash box
1017 filling; simple linear search; and a lookup in the widest channel
1018 (currently the channel with the maximum range)
1019 <Addi> There is one more way that might be simple to implement.
1020 <Addi> You want to hear?
1021 <TonyC> what's that?
1022 <purl> somebody said that was not true
1023 <Addi> For each of the colors in the palette start by creating a
1024 sorted list of the form:
1025 <Addi> [distance, color]
1026 <Addi> Where they are sorted by distance.
1027 <TonyC> distance to where?
1028 <Addi> Where the elements in the lists are the distances and colors of
1029 the other colors in the palette
1031 <Addi> So if you are at color 0
1032 <Addi> ok - now to search for the closest color when you are creating
1033 the final image is done like this:
1034 <Addi> a) pick a random color from the palette
1035 <Addi> b) calculate the distance to it
1036 <Addi> c) only check the vectors that are within double the distance
1037 in the list of the color you picked from the palette.
1038 <Addi> Does that seem logical?
1039 <Addi> Lets imagine that we only have grayscale to make an example:
1040 <Addi> Our palette has 1 4 10 20 as colors.
1041 <Addi> And we want to quantize the color 11
1042 <Addi> lets say we picked 10 randomly
1043 <Addi> the double distance is 2
1044 <Addi> since abs(10-11)*2 is 2
1045 <Addi> And the list at vector 10 is this:
1046 <Addi> [0, 10], [6 4], [9, 1], [10, 20]
1047 <Addi> so we look at the first one (but not the second one since 6 is
1048 at a greater distance than 2.
1049 <Addi> Any of that make sense?
1050 <TonyC> yes, though are you suggesting another random jump to one of
1051 the colours with the possible choices? or an exhaustive search?
1052 <Addi> TonyC: It's possible to come up with a recursive/iterative
1053 enhancement but this is the 'basic' version.
1054 <Addi> Which would do an iterative search.
1055 <Addi> You can come up with conditions where it pays to switch to a new one.
1056 <Addi> And the 'random' start can be switched over to a small tree.
1057 <Addi> So you would have a little index at the start.
1058 <Addi> to get you into the general direction
1059 <Addi> Perhaps just an 8 split.
1060 <Addi> that is - split each dimension in half.
1062 <TonyC> I get the idea
1063 <Addi> But this would seem to be a good approach in our case since we
1064 usually have few codevectors.
1065 <Addi> So we only need 256*256 entries in a table.
1066 <Addi> We could even only index some of them that were deemed as good
1068 <TonyC> I was considering adding paletted output support for PNG and
1069 TIFF at some point, which support 16-bit palettes
1077 typedef struct i_dists {
1085 static int dists_sort(void const *a, void const *b) {
1086 return ((i_dists *)a)->dist - ((i_dists *)b)->dist;
1089 static void rand2dist_setup(i_quantize *quant, i_dists **cdists) {
1091 mymalloc(sizeof(i_dists)*quant->mc_count*quant->mc_count);
1094 for (i = 0; i < quant->mc_count; ++i) {
1095 i_dists *ldists = dists + quant->mc_count * i;
1096 i_color val = quant->mc_colors[i];
1097 for (j = 0; j < quant->mc_count; ++j) {
1098 ldists[j].index = j;
1099 ldists[j].dist = ceucl_d(&val, quant->mc_colors+j);
1101 qsort(ldists, quant->mc_count, sizeof(i_dists), dists_sort);
1107 bst_idx = rand() % quant->mc_count; \
1108 rand2dist_setup(quant, &dists)
1110 static int rand2dist_find(i_color val, i_quantize *quant, i_dists *dists, int index) {
1117 cdists = dists + index * quant->mc_count;
1119 maxld = 8 * ceucl_d(&val, quant->mc_colors+index);
1120 for (i = 0; i < quant->mc_count && cdists[i].dist <= maxld; ++i) {
1121 cd = ceucl_d(&val, quant->mc_colors+cdists[i].index);
1123 bst_idx = cdists[i].index;
1130 #define CF_FIND bst_idx = rand2dist_find(val, quant, dists, bst_idx)
1132 #define CF_CLEANUP myfree(dists)
1137 static void translate_addi(i_quantize *quant, i_img *img, i_palidx *out) {
1138 int x, y, i, k, bst_idx;
1140 int pixdev = quant->perturb;
1147 for(y=0;y<img->ysize;y++) for(x=0;x<img->xsize;x++) {
1148 i_gpix(img,x,y,&val);
1149 val.channel[0]=g_sat(val.channel[0]+(int)(pixdev*frandn()));
1150 val.channel[1]=g_sat(val.channel[1]+(int)(pixdev*frandn()));
1151 val.channel[2]=g_sat(val.channel[2]+(int)(pixdev*frandn()));
1157 for(y=0;y<img->ysize;y++) for(x=0;x<img->xsize;x++) {
1158 i_gpix(img,x,y,&val);
1166 static int floyd_map[] =
1172 static int jarvis_map[] =
1179 static int stucki_map[] =
1186 struct errdiff_map {
1188 int width, height, orig;
1191 static struct errdiff_map maps[] =
1193 { floyd_map, 3, 2, 1 },
1194 { jarvis_map, 5, 3, 2 },
1195 { stucki_map, 5, 3, 2 },
1198 typedef struct errdiff_tag {
1202 /* perform an error diffusion dither */
1205 translate_errdiff(i_quantize *quant, i_img *img, i_palidx *out) {
1207 int mapw, maph, mapo;
1213 int minr, maxr, ming, maxg, minb, maxb, cr, cg, cb;
1218 if ((quant->errdiff & ed_mask) == ed_custom) {
1219 map = quant->ed_map;
1220 mapw = quant->ed_width;
1221 maph = quant->ed_height;
1222 mapo = quant->ed_orig;
1225 int index = quant->errdiff & ed_mask;
1226 if (index >= ed_custom) index = ed_floyd;
1227 map = maps[index].map;
1228 mapw = maps[index].width;
1229 maph = maps[index].height;
1230 mapo = maps[index].orig;
1233 errw = img->xsize+mapw;
1234 err = mymalloc(sizeof(*err) * maph * errw);
1235 /*errp = err+mapo;*/
1236 memset(err, 0, sizeof(*err) * maph * errw);
1239 for (i = 0; i < maph * mapw; ++i)
1240 difftotal += map[i];
1242 for (dy = 0; dy < maph; ++dy) {
1243 for (dx = 0; dx < mapw; ++dx) {
1244 printf("%2d", map[dx+dy*mapw]);
1251 for (y = 0; y < img->ysize; ++y) {
1252 for (x = 0; x < img->xsize; ++x) {
1256 i_gpix(img, x, y, &val);
1258 perr.r = perr.r < 0 ? -((-perr.r)/difftotal) : perr.r/difftotal;
1259 perr.g = perr.g < 0 ? -((-perr.g)/difftotal) : perr.g/difftotal;
1260 perr.b = perr.b < 0 ? -((-perr.b)/difftotal) : perr.b/difftotal;
1261 /*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);*/
1262 val.channel[0] = g_sat(val.channel[0]-perr.r);
1263 val.channel[1] = g_sat(val.channel[1]-perr.g);
1264 val.channel[2] = g_sat(val.channel[2]-perr.b);
1267 perr.r = quant->mc_colors[bst_idx].channel[0] - val.channel[0];
1268 perr.g = quant->mc_colors[bst_idx].channel[1] - val.channel[1];
1269 perr.b = quant->mc_colors[bst_idx].channel[2] - val.channel[2];
1270 /*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);*/
1271 for (dx = 0; dx < mapw; ++dx) {
1272 for (dy = 0; dy < maph; ++dy) {
1273 err[x+dx+dy*errw].r += perr.r * map[dx+mapw*dy];
1274 err[x+dx+dy*errw].g += perr.g * map[dx+mapw*dy];
1275 err[x+dx+dy*errw].b += perr.b * map[dx+mapw*dy];
1280 /* shift up the error matrix */
1281 for (dy = 0; dy < maph-1; ++dy) {
1282 memcpy(err+dy*errw, err+(dy+1)*errw, sizeof(*err)*errw);
1284 memset(err+(maph-1)*errw, 0, sizeof(*err)*errw);
1289 /* Prescan finds the boxes in the image that have the highest number of colors
1290 and that result is used as the initial value for the vectores */
1293 static void prescan(i_img **imgs,int count, int cnum, cvec *clr) {
1298 for(i=0;i<512;i++) {
1304 /* process each image */
1305 for (i = 0; i < count; ++i) {
1306 i_img *im = imgs[i];
1307 for(y=0;y<im->ysize;y++) for(x=0;x<im->xsize;x++) {
1308 i_gpix(im,x,y,&val);
1309 prebox[pixbox(&val)].pixcnt++;
1313 for(i=0;i<512;i++) prebox[i].pdc=prebox[i].pixcnt;
1314 qsort(prebox,512,sizeof(pbox),(cmpfunc)pboxcmp);
1316 for(i=0;i<cnum;i++) {
1317 /* printf("Color %d\n",i);
1318 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); }
1323 /* 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); } */
1329 /* printf("prebox[%d].cand=%d\n",k,prebox[k].cand); */
1330 if (clr[i].fixed) { i++; continue; } /* reserved go to next */
1331 if (j>=prebox[k].cand) { k++; j=1; } else {
1332 if (prebox[k].cand == 2) boxcenter(prebox[k].boxnum,&(clr[i]));
1333 else boxrand(prebox[k].boxnum,&(clr[i]));
1334 /* 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); */
1342 static void reorder(pbox prescan[512]) {
1350 c.pdc=c.pixcnt/(c.cand*c.cand);
1351 /* c.pdc=c.pixcnt/c.cand; */
1352 while(c.pdc < prescan[nidx+1].pdc && nidx < 511) {
1353 prescan[nidx]=prescan[nidx+1];
1360 pboxcmp(const pbox *a,const pbox *b) {
1361 if (a->pixcnt > b->pixcnt) return -1;
1362 if (a->pixcnt < b->pixcnt) return 1;
1367 boxcenter(int box,cvec *cv) {
1368 cv->r=15+((box&448)>>1);
1369 cv->g=15+((box&56)<<2);
1370 cv->b=15+((box&7)<<5);
1374 bbox(int box,int *r0,int *r1,int *g0,int *g1,int *b0,int *b1) {
1384 boxrand(int box,cvec *cv) {
1385 cv->r=6+(rand()%25)+((box&448)>>1);
1386 cv->g=6+(rand()%25)+((box&56)<<2);
1387 cv->b=6+(rand()%25)+((box&7)<<5);
1397 while (w >= 1 || w == 0) {
1398 u1 = 2 * frand() - 1;
1399 u2 = 2 * frand() - 1;
1403 w = sqrt((-2*log(w))/w);
1407 /* Create hash index */
1410 cr_hashindex(cvec clr[256],int cnum,hashbox hb[512]) {
1412 int bx,mind,cd,cumcnt,bst_idx,i;
1413 /* printf("indexing... \n");*/
1416 for(bx=0; bx<512; bx++) {
1418 for(i=0; i<cnum; i++) {
1419 cd = maxdist(bx,&clr[i]);
1420 if (cd < mind) { mind=cd; bst_idx=i; }
1424 for(i=0;i<cnum;i++) if (mindist(bx,&clr[i])<mind) hb[bx].vec[hb[bx].cnt++]=i;
1425 /*printf("box %d -> approx -> %d\n",bx,hb[bx].cnt); */
1426 /* statbox(bx,cnum,clr); */
1430 /* printf("Average search space: %d\n",cumcnt/512); */
1434 maxdist(int boxnum,cvec *cv) {
1435 int r0,r1,g0,g1,b0,b1;
1442 bbox(boxnum,&r0,&r1,&g0,&g1,&b0,&b1);
1444 mr=max(abs(b-b0),abs(b-b1));
1445 mg=max(abs(g-g0),abs(g-g1));
1446 mb=max(abs(r-r0),abs(r-r1));
1448 return PWR2(mr)+PWR2(mg)+PWR2(mb);
1452 mindist(int boxnum,cvec *cv) {
1453 int r0,r1,g0,g1,b0,b1;
1460 bbox(boxnum,&r0,&r1,&g0,&g1,&b0,&b1);
1462 /* printf("box %d, (%d,%d,%d)-(%d,%d,%d) vec (%d,%d,%d) ",boxnum,r0,g0,b0,r1,g1,b1,r,g,b); */
1464 if (r0<=r && r<=r1 && g0<=g && g<=g1 && b0<=b && b<=b1) return 0;
1466 mr=min(abs(b-b0),abs(b-b1));
1467 mg=min(abs(g-g0),abs(g-g1));
1468 mb=min(abs(r-r0),abs(r-r1));
1474 if (r0<=r && r<=r1 && g0<=g && g<=g1) return mb;
1475 if (r0<=r && r<=r1 && b0<=b && b<=b1) return mg;
1476 if (b0<=b && b<=b1 && g0<=g && g<=g1) return mr;
1478 if (r0<=r && r<=r1) return mg+mb;
1479 if (g0<=g && g<=g1) return mr+mb;
1480 if (b0<=b && b<=b1) return mg+mr;
1485 static void transparent_threshold(i_quantize *, i_palidx *, i_img *, i_palidx);
1486 static void transparent_errdiff(i_quantize *, i_palidx *, i_img *, i_palidx);
1487 static void transparent_ordered(i_quantize *, i_palidx *, i_img *, i_palidx);
1489 void quant_transparent(i_quantize *quant, i_palidx *data, i_img *img,
1490 i_palidx trans_index)
1492 switch (quant->transp) {
1497 quant->tr_threshold = 128;
1500 transparent_threshold(quant, data, img, trans_index);
1504 transparent_errdiff(quant, data, img, trans_index);
1508 transparent_ordered(quant, data, img, trans_index);
1514 transparent_threshold(i_quantize *quant, i_palidx *data, i_img *img,
1515 i_palidx trans_index)
1519 for (y = 0; y < img->ysize; ++y) {
1520 for (x = 0; x < img->xsize; ++x) {
1522 i_gpix(img, x, y, &val);
1523 if (val.rgba.a < quant->tr_threshold)
1524 data[y*img->xsize+x] = trans_index;
1530 transparent_errdiff(i_quantize *quant, i_palidx *data, i_img *img,
1531 i_palidx trans_index)
1535 int mapw, maph, mapo;
1536 int errw, *err, *errp;
1537 int difftotal, out, error;
1538 int x, y, dx, dy, i;
1540 /* no custom map for transparency (yet) */
1541 index = quant->tr_errdiff & ed_mask;
1542 if (index >= ed_custom) index = ed_floyd;
1543 map = maps[index].map;
1544 mapw = maps[index].width;
1545 maph = maps[index].height;
1546 mapo = maps[index].orig;
1548 errw = img->xsize+mapw-1;
1549 err = mymalloc(sizeof(*err) * maph * errw);
1551 memset(err, 0, sizeof(*err) * maph * errw);
1554 for (i = 0; i < maph * mapw; ++i)
1555 difftotal += map[i];
1556 for (y = 0; y < img->ysize; ++y) {
1557 for (x = 0; x < img->xsize; ++x) {
1559 i_gpix(img, x, y, &val);
1560 val.rgba.a = g_sat(val.rgba.a-errp[x]/difftotal);
1561 if (val.rgba.a < 128) {
1563 data[y*img->xsize+x] = trans_index;
1568 error = out - val.rgba.a;
1569 for (dx = 0; dx < mapw; ++dx) {
1570 for (dy = 0; dy < maph; ++dy) {
1571 errp[x+dx-mapo+dy*errw] += error * map[dx+mapw*dy];
1575 /* shift up the error matrix */
1576 for (dy = 0; dy < maph-1; ++dy)
1577 memcpy(err+dy*errw, err+(dy+1)*errw, sizeof(*err)*errw);
1578 memset(err+(maph-1)*errw, 0, sizeof(*err)*errw);
1582 /* builtin ordered dither maps */
1583 unsigned char orddith_maps[][64] =
1586 this is purely random - it's pretty awful
1588 48, 72, 196, 252, 180, 92, 108, 52,
1589 228, 176, 64, 8, 236, 40, 20, 164,
1590 120, 128, 84, 116, 24, 28, 172, 220,
1591 68, 0, 188, 124, 184, 224, 192, 104,
1592 132, 100, 240, 200, 152, 160, 244, 44,
1593 96, 204, 144, 16, 140, 56, 232, 216,
1594 208, 4, 76, 212, 136, 248, 80, 168,
1595 156, 88, 32, 112, 148, 12, 36, 60,
1599 perl spot.perl '($x-3.5)*($x-3.5)+($y-3.5)*($y-3.5)'
1601 240, 232, 200, 136, 140, 192, 228, 248,
1602 220, 148, 100, 76, 80, 104, 152, 212,
1603 180, 116, 56, 32, 36, 60, 120, 176,
1604 156, 64, 28, 0, 8, 44, 88, 160,
1605 128, 92, 24, 12, 4, 40, 68, 132,
1606 184, 96, 48, 20, 16, 52, 108, 188,
1607 216, 144, 112, 72, 84, 124, 164, 224,
1608 244, 236, 196, 168, 172, 204, 208, 252,
1612 'min(dist(1.5, 1.5),dist(5.5,1.5),dist(1.5,5.5),dist(5.5,5.5))'
1614 196, 72, 104, 220, 200, 80, 112, 224,
1615 76, 4, 24, 136, 84, 8, 32, 144,
1616 108, 28, 52, 168, 116, 36, 56, 176,
1617 216, 140, 172, 244, 228, 148, 180, 248,
1618 204, 92, 124, 236, 192, 68, 96, 208,
1619 88, 12, 44, 156, 64, 0, 16, 128,
1620 120, 40, 60, 188, 100, 20, 48, 160,
1621 232, 152, 184, 252, 212, 132, 164, 240,
1624 perl spot.perl '$y-3'
1626 160, 164, 168, 172, 176, 180, 184, 188,
1627 128, 132, 136, 140, 144, 148, 152, 156,
1628 32, 36, 40, 44, 48, 52, 56, 60,
1629 0, 4, 8, 12, 16, 20, 24, 28,
1630 64, 68, 72, 76, 80, 84, 88, 92,
1631 96, 100, 104, 108, 112, 116, 120, 124,
1632 192, 196, 200, 204, 208, 212, 216, 220,
1633 224, 228, 232, 236, 240, 244, 248, 252,
1636 perl spot.perl '$x-3'
1638 180, 100, 40, 12, 44, 104, 184, 232,
1639 204, 148, 60, 16, 64, 128, 208, 224,
1640 212, 144, 76, 8, 80, 132, 216, 244,
1641 160, 112, 68, 20, 84, 108, 172, 236,
1642 176, 96, 72, 28, 88, 152, 188, 228,
1643 200, 124, 92, 0, 32, 116, 164, 240,
1644 168, 120, 36, 24, 48, 136, 192, 248,
1645 196, 140, 52, 4, 56, 156, 220, 252,
1648 perl spot.perl '$y+$x-7'
1650 248, 232, 224, 192, 140, 92, 52, 28,
1651 240, 220, 196, 144, 108, 60, 12, 64,
1652 216, 180, 148, 116, 76, 20, 80, 128,
1653 204, 152, 104, 44, 16, 72, 100, 160,
1654 164, 96, 68, 24, 56, 112, 168, 176,
1655 124, 40, 8, 36, 88, 136, 184, 212,
1656 84, 4, 32, 120, 156, 188, 228, 236,
1657 0, 48, 132, 172, 200, 208, 244, 252,
1660 perl spot.perl '$y-$x'
1662 0, 32, 116, 172, 184, 216, 236, 252,
1663 56, 8, 72, 132, 136, 200, 228, 240,
1664 100, 36, 12, 40, 92, 144, 204, 220,
1665 168, 120, 60, 16, 44, 96, 156, 176,
1666 180, 164, 112, 48, 28, 52, 128, 148,
1667 208, 192, 152, 88, 84, 20, 64, 104,
1668 232, 224, 196, 140, 108, 68, 24, 76,
1669 248, 244, 212, 188, 160, 124, 80, 4,
1673 good for display, bad for print
1676 0, 128, 32, 192, 8, 136, 40, 200,
1677 224, 64, 160, 112, 232, 72, 168, 120,
1678 48, 144, 16, 208, 56, 152, 24, 216,
1679 176, 96, 240, 80, 184, 104, 248, 88,
1680 12, 140, 44, 204, 4, 132, 36, 196,
1681 236, 76, 172, 124, 228, 68, 164, 116,
1682 60, 156, 28, 220, 52, 148, 20, 212,
1683 188, 108, 252, 92, 180, 100, 244, 84,
1688 transparent_ordered(i_quantize *quant, i_palidx *data, i_img *img,
1689 i_palidx trans_index)
1691 unsigned char *spot;
1693 if (quant->tr_orddith == od_custom)
1694 spot = quant->tr_custom;
1696 spot = orddith_maps[quant->tr_orddith];
1697 for (y = 0; y < img->ysize; ++y) {
1698 for (x = 0; x < img->xsize; ++x) {
1700 i_gpix(img, x, y, &val);
1701 if (val.rgba.a < spot[(x&7)+(y&7)*8])
1702 data[x+y*img->xsize] = trans_index;