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
8 static void makemap_addi(i_quantize *, i_img **imgs, int count);
9 static void makemap_mediancut(i_quantize *, i_img **imgs, int count);
10 static void makemap_mono(i_quantize *);
14 setcol(i_color *cl,unsigned char r,unsigned char g,unsigned char b,unsigned char a) {
23 /* make a colour map overwrites mc_existing/mc_count in quant Note
24 that i_makemap will be called once for each image if mc_perimage is
25 set and the format support multiple colour maps per image.
27 This means we don't need any special processing at this level to
28 handle multiple colour maps.
32 =item i_quant_makemap(C<quant>, C<imgs>, C<count>)
34 =category Image quantization
36 Analyzes the C<count> images in C<imgs> according to the rules in
37 C<quant> to build a color map (optimal or not depending on
38 C<< quant->make_colors >>).
44 i_quant_makemap(i_quantize *quant, i_img **imgs, int count) {
46 if (quant->translate == pt_giflib) {
47 /* giflib does it's own color table generation */
48 /* previously we used giflib's quantizer, but it didn't handle multiple
49 images, which made it hard to build a global color map
50 We've implemented our own median cut code so we can ignore
52 makemap_mediancut(quant, imgs, count);
56 switch (quant->make_colors & mc_mask) {
58 /* use user's specified map */
64 for (r = 0; r < 256; r+=0x33)
65 for (g = 0; g < 256; g+=0x33)
66 for (b = 0; b < 256; b += 0x33)
67 setcol(quant->mc_colors+i++, r, g, b, 255);
73 makemap_mediancut(quant, imgs, count);
82 makemap_addi(quant, imgs, count);
87 static void translate_closest(i_quantize *, i_img *, i_palidx *);
88 static void translate_errdiff(i_quantize *, i_img *, i_palidx *);
89 static void translate_addi(i_quantize *, i_img *, i_palidx *);
92 =item i_quant_translate(C<quant>, C<img>)
94 =category Image quantization
96 Quantize the image given the palette in C<quant>.
98 On success returns a pointer to a memory block of C<< img->xsize *
99 img->ysize >> C<i_palidx> entries.
101 On failure returns NULL.
103 You should call myfree() on the returned block when you're done with
106 This function will fail if the supplied palette contains no colors.
111 i_quant_translate(i_quantize *quant, i_img *img) {
115 mm_log((1, "quant_translate(quant %p, img %p)\n", quant, img));
117 /* there must be at least one color in the paletted (though even that
119 if (quant->mc_count == 0) {
120 i_push_error(0, "no colors available for translation");
124 bytes = img->xsize * img->ysize;
125 if (bytes / img->ysize != img->xsize) {
126 i_push_error(0, "integer overflow calculating memory allocation");
129 result = mymalloc(bytes);
131 switch (quant->translate) {
134 translate_closest(quant, img, result);
138 translate_errdiff(quant, img, result);
143 translate_addi(quant, img, result);
150 static void translate_closest(i_quantize *quant, i_img *img, i_palidx *out) {
152 translate_addi(quant, img, out);
155 #define PWR2(x) ((x)*(x))
157 typedef int (*cmpfunc)(const void*, const void*);
180 static void prescan(i_img **im,int count, int cnum, cvec *clr, i_sample_t *line);
181 static void reorder(pbox prescan[512]);
182 static int pboxcmp(const pbox *a,const pbox *b);
183 static void boxcenter(int box,cvec *cv);
184 static float frandn(void);
185 static void boxrand(int box,cvec *cv);
186 static void bbox(int box,int *r0,int *r1,int *g0,int *g1,int *b0,int *b1);
187 static void cr_hashindex(cvec clr[256],int cnum,hashbox hb[512]);
188 static int mindist(int boxnum,cvec *cv);
189 static int maxdist(int boxnum,cvec *cv);
191 /* Some of the simpler functions are kept here to aid the compiler -
192 maybe some of them will be inlined. */
195 pixbox(i_color *ic) { return ((ic->channel[0] & 224)<<1)+ ((ic->channel[1]&224)>>2) + ((ic->channel[2] &224) >> 5); }
198 pixbox_ch(i_sample_t *chans) { return ((chans[0] & 224)<<1)+ ((chans[1]&224)>>2) + ((chans[2] &224) >> 5); }
202 if (in>255) { return 255; }
203 else if (in>0) return in;
210 return rand()/(RAND_MAX+1.0);
216 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]); }
221 eucl_d_ch(cvec* cv,i_sample_t *chans) {
222 return PWR2(cv->r - chans[0]) + PWR2(cv->g - chans[1])
223 + PWR2(cv->b - chans[2]);
227 ceucl_d(i_color *c1, i_color *c2) {
228 return PWR2(c1->channel[0]-c2->channel[0])
229 +PWR2(c1->channel[1]-c2->channel[1])
230 +PWR2(c1->channel[2]-c2->channel[2]);
234 gray_samples[] = { 0, 0, 0 };
238 This quantization algorithm and implementation routines are by Arnar
239 M. Hrafnkelson. In case any new ideas are here they are mine since
240 this was written from scratch.
242 The algorithm uses local means in the following way:
244 For each point in the colormap we find which image points
245 have that point as it's closest point. We calculate the mean
246 of those points and in the next iteration it will be the new
247 entry in the colormap.
249 In order to speed this process up (i.e. nearest neighbor problem) We
250 divied the r,g,b space up in equally large 512 boxes. The boxes are
251 numbered from 0 to 511. Their numbering is so that for a given vector
252 it is known that it belongs to the box who is formed by concatenating the
253 3 most significant bits from each component of the RGB triplet.
255 For each box we find the list of points from the colormap who might be
256 closest to any given point within the box. The exact solution
257 involves finding the Voronoi map (or the dual the Delauny
258 triangulation) and has many issues including numerical stability.
260 So we use this approximation:
262 1. Find which point has the shortest maximum distance to the box.
263 2. Find all points that have a shorter minimum distance than that to the box
265 This is a very simple task and is not computationally heavy if one
266 takes into account that the minimum distances from a pixel to a box is
267 always found by checking if it's inside the box or is closest to some
268 side or a corner. Finding the maximum distance is also either a side
271 This approach results 2-3 times more than the actual points needed but
272 is still a good gain over the complete space. Usually when one has a
273 256 Colorcolor map a search over 30 is often obtained.
275 A bit of an enhancement to this approach is to keep a seperate list
276 for each side of the cube, but this will require even more memory.
278 Arnar M. Hrafnkelsson (addi@umich.edu);
282 Extracted from gifquant.c, removed dependencies on gif_lib,
283 and added support for multiple images.
284 starting from 1nov2000 by TonyC <tony@develop-help.com>.
289 makemap_addi(i_quantize *quant, i_img **imgs, int count) {
291 int cnum, i, x, y, bst_idx=0, ld, cd, iter, currhb, img_num;
298 const int *sample_indices;
300 mm_log((1, "makemap_addi(quant %p { mc_count=%d, mc_colors=%p }, imgs %p, count %d)\n",
301 quant, quant->mc_count, quant->mc_colors, imgs, count));
305 clr = i_mempool_alloc(&mp, sizeof(cvec) * quant->mc_size);
306 hb = i_mempool_alloc(&mp, sizeof(hashbox) * 512);
307 for (i=0; i < quant->mc_count; ++i) {
308 clr[i].r = quant->mc_colors[i].rgb.r;
309 clr[i].g = quant->mc_colors[i].rgb.g;
310 clr[i].b = quant->mc_colors[i].rgb.b;
314 /* mymalloc doesn't clear memory, so I think we need this */
315 for (; i < quant->mc_size; ++i) {
316 /*clr[i].r = clr[i].g = clr[i].b = 0;*/
323 cnum = quant->mc_size;
326 for (img_num = 0; img_num < count; ++img_num) {
327 if (imgs[img_num]->xsize > maxwidth)
328 maxwidth = imgs[img_num]->xsize;
330 line = i_mempool_alloc(&mp, 3 * maxwidth * sizeof(*line));
332 prescan(imgs, count, cnum, clr, line);
333 cr_hashindex(clr, cnum, hb);
335 for(iter=0;iter<3;iter++) {
338 for (img_num = 0; img_num < count; ++img_num) {
339 i_img *im = imgs[img_num];
340 sample_indices = im->channels >= 3 ? NULL : gray_samples;
341 for(y=0;y<im->ysize;y++) {
342 i_gsamp(im, 0, im->xsize, y, line, sample_indices, 3);
344 for(x=0;x<im->xsize;x++) {
346 /*i_gpix(im,x,y,&val);*/
347 currhb=pixbox_ch(val);
348 /* printf("box = %d \n",currhb); */
349 for(i=0;i<hb[currhb].cnt;i++) {
350 /* 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); */
352 cd=eucl_d_ch(&clr[hb[currhb].vec[i]],val);
354 ld=cd; /* shortest distance yet */
355 bst_idx=hb[currhb].vec[i]; /* index of closest vector yet */
359 clr[bst_idx].mcount++;
361 clr[bst_idx].dr+=val[0];
362 clr[bst_idx].dg+=val[1];
363 clr[bst_idx].db+=val[2];
365 val += 3; /* next 3 samples (next pixel) */
372 clr[i].dr/=clr[i].mcount;
373 clr[i].dg/=clr[i].mcount;
374 clr[i].db/=clr[i].mcount;
377 /* for(i=0;i<cnum;i++) printf("vec(%d)=(%d,%d,%d) dest=(%d,%d,%d) matchcount=%d\n",
378 i,clr[i].r,clr[i].g,clr[i].b,clr[i].dr,clr[i].dg,clr[i].db,clr[i].mcount); */
380 /* printf("total error: %.2f\n",sqrt(accerr)); */
382 for(i=0;i<cnum;i++) {
383 if (clr[i].fixed) continue; /* skip reserved colors */
387 clr[i].r=clr[i].r*(1-dlt)+dlt*clr[i].dr;
388 clr[i].g=clr[i].g*(1-dlt)+dlt*clr[i].dg;
389 clr[i].b=clr[i].b*(1-dlt)+dlt*clr[i].db;
391 /* let's try something else */
403 cr_hashindex(clr,cnum,hb);
408 for(i=0;i<cnum;i++) {
409 cd=eucl_d(&clr[i],&val);
417 /* if defined, we only include colours with an mcount or that were
418 supplied in the fixed palette, giving us a smaller output palette */
419 #define ONLY_USE_USED
421 /* transfer the colors back */
423 for (i = 0; i < cnum; ++i) {
424 if (clr[i].fixed || clr[i].used) {
425 /*printf("Adding %d (%d,%d,%d)\n", i, clr[i].r, clr[i].g, clr[i].b);*/
426 quant->mc_colors[quant->mc_count].rgb.r = clr[i].r;
427 quant->mc_colors[quant->mc_count].rgb.g = clr[i].g;
428 quant->mc_colors[quant->mc_count].rgb.b = clr[i].b;
433 /* transfer the colors back */
434 for (i = 0; i < cnum; ++i) {
435 quant->mc_colors[i].rgb.r = clr[i].r;
436 quant->mc_colors[i].rgb.g = clr[i].g;
437 quant->mc_colors[i].rgb.b = clr[i].b;
439 quant->mc_count = cnum;
443 mm_log((1, "makemap_addi returns - quant.mc_count = %d\n", quant->mc_count));
444 for (i = 0; i < quant->mc_count; ++i)
445 mm_log((5, " map entry %d: (%d, %d, %d)\n", i, clr[i].r, clr[i].g, clr[i].b));
448 i_mempool_destroy(&mp);
456 #define MEDIAN_CUT_COLORS 32768
458 #define MED_CUT_INDEX(c) ((((c).rgb.r & 0xF8) << 7) | \
459 (((c).rgb.g & 0xF8) << 2) | (((c).rgb.b & 0xF8) >> 3))
461 #define MED_CUT_GRAY_INDEX(c) ((((c).rgb.r & 0xF8) << 7) | \
462 (((c).rgb.r & 0xF8) << 2) | (((c).rgb.r & 0xF8) >> 3))
464 /* scale these to cover the whole range */
465 #define MED_CUT_RED(index) ((((index) & 0x7C00) >> 10) * 255 / 31)
466 #define MED_CUT_GREEN(index) ((((index) & 0x3E0) >> 5) * 255 / 31)
467 #define MED_CUT_BLUE(index) (((index) & 0x1F) * 255 / 31)
470 i_sample_t min[3]; /* minimum for each channel */
471 i_sample_t max[3]; /* maximum for each channel */
472 i_sample_t width[3]; /* width for each channel */
473 int start, size; /* beginning and size of the partition */
474 int pixels; /* number of pixels represented by this partition */
478 =item calc_part(part, colors)
480 Calculates the new color limits for the given partition.
482 Giflib assumes that the limits for the non-split channels stay the
483 same, but this strikes me as incorrect, especially if the colors tend
486 Of course this could be optimized by not recalculating the channel we
487 just sorted on, but it's not worth the effort right now.
491 static void calc_part(medcut_partition *part, quant_color_entry *colors) {
494 for (ch = 0; ch < 3; ++ch) {
498 for (i = part->start; i < part->start + part->size; ++i) {
499 for (ch = 0; ch < 3; ++ch) {
500 if (part->min[ch] > colors[i].rgb[ch])
501 part->min[ch] = colors[i].rgb[ch];
502 if (part->max[ch] < colors[i].rgb[ch])
503 part->max[ch] = colors[i].rgb[ch];
506 for (ch = 0; ch < 3; ++ch) {
507 part->width[ch] = part->max[ch] - part->min[ch];
511 /* simple functions to sort by each channel - we could use a global, but
515 color_sort_red(void const *left, void const *right) {
516 return ((quant_color_entry *)left)->rgb[0] - ((quant_color_entry *)right)->rgb[0];
520 color_sort_green(void const *left, void const *right) {
521 return ((quant_color_entry *)left)->rgb[1] - ((quant_color_entry *)right)->rgb[1];
525 color_sort_blue(void const *left, void const *right) {
526 return ((quant_color_entry *)left)->rgb[2] - ((quant_color_entry *)right)->rgb[2];
529 static int (*sorters[])(void const *, void const *) =
537 makemap_mediancut(i_quantize *quant, i_img **imgs, int count) {
538 quant_color_entry *colors;
540 int imgn, x, y, i, ch;
545 medcut_partition *parts;
548 /* number of channels we search for the best channel to partition
549 this isn't terribly efficient, but it should work */
552 /*printf("images %d pal size %d\n", count, quant->mc_size);*/
556 colors = i_mempool_alloc(&mp, sizeof(*colors) * MEDIAN_CUT_COLORS);
557 for (i = 0; i < MEDIAN_CUT_COLORS; ++i) {
558 colors[i].rgb[0] = MED_CUT_RED(i);
559 colors[i].rgb[1] = MED_CUT_GREEN(i);
560 colors[i].rgb[2] = MED_CUT_BLUE(i);
565 for (imgn = 0; imgn < count; ++imgn) {
566 if (imgs[imgn]->xsize > max_width)
567 max_width = imgs[imgn]->xsize;
569 line = i_mempool_alloc(&mp, sizeof(i_color) * max_width);
571 /* build the stats */
573 chan_count = 1; /* assume we just have grayscale */
574 for (imgn = 0; imgn < count; ++imgn) {
575 total_pixels += imgs[imgn]->xsize * imgs[imgn]->ysize;
576 for (y = 0; y < imgs[imgn]->ysize; ++y) {
577 i_glin(imgs[imgn], 0, imgs[imgn]->xsize, y, line);
578 if (imgs[imgn]->channels > 2) {
580 for (x = 0; x < imgs[imgn]->xsize; ++x) {
581 ++colors[MED_CUT_INDEX(line[x])].count;
585 /* a gray-scale image, just use the first channel */
586 for (x = 0; x < imgs[imgn]->xsize; ++x) {
587 ++colors[MED_CUT_GRAY_INDEX(line[x])].count;
593 /* eliminate the empty colors */
595 for (in = 0; in < MEDIAN_CUT_COLORS; ++in) {
596 if (colors[in].count) {
597 colors[out++] = colors[in];
600 /*printf("out %d\n", out);
602 for (i = 0; i < out; ++i) {
603 if (colors[i].count) {
604 printf("%d: (%d,%d,%d) -> %d\n", i, colors[i].rgb[0], colors[i].rgb[1],
605 colors[i].rgb[2], colors[i].count);
609 if (out < quant->mc_size) {
610 /* just copy them into the color table */
611 for (i = 0; i < out; ++i) {
612 for (ch = 0; ch < 3; ++ch) {
613 quant->mc_colors[i].channel[ch] = colors[i].rgb[ch];
616 quant->mc_count = out;
619 /* build the starting partition */
620 parts = i_mempool_alloc(&mp, sizeof(*parts) * quant->mc_size);
623 parts[0].pixels = total_pixels;
624 calc_part(parts, colors);
627 while (color_count < quant->mc_size) {
628 /* initialized to avoid compiler warnings */
629 int max_index = 0, max_ch = 0; /* index/channel with biggest spread */
631 medcut_partition *workpart;
635 /* find the partition with the most biggest span with more than
638 for (i = 0; i < color_count; ++i) {
639 for (ch = 0; ch < chan_count; ++ch) {
640 if (parts[i].width[ch] > max_size
641 && parts[i].size > 1) {
644 max_size = parts[i].width[ch];
649 /* nothing else we can split */
653 workpart = parts+max_index;
654 /*printf("splitting partition %d (pixels %ld, start %d, size %d)\n", max_index, workpart->pixels, workpart->start, workpart->size);*/
655 qsort(colors + workpart->start, workpart->size, sizeof(*colors),
658 /* find the median or something like it we need to make sure both
659 sides of the split have at least one color in them, so we don't
660 test at the first or last entry */
662 cum_total = colors[i].count;
664 half = workpart->pixels / 2;
665 while (i < workpart->start + workpart->size - 1
666 && cum_total < half) {
667 cum_total += colors[i++].count;
669 /*printf("Split at %d to make %d (half %ld, cumtotal %ld)\n", i, color_count, half, cum_total);*/
671 /* found the spot to split */
672 parts[color_count].start = i;
673 parts[color_count].size = workpart->start + workpart->size - i;
674 workpart->size = i - workpart->start;
675 parts[color_count].pixels = workpart->pixels - cum_total;
676 workpart->pixels = cum_total;
678 /* recalculate the limits */
679 calc_part(workpart, colors);
680 calc_part(parts+color_count, colors);
684 /* fill in the color table - since we could still have partitions
685 that have more than one color, we need to average the colors */
686 for (part_num = 0; part_num < color_count; ++part_num) {
688 medcut_partition *workpart;
690 workpart = parts+part_num;
691 for (ch = 0; ch < 3; ++ch)
694 for (i = workpart->start; i < workpart->start + workpart->size; ++i) {
695 for (ch = 0; ch < 3; ++ch) {
696 sums[ch] += colors[i].rgb[ch] * colors[i].count;
699 for (ch = 0; ch < 3; ++ch) {
700 quant->mc_colors[part_num].channel[ch] = sums[ch] / workpart->pixels;
703 quant->mc_count = color_count;
705 /*printf("out %d colors\n", quant->mc_count);*/
706 i_mempool_destroy(&mp);
710 makemap_mono(i_quantize *quant) {
711 quant->mc_colors[0].rgba.r = 0;
712 quant->mc_colors[0].rgba.g = 0;
713 quant->mc_colors[0].rgba.b = 0;
714 quant->mc_colors[0].rgba.a = 255;
715 quant->mc_colors[1].rgba.r = 255;
716 quant->mc_colors[1].rgba.g = 255;
717 quant->mc_colors[1].rgba.b = 255;
718 quant->mc_colors[1].rgba.a = 255;
724 /* Define one of the following 4 symbols to choose a colour search method
725 The idea is to try these out, including benchmarking, to see which
726 is fastest in a good spread of circumstances.
727 I'd expect IM_CFLINSEARCH to be fastest for very small palettes, and
728 IM_CFHASHBOX for large images with large palettes.
730 Some other possibilities include:
731 - search over entries sorted by luminance
733 Initially I was planning on testing using the macros and then
734 integrating the code directly into each function, but this means if
735 we find a bug at a late stage we will need to update N copies of
736 the same code. Also, keeping the code in the macros means that the
737 code in the translation functions is much more to the point,
738 there's no distracting colour search code to remove attention from
739 what makes _this_ translation function different. It may be
740 advisable to move the setup code into functions at some point, but
741 it should be possible to do this fairly transparently.
743 If IM_CF_COPTS is defined then CFLAGS must have an appropriate
746 Each option needs to define 4 macros:
747 CF_VARS - variables to define in the function
748 CF_SETUP - code to setup for the colour search, eg. allocating and
749 initializing lookup tables
750 CF_FIND - code that looks for the color in val and puts the best
751 matching index in bst_idx
752 CF_CLEANUP - code to clean up, eg. releasing memory
755 /*#define IM_CFLINSEARCH*/
757 /*#define IM_CFSORTCHAN*/
758 /*#define IM_CFRAND2DIST*/
761 /* return true if the color map contains only grays */
763 is_gray_map(const i_quantize *quant) {
766 for (i = 0; i < quant->mc_count; ++i) {
767 if (quant->mc_colors[i].rgb.r != quant->mc_colors[i].rgb.g
768 || quant->mc_colors[i].rgb.r != quant->mc_colors[i].rgb.b) {
769 mm_log((1, " not a gray map\n"));
774 mm_log((1, " is a gray map\n"));
780 /* The original version I wrote for this used the sort.
781 If this is defined then we use a sort to extract the indices for
785 /* assume i is available */
786 #define CF_VARS hashbox *hb = mymalloc(sizeof(hashbox) * 512); \
792 static long *gdists; /* qsort is annoying */
793 /* int might be smaller than long, so we need to do a real compare
794 rather than a subtraction*/
795 static int distcomp(void const *a, void const *b) {
796 long ra = gdists[*(int const *)a];
797 long rb = gdists[*(int const *)b];
808 /* for each hashbox build a list of colours that are in the hb or is closer
810 This is pretty involved. The original gifquant generated the hashbox
811 as part of it's normal processing, but since the map generation is now
812 separated from the translation we need to do this on the spot.
813 Any optimizations, even if they don't produce perfect results would be
816 static void hbsetup(i_quantize *quant, hashbox *hb) {
817 long *dists, mind, maxd;
818 int cr, cb, cg, hbnum, i;
821 int *indices = mymalloc(quant->mc_count * sizeof(int));
824 dists = mymalloc(quant->mc_count * sizeof(long));
825 for (cr = 0; cr < 8; ++cr) {
826 for (cg = 0; cg < 8; ++cg) {
827 for (cb = 0; cb < 8; ++cb) {
828 /* centre of the hashbox */
829 cenc.channel[0] = cr*pboxjump+pboxjump/2;
830 cenc.channel[1] = cg*pboxjump+pboxjump/2;
831 cenc.channel[2] = cb*pboxjump+pboxjump/2;
832 hbnum = pixbox(&cenc);
834 /* order indices in the order of distance from the hashbox */
835 for (i = 0; i < quant->mc_count; ++i) {
839 dists[i] = ceucl_d(&cenc, quant->mc_colors+i);
842 /* it should be possible to do this without a sort
843 but so far I'm too lazy */
845 qsort(indices, quant->mc_count, sizeof(int), distcomp);
846 /* any colors that can match are within mind+diagonal size of
848 mind = dists[indices[0]];
850 maxd = (sqrt(mind)+pboxjump)*(sqrt(mind)+pboxjump);
851 while (i < quant->mc_count && dists[indices[i]] < maxd) {
852 hb[hbnum].vec[hb[hbnum].cnt++] = indices[i++];
855 /* work out the minimum */
857 for (i = 0; i < quant->mc_count; ++i) {
858 if (dists[i] < mind) mind = dists[i];
860 /* transfer any colours that might be closest to a colour in
862 maxd = (sqrt(mind)+pboxjump)*(sqrt(mind)+pboxjump);
863 for (i = 0; i < quant->mc_count; ++i) {
865 hb[hbnum].vec[hb[hbnum].cnt++] = i;
876 #define CF_SETUP hbsetup(quant, hb)
879 currhb = pixbox(&val); \
881 for (i = 0; i < hb[currhb].cnt; ++i) { \
882 cd = ceucl_d(quant->mc_colors+hb[currhb].vec[i], &val); \
883 if (cd < ld) { ld = cd; bst_idx = hb[currhb].vec[i]; } \
886 #define CF_CLEANUP myfree(hb)
890 #ifdef IM_CFLINSEARCH
891 /* as simple as it gets */
892 #define CF_VARS long ld, cd
893 #define CF_SETUP /* none needed */
896 for (i = 0; i < quant->mc_count; ++i) { \
897 cd = ceucl_d(quant->mc_colors+i, &val); \
898 if (cd < ld) { ld = cd; bst_idx = i; } \
904 static int gsortchan;
905 static i_quantize *gquant;
906 static int chansort(void const *a, void const *b) {
907 return gquant->mc_colors[*(int const *)a].channel[gsortchan] -
908 gquant->mc_colors[*(int const *)b].channel[gsortchan];
910 #define CF_VARS int *indices, sortchan, diff; \
912 int vindex[256] /* where to find value i of chan */
914 static void chansetup(i_img *img, i_quantize *quant, int *csortchan,
915 int *vindex, int **cindices) {
916 int *indices, sortchan, chan, i, chval;
917 int chanmins[MAXCHANNELS], chanmaxs[MAXCHANNELS], maxrange;
919 /* find the channel with the maximum range */
920 /* the maximum stddev would probably be better */
921 for (chan = 0; chan < img->channels; ++chan) {
922 chanmins[chan] = 256; chanmaxs[chan] = 0;
923 for (i = 0; i < quant->mc_count; ++i) {
924 if (quant->mc_colors[i].channel[chan] < chanmins[chan])
925 chanmins[chan] = quant->mc_colors[i].channel[chan];
926 if (quant->mc_colors[i].channel[chan] > chanmaxs[chan])
927 chanmaxs[chan] = quant->mc_colors[i].channel[chan];
931 for (chan = 0; chan < img->channels; ++chan) {
932 if (chanmaxs[chan]-chanmins[chan] > maxrange) {
933 maxrange = chanmaxs[chan]-chanmins[chan];
937 indices = mymalloc(quant->mc_count * sizeof(int)) ;
938 for (i = 0; i < quant->mc_count; ++i) {
941 gsortchan = sortchan;
943 qsort(indices, quant->mc_count, sizeof(int), chansort) ;
944 /* now a lookup table to find entries faster */
945 for (chval=0, i=0; i < quant->mc_count; ++i) {
946 while (chval < 256 &&
947 chval < quant->mc_colors[indices[i]].channel[sortchan]) {
951 while (chval < 256) {
952 vindex[chval++] = quant->mc_count-1;
954 *csortchan = sortchan;
959 chansetup(img, quant, &sortchan, vindex, &indices)
961 int chanfind(i_color val, i_quantize *quant, int *indices, int *vindex,
963 int i, bst_idx, diff, maxdiff;
966 i = vindex[val.channel[sortchan]];
967 bst_idx = indices[i];
970 maxdiff = quant->mc_count;
971 while (diff < maxdiff) {
972 if (i+diff < quant->mc_count) {
973 cd = ceucl_d(&val, quant->mc_colors+indices[i+diff]);
975 bst_idx = indices[i+diff];
981 cd = ceucl_d(&val, quant->mc_colors+indices[i-diff]);
983 bst_idx = indices[i-diff];
995 bst_idx = chanfind(val, quant, indices, vindex, sortchan)
998 #define CF_CLEANUP myfree(indices)
1002 #ifdef IM_CFRAND2DIST
1004 /* This is based on a method described by Addi in the #imager channel
1005 on the 28/2/2001. I was about 1am Sydney time at the time, so I
1006 wasn't at my most cogent. Well, that's my excuse :)
1008 <TonyC> what I have at the moment is: hashboxes, with optimum hash box
1009 filling; simple linear search; and a lookup in the widest channel
1010 (currently the channel with the maximum range)
1011 <Addi> There is one more way that might be simple to implement.
1012 <Addi> You want to hear?
1013 <TonyC> what's that?
1014 <purl> somebody said that was not true
1015 <Addi> For each of the colors in the palette start by creating a
1016 sorted list of the form:
1017 <Addi> [distance, color]
1018 <Addi> Where they are sorted by distance.
1019 <TonyC> distance to where?
1020 <Addi> Where the elements in the lists are the distances and colors of
1021 the other colors in the palette
1023 <Addi> So if you are at color 0
1024 <Addi> ok - now to search for the closest color when you are creating
1025 the final image is done like this:
1026 <Addi> a) pick a random color from the palette
1027 <Addi> b) calculate the distance to it
1028 <Addi> c) only check the vectors that are within double the distance
1029 in the list of the color you picked from the palette.
1030 <Addi> Does that seem logical?
1031 <Addi> Lets imagine that we only have grayscale to make an example:
1032 <Addi> Our palette has 1 4 10 20 as colors.
1033 <Addi> And we want to quantize the color 11
1034 <Addi> lets say we picked 10 randomly
1035 <Addi> the double distance is 2
1036 <Addi> since abs(10-11)*2 is 2
1037 <Addi> And the list at vector 10 is this:
1038 <Addi> [0, 10], [6 4], [9, 1], [10, 20]
1039 <Addi> so we look at the first one (but not the second one since 6 is
1040 at a greater distance than 2.
1041 <Addi> Any of that make sense?
1042 <TonyC> yes, though are you suggesting another random jump to one of
1043 the colours with the possible choices? or an exhaustive search?
1044 <Addi> TonyC: It's possible to come up with a recursive/iterative
1045 enhancement but this is the 'basic' version.
1046 <Addi> Which would do an iterative search.
1047 <Addi> You can come up with conditions where it pays to switch to a new one.
1048 <Addi> And the 'random' start can be switched over to a small tree.
1049 <Addi> So you would have a little index at the start.
1050 <Addi> to get you into the general direction
1051 <Addi> Perhaps just an 8 split.
1052 <Addi> that is - split each dimension in half.
1054 <TonyC> I get the idea
1055 <Addi> But this would seem to be a good approach in our case since we
1056 usually have few codevectors.
1057 <Addi> So we only need 256*256 entries in a table.
1058 <Addi> We could even only index some of them that were deemed as good
1060 <TonyC> I was considering adding paletted output support for PNG and
1061 TIFF at some point, which support 16-bit palettes
1069 typedef struct i_dists {
1077 static int dists_sort(void const *a, void const *b) {
1078 return ((i_dists *)a)->dist - ((i_dists *)b)->dist;
1081 static void rand2dist_setup(i_quantize *quant, i_dists **cdists) {
1083 mymalloc(sizeof(i_dists)*quant->mc_count*quant->mc_count);
1086 for (i = 0; i < quant->mc_count; ++i) {
1087 i_dists *ldists = dists + quant->mc_count * i;
1088 i_color val = quant->mc_colors[i];
1089 for (j = 0; j < quant->mc_count; ++j) {
1090 ldists[j].index = j;
1091 ldists[j].dist = ceucl_d(&val, quant->mc_colors+j);
1093 qsort(ldists, quant->mc_count, sizeof(i_dists), dists_sort);
1099 bst_idx = rand() % quant->mc_count; \
1100 rand2dist_setup(quant, &dists)
1102 static int rand2dist_find(i_color val, i_quantize *quant, i_dists *dists, int index) {
1109 cdists = dists + index * quant->mc_count;
1111 maxld = 8 * ceucl_d(&val, quant->mc_colors+index);
1112 for (i = 0; i < quant->mc_count && cdists[i].dist <= maxld; ++i) {
1113 cd = ceucl_d(&val, quant->mc_colors+cdists[i].index);
1115 bst_idx = cdists[i].index;
1122 #define CF_FIND bst_idx = rand2dist_find(val, quant, dists, bst_idx)
1124 #define CF_CLEANUP myfree(dists)
1129 static void translate_addi(i_quantize *quant, i_img *img, i_palidx *out) {
1130 int x, y, i, k, bst_idx = 0;
1132 int pixdev = quant->perturb;
1137 if (img->channels >= 3) {
1140 for(y=0;y<img->ysize;y++) for(x=0;x<img->xsize;x++) {
1141 i_gpix(img,x,y,&val);
1142 val.channel[0]=g_sat(val.channel[0]+(int)(pixdev*frandn()));
1143 val.channel[1]=g_sat(val.channel[1]+(int)(pixdev*frandn()));
1144 val.channel[2]=g_sat(val.channel[2]+(int)(pixdev*frandn()));
1150 for(y=0;y<img->ysize;y++) for(x=0;x<img->xsize;x++) {
1151 i_gpix(img,x,y,&val);
1160 for(y=0;y<img->ysize;y++) for(x=0;x<img->xsize;x++) {
1161 i_gpix(img,x,y,&val);
1162 val.channel[1] = val.channel[2] =
1163 val.channel[0]=g_sat(val.channel[0]+(int)(pixdev*frandn()));
1169 for(y=0;y<img->ysize;y++) for(x=0;x<img->xsize;x++) {
1170 i_gpix(img,x,y,&val);
1171 val.channel[1] = val.channel[2] = val.channel[0];
1180 static int floyd_map[] =
1186 static int jarvis_map[] =
1193 static int stucki_map[] =
1200 struct errdiff_map {
1202 int width, height, orig;
1205 static struct errdiff_map maps[] =
1207 { floyd_map, 3, 2, 1 },
1208 { jarvis_map, 5, 3, 2 },
1209 { stucki_map, 5, 3, 2 },
1212 typedef struct errdiff_tag {
1216 /* perform an error diffusion dither */
1219 translate_errdiff(i_quantize *quant, i_img *img, i_palidx *out) {
1221 int mapw, maph, mapo;
1228 int is_gray = is_gray_map(quant);
1231 if ((quant->errdiff & ed_mask) == ed_custom) {
1232 map = quant->ed_map;
1233 mapw = quant->ed_width;
1234 maph = quant->ed_height;
1235 mapo = quant->ed_orig;
1238 int index = quant->errdiff & ed_mask;
1239 if (index >= ed_custom) index = ed_floyd;
1240 map = maps[index].map;
1241 mapw = maps[index].width;
1242 maph = maps[index].height;
1243 mapo = maps[index].orig;
1246 errw = img->xsize+mapw;
1247 err = mymalloc(sizeof(*err) * maph * errw);
1248 /*errp = err+mapo;*/
1249 memset(err, 0, sizeof(*err) * maph * errw);
1252 for (i = 0; i < maph * mapw; ++i)
1253 difftotal += map[i];
1255 for (dy = 0; dy < maph; ++dy) {
1256 for (dx = 0; dx < mapw; ++dx) {
1257 printf("%2d", map[dx+dy*mapw]);
1264 for (y = 0; y < img->ysize; ++y) {
1265 for (x = 0; x < img->xsize; ++x) {
1269 i_gpix(img, x, y, &val);
1270 if (img->channels < 3) {
1271 val.channel[1] = val.channel[2] = val.channel[0];
1274 int gray = 0.5 + color_to_grey(&val);
1275 val.channel[0] = val.channel[1] = val.channel[2] = gray;
1278 perr.r = perr.r < 0 ? -((-perr.r)/difftotal) : perr.r/difftotal;
1279 perr.g = perr.g < 0 ? -((-perr.g)/difftotal) : perr.g/difftotal;
1280 perr.b = perr.b < 0 ? -((-perr.b)/difftotal) : perr.b/difftotal;
1281 /*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);*/
1282 val.channel[0] = g_sat(val.channel[0]-perr.r);
1283 val.channel[1] = g_sat(val.channel[1]-perr.g);
1284 val.channel[2] = g_sat(val.channel[2]-perr.b);
1287 perr.r = quant->mc_colors[bst_idx].channel[0] - val.channel[0];
1288 perr.g = quant->mc_colors[bst_idx].channel[1] - val.channel[1];
1289 perr.b = quant->mc_colors[bst_idx].channel[2] - val.channel[2];
1290 /*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);*/
1291 for (dx = 0; dx < mapw; ++dx) {
1292 for (dy = 0; dy < maph; ++dy) {
1293 err[x+dx+dy*errw].r += perr.r * map[dx+mapw*dy];
1294 err[x+dx+dy*errw].g += perr.g * map[dx+mapw*dy];
1295 err[x+dx+dy*errw].b += perr.b * map[dx+mapw*dy];
1300 /* shift up the error matrix */
1301 for (dy = 0; dy < maph-1; ++dy) {
1302 memcpy(err+dy*errw, err+(dy+1)*errw, sizeof(*err)*errw);
1304 memset(err+(maph-1)*errw, 0, sizeof(*err)*errw);
1309 /* Prescan finds the boxes in the image that have the highest number of colors
1310 and that result is used as the initial value for the vectores */
1313 static void prescan(i_img **imgs,int count, int cnum, cvec *clr, i_sample_t *line) {
1319 for(i=0;i<512;i++) {
1325 /* process each image */
1326 for (i = 0; i < count; ++i) {
1327 i_img *im = imgs[i];
1328 chans = im->channels >= 3 ? NULL : gray_samples;
1329 for(y=0;y<im->ysize;y++) {
1330 i_gsamp(im, 0, im->xsize, y, line, chans, 3);
1332 for(x=0;x<im->xsize;x++) {
1333 prebox[pixbox_ch(val)].pixcnt++;
1338 for(i=0;i<512;i++) prebox[i].pdc=prebox[i].pixcnt;
1339 qsort(prebox,512,sizeof(pbox),(cmpfunc)pboxcmp);
1341 for(i=0;i<cnum;i++) {
1342 /* printf("Color %d\n",i);
1343 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); }
1348 /* 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); } */
1354 /* printf("prebox[%d].cand=%d\n",k,prebox[k].cand); */
1355 if (clr[i].fixed) { i++; continue; } /* reserved go to next */
1356 if (j>=prebox[k].cand) { k++; j=1; } else {
1357 if (prebox[k].cand == 2) boxcenter(prebox[k].boxnum,&(clr[i]));
1358 else boxrand(prebox[k].boxnum,&(clr[i]));
1359 /* 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); */
1367 static void reorder(pbox prescan[512]) {
1375 c.pdc=c.pixcnt/(c.cand*c.cand);
1376 /* c.pdc=c.pixcnt/c.cand; */
1377 while(c.pdc < prescan[nidx+1].pdc && nidx < 511) {
1378 prescan[nidx]=prescan[nidx+1];
1385 pboxcmp(const pbox *a,const pbox *b) {
1386 if (a->pixcnt > b->pixcnt) return -1;
1387 if (a->pixcnt < b->pixcnt) return 1;
1392 boxcenter(int box,cvec *cv) {
1393 cv->r=15+((box&448)>>1);
1394 cv->g=15+((box&56)<<2);
1395 cv->b=15+((box&7)<<5);
1399 bbox(int box,int *r0,int *r1,int *g0,int *g1,int *b0,int *b1) {
1409 boxrand(int box,cvec *cv) {
1410 cv->r=6+(rand()%25)+((box&448)>>1);
1411 cv->g=6+(rand()%25)+((box&56)<<2);
1412 cv->b=6+(rand()%25)+((box&7)<<5);
1422 while (w >= 1 || w == 0) {
1423 u1 = 2 * frand() - 1;
1424 u2 = 2 * frand() - 1;
1428 w = sqrt((-2*log(w))/w);
1432 /* Create hash index */
1435 cr_hashindex(cvec clr[256],int cnum,hashbox hb[512]) {
1437 int bx,mind,cd,cumcnt,bst_idx,i;
1438 /* printf("indexing... \n");*/
1441 for(bx=0; bx<512; bx++) {
1443 for(i=0; i<cnum; i++) {
1444 cd = maxdist(bx,&clr[i]);
1445 if (cd < mind) { mind=cd; bst_idx=i; }
1449 for(i=0;i<cnum;i++) if (mindist(bx,&clr[i])<mind) hb[bx].vec[hb[bx].cnt++]=i;
1450 /*printf("box %d -> approx -> %d\n",bx,hb[bx].cnt); */
1451 /* statbox(bx,cnum,clr); */
1455 /* printf("Average search space: %d\n",cumcnt/512); */
1459 maxdist(int boxnum,cvec *cv) {
1460 int r0,r1,g0,g1,b0,b1;
1467 bbox(boxnum,&r0,&r1,&g0,&g1,&b0,&b1);
1469 mr=i_max(abs(b-b0),abs(b-b1));
1470 mg=i_max(abs(g-g0),abs(g-g1));
1471 mb=i_max(abs(r-r0),abs(r-r1));
1473 return PWR2(mr)+PWR2(mg)+PWR2(mb);
1477 mindist(int boxnum,cvec *cv) {
1478 int r0,r1,g0,g1,b0,b1;
1485 bbox(boxnum,&r0,&r1,&g0,&g1,&b0,&b1);
1487 /* printf("box %d, (%d,%d,%d)-(%d,%d,%d) vec (%d,%d,%d) ",boxnum,r0,g0,b0,r1,g1,b1,r,g,b); */
1489 if (r0<=r && r<=r1 && g0<=g && g<=g1 && b0<=b && b<=b1) return 0;
1491 mr=i_min(abs(b-b0),abs(b-b1));
1492 mg=i_min(abs(g-g0),abs(g-g1));
1493 mb=i_min(abs(r-r0),abs(r-r1));
1499 if (r0<=r && r<=r1 && g0<=g && g<=g1) return mb;
1500 if (r0<=r && r<=r1 && b0<=b && b<=b1) return mg;
1501 if (b0<=b && b<=b1 && g0<=g && g<=g1) return mr;
1503 if (r0<=r && r<=r1) return mg+mb;
1504 if (g0<=g && g<=g1) return mr+mb;
1505 if (b0<=b && b<=b1) return mg+mr;
1510 static void transparent_threshold(i_quantize *, i_palidx *, i_img *, i_palidx);
1511 static void transparent_errdiff(i_quantize *, i_palidx *, i_img *, i_palidx);
1512 static void transparent_ordered(i_quantize *, i_palidx *, i_img *, i_palidx);
1515 =item i_quant_transparent(C<quant>, C<data>, C<img>, C<trans_index>)
1517 =category Image quantization
1519 Dither the alpha channel on C<img> into the palette indexes in
1520 C<data>. Pixels to be transparent are replaced with C<trans_pixel>.
1522 The method used depends on the tr_* members of C<quant>.
1528 i_quant_transparent(i_quantize *quant, i_palidx *data, i_img *img,
1529 i_palidx trans_index)
1531 switch (quant->transp) {
1536 quant->tr_threshold = 128;
1539 transparent_threshold(quant, data, img, trans_index);
1543 transparent_errdiff(quant, data, img, trans_index);
1547 transparent_ordered(quant, data, img, trans_index);
1553 transparent_threshold(i_quantize *quant, i_palidx *data, i_img *img,
1554 i_palidx trans_index)
1557 i_sample_t *line = mymalloc(img->xsize * sizeof(i_sample_t));
1558 int trans_chan = img->channels > 2 ? 3 : 1;
1560 for (y = 0; y < img->ysize; ++y) {
1561 i_gsamp(img, 0, img->xsize, y, line, &trans_chan, 1);
1562 for (x = 0; x < img->xsize; ++x) {
1563 if (line[x] < quant->tr_threshold)
1564 data[y*img->xsize+x] = trans_index;
1571 transparent_errdiff(i_quantize *quant, i_palidx *data, i_img *img,
1572 i_palidx trans_index)
1576 int mapw, maph, mapo;
1577 int errw, *err, *errp;
1578 int difftotal, out, error;
1579 int x, y, dx, dy, i;
1581 int trans_chan = img->channels > 2 ? 3 : 1;
1583 /* no custom map for transparency (yet) */
1584 index = quant->tr_errdiff & ed_mask;
1585 if (index >= ed_custom) index = ed_floyd;
1586 map = maps[index].map;
1587 mapw = maps[index].width;
1588 maph = maps[index].height;
1589 mapo = maps[index].orig;
1591 errw = img->xsize+mapw-1;
1592 err = mymalloc(sizeof(*err) * maph * errw);
1594 memset(err, 0, sizeof(*err) * maph * errw);
1596 line = mymalloc(img->xsize * sizeof(i_sample_t));
1598 for (i = 0; i < maph * mapw; ++i)
1599 difftotal += map[i];
1600 for (y = 0; y < img->ysize; ++y) {
1601 i_gsamp(img, 0, img->xsize, y, line, &trans_chan, 1);
1602 for (x = 0; x < img->xsize; ++x) {
1603 line[x] = g_sat(line[x]-errp[x]/difftotal);
1604 if (line[x] < 128) {
1606 data[y*img->xsize+x] = trans_index;
1611 error = out - line[x];
1612 for (dx = 0; dx < mapw; ++dx) {
1613 for (dy = 0; dy < maph; ++dy) {
1614 errp[x+dx-mapo+dy*errw] += error * map[dx+mapw*dy];
1618 /* shift up the error matrix */
1619 for (dy = 0; dy < maph-1; ++dy)
1620 memcpy(err+dy*errw, err+(dy+1)*errw, sizeof(*err)*errw);
1621 memset(err+(maph-1)*errw, 0, sizeof(*err)*errw);
1627 /* builtin ordered dither maps */
1628 static unsigned char
1629 orddith_maps[][64] =
1632 this is purely random - it's pretty awful
1634 48, 72, 196, 252, 180, 92, 108, 52,
1635 228, 176, 64, 8, 236, 40, 20, 164,
1636 120, 128, 84, 116, 24, 28, 172, 220,
1637 68, 0, 188, 124, 184, 224, 192, 104,
1638 132, 100, 240, 200, 152, 160, 244, 44,
1639 96, 204, 144, 16, 140, 56, 232, 216,
1640 208, 4, 76, 212, 136, 248, 80, 168,
1641 156, 88, 32, 112, 148, 12, 36, 60,
1645 perl spot.perl '($x-3.5)*($x-3.5)+($y-3.5)*($y-3.5)'
1647 240, 232, 200, 136, 140, 192, 228, 248,
1648 220, 148, 100, 76, 80, 104, 152, 212,
1649 180, 116, 56, 32, 36, 60, 120, 176,
1650 156, 64, 28, 0, 8, 44, 88, 160,
1651 128, 92, 24, 12, 4, 40, 68, 132,
1652 184, 96, 48, 20, 16, 52, 108, 188,
1653 216, 144, 112, 72, 84, 124, 164, 224,
1654 244, 236, 196, 168, 172, 204, 208, 252,
1658 'min(dist(1.5, 1.5),dist(5.5,1.5),dist(1.5,5.5),dist(5.5,5.5))'
1660 196, 72, 104, 220, 200, 80, 112, 224,
1661 76, 4, 24, 136, 84, 8, 32, 144,
1662 108, 28, 52, 168, 116, 36, 56, 176,
1663 216, 140, 172, 244, 228, 148, 180, 248,
1664 204, 92, 124, 236, 192, 68, 96, 208,
1665 88, 12, 44, 156, 64, 0, 16, 128,
1666 120, 40, 60, 188, 100, 20, 48, 160,
1667 232, 152, 184, 252, 212, 132, 164, 240,
1670 perl spot.perl '$y-3'
1672 160, 164, 168, 172, 176, 180, 184, 188,
1673 128, 132, 136, 140, 144, 148, 152, 156,
1674 32, 36, 40, 44, 48, 52, 56, 60,
1675 0, 4, 8, 12, 16, 20, 24, 28,
1676 64, 68, 72, 76, 80, 84, 88, 92,
1677 96, 100, 104, 108, 112, 116, 120, 124,
1678 192, 196, 200, 204, 208, 212, 216, 220,
1679 224, 228, 232, 236, 240, 244, 248, 252,
1682 perl spot.perl '$x-3'
1684 180, 100, 40, 12, 44, 104, 184, 232,
1685 204, 148, 60, 16, 64, 128, 208, 224,
1686 212, 144, 76, 8, 80, 132, 216, 244,
1687 160, 112, 68, 20, 84, 108, 172, 236,
1688 176, 96, 72, 28, 88, 152, 188, 228,
1689 200, 124, 92, 0, 32, 116, 164, 240,
1690 168, 120, 36, 24, 48, 136, 192, 248,
1691 196, 140, 52, 4, 56, 156, 220, 252,
1694 perl spot.perl '$y+$x-7'
1696 248, 232, 224, 192, 140, 92, 52, 28,
1697 240, 220, 196, 144, 108, 60, 12, 64,
1698 216, 180, 148, 116, 76, 20, 80, 128,
1699 204, 152, 104, 44, 16, 72, 100, 160,
1700 164, 96, 68, 24, 56, 112, 168, 176,
1701 124, 40, 8, 36, 88, 136, 184, 212,
1702 84, 4, 32, 120, 156, 188, 228, 236,
1703 0, 48, 132, 172, 200, 208, 244, 252,
1706 perl spot.perl '$y-$x'
1708 0, 32, 116, 172, 184, 216, 236, 252,
1709 56, 8, 72, 132, 136, 200, 228, 240,
1710 100, 36, 12, 40, 92, 144, 204, 220,
1711 168, 120, 60, 16, 44, 96, 156, 176,
1712 180, 164, 112, 48, 28, 52, 128, 148,
1713 208, 192, 152, 88, 84, 20, 64, 104,
1714 232, 224, 196, 140, 108, 68, 24, 76,
1715 248, 244, 212, 188, 160, 124, 80, 4,
1719 good for display, bad for print
1722 0, 128, 32, 192, 8, 136, 40, 200,
1723 224, 64, 160, 112, 232, 72, 168, 120,
1724 48, 144, 16, 208, 56, 152, 24, 216,
1725 176, 96, 240, 80, 184, 104, 248, 88,
1726 12, 140, 44, 204, 4, 132, 36, 196,
1727 236, 76, 172, 124, 228, 68, 164, 116,
1728 60, 156, 28, 220, 52, 148, 20, 212,
1729 188, 108, 252, 92, 180, 100, 244, 84,
1734 transparent_ordered(i_quantize *quant, i_palidx *data, i_img *img,
1735 i_palidx trans_index)
1737 unsigned char *spot;
1740 int trans_chan = img->channels > 2 ? 3 : 1;
1741 if (quant->tr_orddith == od_custom)
1742 spot = quant->tr_custom;
1744 spot = orddith_maps[quant->tr_orddith];
1746 line = mymalloc(img->xsize * sizeof(i_sample_t));
1747 for (y = 0; y < img->ysize; ++y) {
1748 i_gsamp(img, 0, img->xsize, y, line, &trans_chan, 1);
1749 for (x = 0; x < img->xsize; ++x) {
1750 if (line[x] < spot[(x&7)+(y&7)*8])
1751 data[x+y*img->xsize] = trans_index;