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 =item i_quant_makemap(quant, imgs, count)
32 =category Image quantization
34 Analyzes the I<count> images in I<imgs> according to the rules in
35 I<quant> to build a color map (optimal or not depending on
42 i_quant_makemap(i_quantize *quant, i_img **imgs, int count) {
44 if (quant->translate == pt_giflib) {
45 /* giflib does it's own color table generation */
46 /* previously we used giflib's quantizer, but it didn't handle multiple
47 images, which made it hard to build a global color map
48 We've implemented our own median cut code so we can ignore
50 makemap_mediancut(quant, imgs, count);
54 switch (quant->make_colors & mc_mask) {
56 /* use user's specified map */
62 for (r = 0; r < 256; r+=0x33)
63 for (g = 0; g < 256; g+=0x33)
64 for (b = 0; b < 256; b += 0x33)
65 setcol(quant->mc_colors+i++, r, g, b, 255);
71 makemap_mediancut(quant, imgs, count);
76 makemap_addi(quant, imgs, count);
81 static void translate_closest(i_quantize *, i_img *, i_palidx *);
82 static void translate_errdiff(i_quantize *, i_img *, i_palidx *);
83 static void translate_addi(i_quantize *, i_img *, i_palidx *);
86 =item i_quant_translate(quant, img)
88 =category Image quantization
90 Quantize the image given the palette in quant.
92 On success returns a pointer to a memory block of img->xsize *
93 img->ysize i_palidx entries.
95 On failure returns NULL.
97 You should call myfree() on the returned block when you're done with
100 This function will fail if the supplied palette contains no colors.
105 i_quant_translate(i_quantize *quant, i_img *img) {
109 mm_log((1, "quant_translate(quant %p, img %p)\n", quant, img));
111 /* there must be at least one color in the paletted (though even that
113 if (quant->mc_count == 0) {
114 i_push_error(0, "no colors available for translation");
118 bytes = img->xsize * img->ysize;
119 if (bytes / img->ysize != img->xsize) {
120 i_push_error(0, "integer overflow calculating memory allocation");
123 result = mymalloc(bytes);
125 switch (quant->translate) {
128 translate_closest(quant, img, result);
132 translate_errdiff(quant, img, result);
137 translate_addi(quant, img, result);
144 static void translate_closest(i_quantize *quant, i_img *img, i_palidx *out) {
146 translate_addi(quant, img, out);
149 #define PWR2(x) ((x)*(x))
151 typedef int (*cmpfunc)(const void*, const void*);
174 static void prescan(i_img **im,int count, int cnum, cvec *clr, i_sample_t *line);
175 static void reorder(pbox prescan[512]);
176 static int pboxcmp(const pbox *a,const pbox *b);
177 static void boxcenter(int box,cvec *cv);
178 static float frandn(void);
179 static void boxrand(int box,cvec *cv);
180 static void bbox(int box,int *r0,int *r1,int *g0,int *g1,int *b0,int *b1);
181 static void cr_hashindex(cvec clr[256],int cnum,hashbox hb[512]);
182 static int mindist(int boxnum,cvec *cv);
183 static int maxdist(int boxnum,cvec *cv);
185 /* Some of the simpler functions are kept here to aid the compiler -
186 maybe some of them will be inlined. */
189 pixbox(i_color *ic) { return ((ic->channel[0] & 224)<<1)+ ((ic->channel[1]&224)>>2) + ((ic->channel[2] &224) >> 5); }
192 pixbox_ch(i_sample_t *chans) { return ((chans[0] & 224)<<1)+ ((chans[1]&224)>>2) + ((chans[2] &224) >> 5); }
196 if (in>255) { return 255; }
197 else if (in>0) return in;
204 return rand()/(RAND_MAX+1.0);
210 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]); }
215 eucl_d_ch(cvec* cv,i_sample_t *chans) {
216 return PWR2(cv->r - chans[0]) + PWR2(cv->g - chans[1])
217 + PWR2(cv->b - chans[2]);
222 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]); }
225 gray_samples[] = { 0, 0, 0 };
229 This quantization algorithm and implementation routines are by Arnar
230 M. Hrafnkelson. In case any new ideas are here they are mine since
231 this was written from scratch.
233 The algorithm uses local means in the following way:
235 For each point in the colormap we find which image points
236 have that point as it's closest point. We calculate the mean
237 of those points and in the next iteration it will be the new
238 entry in the colormap.
240 In order to speed this process up (i.e. nearest neighbor problem) We
241 divied the r,g,b space up in equally large 512 boxes. The boxes are
242 numbered from 0 to 511. Their numbering is so that for a given vector
243 it is known that it belongs to the box who is formed by concatenating the
244 3 most significant bits from each component of the RGB triplet.
246 For each box we find the list of points from the colormap who might be
247 closest to any given point within the box. The exact solution
248 involves finding the Voronoi map (or the dual the Delauny
249 triangulation) and has many issues including numerical stability.
251 So we use this approximation:
253 1. Find which point has the shortest maximum distance to the box.
254 2. Find all points that have a shorter minimum distance than that to the box
256 This is a very simple task and is not computationally heavy if one
257 takes into account that the minimum distances from a pixel to a box is
258 always found by checking if it's inside the box or is closest to some
259 side or a corner. Finding the maximum distance is also either a side
262 This approach results 2-3 times more than the actual points needed but
263 is still a good gain over the complete space. Usually when one has a
264 256 Colorcolor map a search over 30 is often obtained.
266 A bit of an enhancement to this approach is to keep a seperate list
267 for each side of the cube, but this will require even more memory.
269 Arnar M. Hrafnkelsson (addi@umich.edu);
273 Extracted from gifquant.c, removed dependencies on gif_lib,
274 and added support for multiple images.
275 starting from 1nov2000 by TonyC <tony@develop-help.com>.
280 makemap_addi(i_quantize *quant, i_img **imgs, int count) {
282 int cnum, i, x, y, bst_idx=0, ld, cd, iter, currhb, img_num;
289 const int *sample_indices;
291 mm_log((1, "makemap_addi(quant %p { mc_count=%d, mc_colors=%p }, imgs %p, count %d)\n",
292 quant, quant->mc_count, quant->mc_colors, imgs, count));
296 clr = i_mempool_alloc(&mp, sizeof(cvec) * quant->mc_size);
297 hb = i_mempool_alloc(&mp, sizeof(hashbox) * 512);
298 for (i=0; i < quant->mc_count; ++i) {
299 clr[i].r = quant->mc_colors[i].rgb.r;
300 clr[i].g = quant->mc_colors[i].rgb.g;
301 clr[i].b = quant->mc_colors[i].rgb.b;
305 /* mymalloc doesn't clear memory, so I think we need this */
306 for (; i < quant->mc_size; ++i) {
307 /*clr[i].r = clr[i].g = clr[i].b = 0;*/
314 cnum = quant->mc_size;
317 for (img_num = 0; img_num < count; ++img_num) {
318 if (imgs[img_num]->xsize > maxwidth)
319 maxwidth = imgs[img_num]->xsize;
321 line = i_mempool_alloc(&mp, 3 * maxwidth * sizeof(*line));
323 prescan(imgs, count, cnum, clr, line);
324 cr_hashindex(clr, cnum, hb);
326 for(iter=0;iter<3;iter++) {
329 for (img_num = 0; img_num < count; ++img_num) {
330 i_img *im = imgs[img_num];
331 sample_indices = im->channels >= 3 ? NULL : gray_samples;
332 for(y=0;y<im->ysize;y++) {
333 i_gsamp(im, 0, im->xsize, y, line, sample_indices, 3);
335 for(x=0;x<im->xsize;x++) {
337 /*i_gpix(im,x,y,&val);*/
338 currhb=pixbox_ch(val);
339 /* printf("box = %d \n",currhb); */
340 for(i=0;i<hb[currhb].cnt;i++) {
341 /* 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); */
343 cd=eucl_d_ch(&clr[hb[currhb].vec[i]],val);
345 ld=cd; /* shortest distance yet */
346 bst_idx=hb[currhb].vec[i]; /* index of closest vector yet */
350 clr[bst_idx].mcount++;
352 clr[bst_idx].dr+=val[0];
353 clr[bst_idx].dg+=val[1];
354 clr[bst_idx].db+=val[2];
356 val += 3; /* next 3 samples (next pixel) */
363 clr[i].dr/=clr[i].mcount;
364 clr[i].dg/=clr[i].mcount;
365 clr[i].db/=clr[i].mcount;
368 /* for(i=0;i<cnum;i++) printf("vec(%d)=(%d,%d,%d) dest=(%d,%d,%d) matchcount=%d\n",
369 i,clr[i].r,clr[i].g,clr[i].b,clr[i].dr,clr[i].dg,clr[i].db,clr[i].mcount); */
371 /* printf("total error: %.2f\n",sqrt(accerr)); */
373 for(i=0;i<cnum;i++) {
374 if (clr[i].fixed) continue; /* skip reserved colors */
378 clr[i].r=clr[i].r*(1-dlt)+dlt*clr[i].dr;
379 clr[i].g=clr[i].g*(1-dlt)+dlt*clr[i].dg;
380 clr[i].b=clr[i].b*(1-dlt)+dlt*clr[i].db;
382 /* let's try something else */
394 cr_hashindex(clr,cnum,hb);
399 for(i=0;i<cnum;i++) {
400 cd=eucl_d(&clr[i],&val);
408 /* if defined, we only include colours with an mcount or that were
409 supplied in the fixed palette, giving us a smaller output palette */
410 #define ONLY_USE_USED
412 /* transfer the colors back */
414 for (i = 0; i < cnum; ++i) {
415 if (clr[i].fixed || clr[i].used) {
416 /*printf("Adding %d (%d,%d,%d)\n", i, clr[i].r, clr[i].g, clr[i].b);*/
417 quant->mc_colors[quant->mc_count].rgb.r = clr[i].r;
418 quant->mc_colors[quant->mc_count].rgb.g = clr[i].g;
419 quant->mc_colors[quant->mc_count].rgb.b = clr[i].b;
424 /* transfer the colors back */
425 for (i = 0; i < cnum; ++i) {
426 quant->mc_colors[i].rgb.r = clr[i].r;
427 quant->mc_colors[i].rgb.g = clr[i].g;
428 quant->mc_colors[i].rgb.b = clr[i].b;
430 quant->mc_count = cnum;
434 mm_log((1, "makemap_addi returns - quant.mc_count = %d\n", quant->mc_count));
435 for (i = 0; i < quant->mc_count; ++i)
436 mm_log((5, " map entry %d: (%d, %d, %d)\n", i, clr[i].r, clr[i].g, clr[i].b));
439 i_mempool_destroy(&mp);
447 #define MEDIAN_CUT_COLORS 32768
449 #define MED_CUT_INDEX(c) ((((c).rgb.r & 0xF8) << 7) | \
450 (((c).rgb.g & 0xF8) << 2) | (((c).rgb.b & 0xF8) >> 3))
452 #define MED_CUT_GRAY_INDEX(c) ((((c).rgb.r & 0xF8) << 7) | \
453 (((c).rgb.r & 0xF8) << 2) | (((c).rgb.r & 0xF8) >> 3))
455 /* scale these to cover the whole range */
456 #define MED_CUT_RED(index) ((((index) & 0x7C00) >> 10) * 255 / 31)
457 #define MED_CUT_GREEN(index) ((((index) & 0x3E0) >> 5) * 255 / 31)
458 #define MED_CUT_BLUE(index) (((index) & 0x1F) * 255 / 31)
461 i_sample_t min[3]; /* minimum for each channel */
462 i_sample_t max[3]; /* maximum for each channel */
463 i_sample_t width[3]; /* width for each channel */
464 int start, size; /* beginning and size of the partition */
465 int pixels; /* number of pixels represented by this partition */
469 =item calc_part(part, colors)
471 Calculates the new color limits for the given partition.
473 Giflib assumes that the limits for the non-split channels stay the
474 same, but this strikes me as incorrect, especially if the colors tend
477 Of course this could be optimized by not recalculating the channel we
478 just sorted on, but it's not worth the effort right now.
482 static void calc_part(medcut_partition *part, quant_color_entry *colors) {
485 for (ch = 0; ch < 3; ++ch) {
489 for (i = part->start; i < part->start + part->size; ++i) {
490 for (ch = 0; ch < 3; ++ch) {
491 if (part->min[ch] > colors[i].rgb[ch])
492 part->min[ch] = colors[i].rgb[ch];
493 if (part->max[ch] < colors[i].rgb[ch])
494 part->max[ch] = colors[i].rgb[ch];
497 for (ch = 0; ch < 3; ++ch) {
498 part->width[ch] = part->max[ch] - part->min[ch];
502 /* simple functions to sort by each channel - we could use a global, but
506 color_sort_red(void const *left, void const *right) {
507 return ((quant_color_entry *)left)->rgb[0] - ((quant_color_entry *)right)->rgb[0];
511 color_sort_green(void const *left, void const *right) {
512 return ((quant_color_entry *)left)->rgb[1] - ((quant_color_entry *)right)->rgb[1];
516 color_sort_blue(void const *left, void const *right) {
517 return ((quant_color_entry *)left)->rgb[2] - ((quant_color_entry *)right)->rgb[2];
520 static int (*sorters[])(void const *, void const *) =
528 makemap_mediancut(i_quantize *quant, i_img **imgs, int count) {
529 quant_color_entry *colors;
531 int imgn, x, y, i, ch;
536 medcut_partition *parts;
539 /* number of channels we search for the best channel to partition
540 this isn't terribly efficient, but it should work */
543 /*printf("images %d pal size %d\n", count, quant->mc_size);*/
547 colors = i_mempool_alloc(&mp, sizeof(*colors) * MEDIAN_CUT_COLORS);
548 for (i = 0; i < MEDIAN_CUT_COLORS; ++i) {
549 colors[i].rgb[0] = MED_CUT_RED(i);
550 colors[i].rgb[1] = MED_CUT_GREEN(i);
551 colors[i].rgb[2] = MED_CUT_BLUE(i);
556 for (imgn = 0; imgn < count; ++imgn) {
557 if (imgs[imgn]->xsize > max_width)
558 max_width = imgs[imgn]->xsize;
560 line = i_mempool_alloc(&mp, sizeof(i_color) * max_width);
562 /* build the stats */
564 chan_count = 1; /* assume we just have grayscale */
565 for (imgn = 0; imgn < count; ++imgn) {
566 total_pixels += imgs[imgn]->xsize * imgs[imgn]->ysize;
567 for (y = 0; y < imgs[imgn]->ysize; ++y) {
568 i_glin(imgs[imgn], 0, imgs[imgn]->xsize, y, line);
569 if (imgs[imgn]->channels > 2) {
571 for (x = 0; x < imgs[imgn]->xsize; ++x) {
572 ++colors[MED_CUT_INDEX(line[x])].count;
576 /* a gray-scale image, just use the first channel */
577 for (x = 0; x < imgs[imgn]->xsize; ++x) {
578 ++colors[MED_CUT_GRAY_INDEX(line[x])].count;
584 /* eliminate the empty colors */
586 for (in = 0; in < MEDIAN_CUT_COLORS; ++in) {
587 if (colors[in].count) {
588 colors[out++] = colors[in];
591 /*printf("out %d\n", out);
593 for (i = 0; i < out; ++i) {
594 if (colors[i].count) {
595 printf("%d: (%d,%d,%d) -> %d\n", i, colors[i].rgb[0], colors[i].rgb[1],
596 colors[i].rgb[2], colors[i].count);
600 if (out < quant->mc_size) {
601 /* just copy them into the color table */
602 for (i = 0; i < out; ++i) {
603 for (ch = 0; ch < 3; ++ch) {
604 quant->mc_colors[i].channel[ch] = colors[i].rgb[ch];
607 quant->mc_count = out;
610 /* build the starting partition */
611 parts = i_mempool_alloc(&mp, sizeof(*parts) * quant->mc_size);
614 parts[0].pixels = total_pixels;
615 calc_part(parts, colors);
618 while (color_count < quant->mc_size) {
619 int max_index, max_ch; /* index/channel with biggest spread */
621 medcut_partition *workpart;
625 /* find the partition with the most biggest span with more than
628 for (i = 0; i < color_count; ++i) {
629 for (ch = 0; ch < chan_count; ++ch) {
630 if (parts[i].width[ch] > max_size
631 && parts[i].size > 1) {
634 max_size = parts[i].width[ch];
639 /* nothing else we can split */
643 workpart = parts+max_index;
644 /*printf("splitting partition %d (pixels %ld, start %d, size %d)\n", max_index, workpart->pixels, workpart->start, workpart->size);*/
645 qsort(colors + workpart->start, workpart->size, sizeof(*colors),
648 /* find the median or something like it we need to make sure both
649 sides of the split have at least one color in them, so we don't
650 test at the first or last entry */
652 cum_total = colors[i].count;
654 half = workpart->pixels / 2;
655 while (i < workpart->start + workpart->size - 1
656 && cum_total < half) {
657 cum_total += colors[i++].count;
659 /*printf("Split at %d to make %d (half %ld, cumtotal %ld)\n", i, color_count, half, cum_total);*/
661 /* found the spot to split */
662 parts[color_count].start = i;
663 parts[color_count].size = workpart->start + workpart->size - i;
664 workpart->size = i - workpart->start;
665 parts[color_count].pixels = workpart->pixels - cum_total;
666 workpart->pixels = cum_total;
668 /* recalculate the limits */
669 calc_part(workpart, colors);
670 calc_part(parts+color_count, colors);
674 /* fill in the color table - since we could still have partitions
675 that have more than one color, we need to average the colors */
676 for (part_num = 0; part_num < color_count; ++part_num) {
678 medcut_partition *workpart;
680 workpart = parts+part_num;
681 for (ch = 0; ch < 3; ++ch)
684 for (i = workpart->start; i < workpart->start + workpart->size; ++i) {
685 for (ch = 0; ch < 3; ++ch) {
686 sums[ch] += colors[i].rgb[ch] * colors[i].count;
689 for (ch = 0; ch < 3; ++ch) {
690 quant->mc_colors[part_num].channel[ch] = sums[ch] / workpart->pixels;
693 quant->mc_count = color_count;
695 /*printf("out %d colors\n", quant->mc_count);*/
696 i_mempool_destroy(&mp);
701 /* Define one of the following 4 symbols to choose a colour search method
702 The idea is to try these out, including benchmarking, to see which
703 is fastest in a good spread of circumstances.
704 I'd expect IM_CFLINSEARCH to be fastest for very small palettes, and
705 IM_CFHASHBOX for large images with large palettes.
707 Some other possibilities include:
708 - search over entries sorted by luminance
710 Initially I was planning on testing using the macros and then
711 integrating the code directly into each function, but this means if
712 we find a bug at a late stage we will need to update N copies of
713 the same code. Also, keeping the code in the macros means that the
714 code in the translation functions is much more to the point,
715 there's no distracting colour search code to remove attention from
716 what makes _this_ translation function different. It may be
717 advisable to move the setup code into functions at some point, but
718 it should be possible to do this fairly transparently.
720 If IM_CF_COPTS is defined then CFLAGS must have an appropriate
723 Each option needs to define 4 macros:
724 CF_VARS - variables to define in the function
725 CF_SETUP - code to setup for the colour search, eg. allocating and
726 initializing lookup tables
727 CF_FIND - code that looks for the color in val and puts the best
728 matching index in bst_idx
729 CF_CLEANUP - code to clean up, eg. releasing memory
732 /*#define IM_CFLINSEARCH*/
734 /*#define IM_CFSORTCHAN*/
735 /*#define IM_CFRAND2DIST*/
740 /* The original version I wrote for this used the sort.
741 If this is defined then we use a sort to extract the indices for
745 /* assume i is available */
746 #define CF_VARS hashbox *hb = mymalloc(sizeof(hashbox) * 512); \
752 static long *gdists; /* qsort is annoying */
753 /* int might be smaller than long, so we need to do a real compare
754 rather than a subtraction*/
755 static int distcomp(void const *a, void const *b) {
756 long ra = gdists[*(int const *)a];
757 long rb = gdists[*(int const *)b];
768 /* for each hashbox build a list of colours that are in the hb or is closer
770 This is pretty involved. The original gifquant generated the hashbox
771 as part of it's normal processing, but since the map generation is now
772 separated from the translation we need to do this on the spot.
773 Any optimizations, even if they don't produce perfect results would be
776 static void hbsetup(i_quantize *quant, hashbox *hb) {
777 long *dists, mind, maxd;
778 int cr, cb, cg, hbnum, i;
781 int *indices = mymalloc(quant->mc_count * sizeof(int));
784 dists = mymalloc(quant->mc_count * sizeof(long));
785 for (cr = 0; cr < 8; ++cr) {
786 for (cg = 0; cg < 8; ++cg) {
787 for (cb = 0; cb < 8; ++cb) {
788 /* centre of the hashbox */
789 cenc.channel[0] = cr*pboxjump+pboxjump/2;
790 cenc.channel[1] = cg*pboxjump+pboxjump/2;
791 cenc.channel[2] = cb*pboxjump+pboxjump/2;
792 hbnum = pixbox(&cenc);
794 /* order indices in the order of distance from the hashbox */
795 for (i = 0; i < quant->mc_count; ++i) {
799 dists[i] = ceucl_d(&cenc, quant->mc_colors+i);
802 /* it should be possible to do this without a sort
803 but so far I'm too lazy */
805 qsort(indices, quant->mc_count, sizeof(int), distcomp);
806 /* any colors that can match are within mind+diagonal size of
808 mind = dists[indices[0]];
810 maxd = (sqrt(mind)+pboxjump)*(sqrt(mind)+pboxjump);
811 while (i < quant->mc_count && dists[indices[i]] < maxd) {
812 hb[hbnum].vec[hb[hbnum].cnt++] = indices[i++];
815 /* work out the minimum */
817 for (i = 0; i < quant->mc_count; ++i) {
818 if (dists[i] < mind) mind = dists[i];
820 /* transfer any colours that might be closest to a colour in
822 maxd = (sqrt(mind)+pboxjump)*(sqrt(mind)+pboxjump);
823 for (i = 0; i < quant->mc_count; ++i) {
825 hb[hbnum].vec[hb[hbnum].cnt++] = i;
836 #define CF_SETUP hbsetup(quant, hb)
839 currhb = pixbox(&val); \
841 for (i = 0; i < hb[currhb].cnt; ++i) { \
842 cd = ceucl_d(quant->mc_colors+hb[currhb].vec[i], &val); \
843 if (cd < ld) { ld = cd; bst_idx = hb[currhb].vec[i]; } \
846 #define CF_CLEANUP myfree(hb)
850 #ifdef IM_CFLINSEARCH
851 /* as simple as it gets */
852 #define CF_VARS long ld, cd
853 #define CF_SETUP /* none needed */
856 for (i = 0; i < quant->mc_count; ++i) { \
857 cd = ceucl_d(quant->mc_colors+i, &val); \
858 if (cd < ld) { ld = cd; bst_idx = i; } \
864 static int gsortchan;
865 static i_quantize *gquant;
866 static int chansort(void const *a, void const *b) {
867 return gquant->mc_colors[*(int const *)a].channel[gsortchan] -
868 gquant->mc_colors[*(int const *)b].channel[gsortchan];
870 #define CF_VARS int *indices, sortchan, diff; \
872 int vindex[256] /* where to find value i of chan */
874 static void chansetup(i_img *img, i_quantize *quant, int *csortchan,
875 int *vindex, int **cindices) {
876 int *indices, sortchan, chan, i, chval;
877 int chanmins[MAXCHANNELS], chanmaxs[MAXCHANNELS], maxrange;
879 /* find the channel with the maximum range */
880 /* the maximum stddev would probably be better */
881 for (chan = 0; chan < img->channels; ++chan) {
882 chanmins[chan] = 256; chanmaxs[chan] = 0;
883 for (i = 0; i < quant->mc_count; ++i) {
884 if (quant->mc_colors[i].channel[chan] < chanmins[chan])
885 chanmins[chan] = quant->mc_colors[i].channel[chan];
886 if (quant->mc_colors[i].channel[chan] > chanmaxs[chan])
887 chanmaxs[chan] = quant->mc_colors[i].channel[chan];
891 for (chan = 0; chan < img->channels; ++chan) {
892 if (chanmaxs[chan]-chanmins[chan] > maxrange) {
893 maxrange = chanmaxs[chan]-chanmins[chan];
897 indices = mymalloc(quant->mc_count * sizeof(int)) ;
898 for (i = 0; i < quant->mc_count; ++i) {
901 gsortchan = sortchan;
903 qsort(indices, quant->mc_count, sizeof(int), chansort) ;
904 /* now a lookup table to find entries faster */
905 for (chval=0, i=0; i < quant->mc_count; ++i) {
906 while (chval < 256 &&
907 chval < quant->mc_colors[indices[i]].channel[sortchan]) {
911 while (chval < 256) {
912 vindex[chval++] = quant->mc_count-1;
914 *csortchan = sortchan;
919 chansetup(img, quant, &sortchan, vindex, &indices)
921 int chanfind(i_color val, i_quantize *quant, int *indices, int *vindex,
923 int i, bst_idx, diff, maxdiff;
926 i = vindex[val.channel[sortchan]];
927 bst_idx = indices[i];
930 maxdiff = quant->mc_count;
931 while (diff < maxdiff) {
932 if (i+diff < quant->mc_count) {
933 cd = ceucl_d(&val, quant->mc_colors+indices[i+diff]);
935 bst_idx = indices[i+diff];
941 cd = ceucl_d(&val, quant->mc_colors+indices[i-diff]);
943 bst_idx = indices[i-diff];
955 bst_idx = chanfind(val, quant, indices, vindex, sortchan)
958 #define CF_CLEANUP myfree(indices)
962 #ifdef IM_CFRAND2DIST
964 /* This is based on a method described by Addi in the #imager channel
965 on the 28/2/2001. I was about 1am Sydney time at the time, so I
966 wasn't at my most cogent. Well, that's my excuse :)
968 <TonyC> what I have at the moment is: hashboxes, with optimum hash box
969 filling; simple linear search; and a lookup in the widest channel
970 (currently the channel with the maximum range)
971 <Addi> There is one more way that might be simple to implement.
972 <Addi> You want to hear?
974 <purl> somebody said that was not true
975 <Addi> For each of the colors in the palette start by creating a
976 sorted list of the form:
977 <Addi> [distance, color]
978 <Addi> Where they are sorted by distance.
979 <TonyC> distance to where?
980 <Addi> Where the elements in the lists are the distances and colors of
981 the other colors in the palette
983 <Addi> So if you are at color 0
984 <Addi> ok - now to search for the closest color when you are creating
985 the final image is done like this:
986 <Addi> a) pick a random color from the palette
987 <Addi> b) calculate the distance to it
988 <Addi> c) only check the vectors that are within double the distance
989 in the list of the color you picked from the palette.
990 <Addi> Does that seem logical?
991 <Addi> Lets imagine that we only have grayscale to make an example:
992 <Addi> Our palette has 1 4 10 20 as colors.
993 <Addi> And we want to quantize the color 11
994 <Addi> lets say we picked 10 randomly
995 <Addi> the double distance is 2
996 <Addi> since abs(10-11)*2 is 2
997 <Addi> And the list at vector 10 is this:
998 <Addi> [0, 10], [6 4], [9, 1], [10, 20]
999 <Addi> so we look at the first one (but not the second one since 6 is
1000 at a greater distance than 2.
1001 <Addi> Any of that make sense?
1002 <TonyC> yes, though are you suggesting another random jump to one of
1003 the colours with the possible choices? or an exhaustive search?
1004 <Addi> TonyC: It's possible to come up with a recursive/iterative
1005 enhancement but this is the 'basic' version.
1006 <Addi> Which would do an iterative search.
1007 <Addi> You can come up with conditions where it pays to switch to a new one.
1008 <Addi> And the 'random' start can be switched over to a small tree.
1009 <Addi> So you would have a little index at the start.
1010 <Addi> to get you into the general direction
1011 <Addi> Perhaps just an 8 split.
1012 <Addi> that is - split each dimension in half.
1014 <TonyC> I get the idea
1015 <Addi> But this would seem to be a good approach in our case since we
1016 usually have few codevectors.
1017 <Addi> So we only need 256*256 entries in a table.
1018 <Addi> We could even only index some of them that were deemed as good
1020 <TonyC> I was considering adding paletted output support for PNG and
1021 TIFF at some point, which support 16-bit palettes
1029 typedef struct i_dists {
1037 static int dists_sort(void const *a, void const *b) {
1038 return ((i_dists *)a)->dist - ((i_dists *)b)->dist;
1041 static void rand2dist_setup(i_quantize *quant, i_dists **cdists) {
1043 mymalloc(sizeof(i_dists)*quant->mc_count*quant->mc_count);
1046 for (i = 0; i < quant->mc_count; ++i) {
1047 i_dists *ldists = dists + quant->mc_count * i;
1048 i_color val = quant->mc_colors[i];
1049 for (j = 0; j < quant->mc_count; ++j) {
1050 ldists[j].index = j;
1051 ldists[j].dist = ceucl_d(&val, quant->mc_colors+j);
1053 qsort(ldists, quant->mc_count, sizeof(i_dists), dists_sort);
1059 bst_idx = rand() % quant->mc_count; \
1060 rand2dist_setup(quant, &dists)
1062 static int rand2dist_find(i_color val, i_quantize *quant, i_dists *dists, int index) {
1069 cdists = dists + index * quant->mc_count;
1071 maxld = 8 * ceucl_d(&val, quant->mc_colors+index);
1072 for (i = 0; i < quant->mc_count && cdists[i].dist <= maxld; ++i) {
1073 cd = ceucl_d(&val, quant->mc_colors+cdists[i].index);
1075 bst_idx = cdists[i].index;
1082 #define CF_FIND bst_idx = rand2dist_find(val, quant, dists, bst_idx)
1084 #define CF_CLEANUP myfree(dists)
1089 static void translate_addi(i_quantize *quant, i_img *img, i_palidx *out) {
1090 int x, y, i, k, bst_idx;
1092 int pixdev = quant->perturb;
1097 if (img->channels >= 3) {
1100 for(y=0;y<img->ysize;y++) for(x=0;x<img->xsize;x++) {
1101 i_gpix(img,x,y,&val);
1102 val.channel[0]=g_sat(val.channel[0]+(int)(pixdev*frandn()));
1103 val.channel[1]=g_sat(val.channel[1]+(int)(pixdev*frandn()));
1104 val.channel[2]=g_sat(val.channel[2]+(int)(pixdev*frandn()));
1110 for(y=0;y<img->ysize;y++) for(x=0;x<img->xsize;x++) {
1111 i_gpix(img,x,y,&val);
1120 for(y=0;y<img->ysize;y++) for(x=0;x<img->xsize;x++) {
1121 i_gpix(img,x,y,&val);
1122 val.channel[1] = val.channel[2] =
1123 val.channel[0]=g_sat(val.channel[0]+(int)(pixdev*frandn()));
1129 for(y=0;y<img->ysize;y++) for(x=0;x<img->xsize;x++) {
1130 i_gpix(img,x,y,&val);
1131 val.channel[1] = val.channel[2] = val.channel[0];
1140 static int floyd_map[] =
1146 static int jarvis_map[] =
1153 static int stucki_map[] =
1160 struct errdiff_map {
1162 int width, height, orig;
1165 static struct errdiff_map maps[] =
1167 { floyd_map, 3, 2, 1 },
1168 { jarvis_map, 5, 3, 2 },
1169 { stucki_map, 5, 3, 2 },
1172 typedef struct errdiff_tag {
1176 /* perform an error diffusion dither */
1179 translate_errdiff(i_quantize *quant, i_img *img, i_palidx *out) {
1181 int mapw, maph, mapo;
1190 if ((quant->errdiff & ed_mask) == ed_custom) {
1191 map = quant->ed_map;
1192 mapw = quant->ed_width;
1193 maph = quant->ed_height;
1194 mapo = quant->ed_orig;
1197 int index = quant->errdiff & ed_mask;
1198 if (index >= ed_custom) index = ed_floyd;
1199 map = maps[index].map;
1200 mapw = maps[index].width;
1201 maph = maps[index].height;
1202 mapo = maps[index].orig;
1205 errw = img->xsize+mapw;
1206 err = mymalloc(sizeof(*err) * maph * errw);
1207 /*errp = err+mapo;*/
1208 memset(err, 0, sizeof(*err) * maph * errw);
1211 for (i = 0; i < maph * mapw; ++i)
1212 difftotal += map[i];
1214 for (dy = 0; dy < maph; ++dy) {
1215 for (dx = 0; dx < mapw; ++dx) {
1216 printf("%2d", map[dx+dy*mapw]);
1223 for (y = 0; y < img->ysize; ++y) {
1224 for (x = 0; x < img->xsize; ++x) {
1228 i_gpix(img, x, y, &val);
1229 if (img->channels < 3) {
1230 val.channel[1] = val.channel[2] = val.channel[0];
1233 perr.r = perr.r < 0 ? -((-perr.r)/difftotal) : perr.r/difftotal;
1234 perr.g = perr.g < 0 ? -((-perr.g)/difftotal) : perr.g/difftotal;
1235 perr.b = perr.b < 0 ? -((-perr.b)/difftotal) : perr.b/difftotal;
1236 /*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);*/
1237 val.channel[0] = g_sat(val.channel[0]-perr.r);
1238 val.channel[1] = g_sat(val.channel[1]-perr.g);
1239 val.channel[2] = g_sat(val.channel[2]-perr.b);
1242 perr.r = quant->mc_colors[bst_idx].channel[0] - val.channel[0];
1243 perr.g = quant->mc_colors[bst_idx].channel[1] - val.channel[1];
1244 perr.b = quant->mc_colors[bst_idx].channel[2] - val.channel[2];
1245 /*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);*/
1246 for (dx = 0; dx < mapw; ++dx) {
1247 for (dy = 0; dy < maph; ++dy) {
1248 err[x+dx+dy*errw].r += perr.r * map[dx+mapw*dy];
1249 err[x+dx+dy*errw].g += perr.g * map[dx+mapw*dy];
1250 err[x+dx+dy*errw].b += perr.b * map[dx+mapw*dy];
1255 /* shift up the error matrix */
1256 for (dy = 0; dy < maph-1; ++dy) {
1257 memcpy(err+dy*errw, err+(dy+1)*errw, sizeof(*err)*errw);
1259 memset(err+(maph-1)*errw, 0, sizeof(*err)*errw);
1264 /* Prescan finds the boxes in the image that have the highest number of colors
1265 and that result is used as the initial value for the vectores */
1268 static void prescan(i_img **imgs,int count, int cnum, cvec *clr, i_sample_t *line) {
1274 for(i=0;i<512;i++) {
1280 /* process each image */
1281 for (i = 0; i < count; ++i) {
1282 i_img *im = imgs[i];
1283 chans = im->channels >= 3 ? NULL : gray_samples;
1284 for(y=0;y<im->ysize;y++) {
1285 i_gsamp(im, 0, im->xsize, y, line, chans, 3);
1287 for(x=0;x<im->xsize;x++) {
1288 prebox[pixbox_ch(val)].pixcnt++;
1293 for(i=0;i<512;i++) prebox[i].pdc=prebox[i].pixcnt;
1294 qsort(prebox,512,sizeof(pbox),(cmpfunc)pboxcmp);
1296 for(i=0;i<cnum;i++) {
1297 /* printf("Color %d\n",i);
1298 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); }
1303 /* 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); } */
1309 /* printf("prebox[%d].cand=%d\n",k,prebox[k].cand); */
1310 if (clr[i].fixed) { i++; continue; } /* reserved go to next */
1311 if (j>=prebox[k].cand) { k++; j=1; } else {
1312 if (prebox[k].cand == 2) boxcenter(prebox[k].boxnum,&(clr[i]));
1313 else boxrand(prebox[k].boxnum,&(clr[i]));
1314 /* 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); */
1322 static void reorder(pbox prescan[512]) {
1330 c.pdc=c.pixcnt/(c.cand*c.cand);
1331 /* c.pdc=c.pixcnt/c.cand; */
1332 while(c.pdc < prescan[nidx+1].pdc && nidx < 511) {
1333 prescan[nidx]=prescan[nidx+1];
1340 pboxcmp(const pbox *a,const pbox *b) {
1341 if (a->pixcnt > b->pixcnt) return -1;
1342 if (a->pixcnt < b->pixcnt) return 1;
1347 boxcenter(int box,cvec *cv) {
1348 cv->r=15+((box&448)>>1);
1349 cv->g=15+((box&56)<<2);
1350 cv->b=15+((box&7)<<5);
1354 bbox(int box,int *r0,int *r1,int *g0,int *g1,int *b0,int *b1) {
1364 boxrand(int box,cvec *cv) {
1365 cv->r=6+(rand()%25)+((box&448)>>1);
1366 cv->g=6+(rand()%25)+((box&56)<<2);
1367 cv->b=6+(rand()%25)+((box&7)<<5);
1377 while (w >= 1 || w == 0) {
1378 u1 = 2 * frand() - 1;
1379 u2 = 2 * frand() - 1;
1383 w = sqrt((-2*log(w))/w);
1387 /* Create hash index */
1390 cr_hashindex(cvec clr[256],int cnum,hashbox hb[512]) {
1392 int bx,mind,cd,cumcnt,bst_idx,i;
1393 /* printf("indexing... \n");*/
1396 for(bx=0; bx<512; bx++) {
1398 for(i=0; i<cnum; i++) {
1399 cd = maxdist(bx,&clr[i]);
1400 if (cd < mind) { mind=cd; bst_idx=i; }
1404 for(i=0;i<cnum;i++) if (mindist(bx,&clr[i])<mind) hb[bx].vec[hb[bx].cnt++]=i;
1405 /*printf("box %d -> approx -> %d\n",bx,hb[bx].cnt); */
1406 /* statbox(bx,cnum,clr); */
1410 /* printf("Average search space: %d\n",cumcnt/512); */
1414 maxdist(int boxnum,cvec *cv) {
1415 int r0,r1,g0,g1,b0,b1;
1422 bbox(boxnum,&r0,&r1,&g0,&g1,&b0,&b1);
1424 mr=i_max(abs(b-b0),abs(b-b1));
1425 mg=i_max(abs(g-g0),abs(g-g1));
1426 mb=i_max(abs(r-r0),abs(r-r1));
1428 return PWR2(mr)+PWR2(mg)+PWR2(mb);
1432 mindist(int boxnum,cvec *cv) {
1433 int r0,r1,g0,g1,b0,b1;
1440 bbox(boxnum,&r0,&r1,&g0,&g1,&b0,&b1);
1442 /* printf("box %d, (%d,%d,%d)-(%d,%d,%d) vec (%d,%d,%d) ",boxnum,r0,g0,b0,r1,g1,b1,r,g,b); */
1444 if (r0<=r && r<=r1 && g0<=g && g<=g1 && b0<=b && b<=b1) return 0;
1446 mr=i_min(abs(b-b0),abs(b-b1));
1447 mg=i_min(abs(g-g0),abs(g-g1));
1448 mb=i_min(abs(r-r0),abs(r-r1));
1454 if (r0<=r && r<=r1 && g0<=g && g<=g1) return mb;
1455 if (r0<=r && r<=r1 && b0<=b && b<=b1) return mg;
1456 if (b0<=b && b<=b1 && g0<=g && g<=g1) return mr;
1458 if (r0<=r && r<=r1) return mg+mb;
1459 if (g0<=g && g<=g1) return mr+mb;
1460 if (b0<=b && b<=b1) return mg+mr;
1465 static void transparent_threshold(i_quantize *, i_palidx *, i_img *, i_palidx);
1466 static void transparent_errdiff(i_quantize *, i_palidx *, i_img *, i_palidx);
1467 static void transparent_ordered(i_quantize *, i_palidx *, i_img *, i_palidx);
1470 =item i_quant_transparent(quant, data, img, trans_index)
1472 =category Image quantization
1474 Dither the alpha channel on I<img> into the palette indexes in
1475 I<data>. Pixels to be transparent are replaced with I<trans_pixel>.
1477 The method used depends on the tr_* members of quant.
1483 i_quant_transparent(i_quantize *quant, i_palidx *data, i_img *img,
1484 i_palidx trans_index)
1486 switch (quant->transp) {
1491 quant->tr_threshold = 128;
1494 transparent_threshold(quant, data, img, trans_index);
1498 transparent_errdiff(quant, data, img, trans_index);
1502 transparent_ordered(quant, data, img, trans_index);
1508 transparent_threshold(i_quantize *quant, i_palidx *data, i_img *img,
1509 i_palidx trans_index)
1512 i_sample_t *line = mymalloc(img->xsize * sizeof(i_sample_t));
1513 int trans_chan = img->channels > 2 ? 3 : 1;
1515 for (y = 0; y < img->ysize; ++y) {
1516 i_gsamp(img, 0, img->xsize, y, line, &trans_chan, 1);
1517 for (x = 0; x < img->xsize; ++x) {
1518 if (line[x] < quant->tr_threshold)
1519 data[y*img->xsize+x] = trans_index;
1526 transparent_errdiff(i_quantize *quant, i_palidx *data, i_img *img,
1527 i_palidx trans_index)
1531 int mapw, maph, mapo;
1532 int errw, *err, *errp;
1533 int difftotal, out, error;
1534 int x, y, dx, dy, i;
1536 int trans_chan = img->channels > 2 ? 3 : 1;
1538 /* no custom map for transparency (yet) */
1539 index = quant->tr_errdiff & ed_mask;
1540 if (index >= ed_custom) index = ed_floyd;
1541 map = maps[index].map;
1542 mapw = maps[index].width;
1543 maph = maps[index].height;
1544 mapo = maps[index].orig;
1546 errw = img->xsize+mapw-1;
1547 err = mymalloc(sizeof(*err) * maph * errw);
1549 memset(err, 0, sizeof(*err) * maph * errw);
1551 line = mymalloc(img->xsize * sizeof(i_sample_t));
1553 for (i = 0; i < maph * mapw; ++i)
1554 difftotal += map[i];
1555 for (y = 0; y < img->ysize; ++y) {
1556 i_gsamp(img, 0, img->xsize, y, line, &trans_chan, 1);
1557 for (x = 0; x < img->xsize; ++x) {
1558 line[x] = g_sat(line[x]-errp[x]/difftotal);
1559 if (line[x] < 128) {
1561 data[y*img->xsize+x] = trans_index;
1566 error = out - line[x];
1567 for (dx = 0; dx < mapw; ++dx) {
1568 for (dy = 0; dy < maph; ++dy) {
1569 errp[x+dx-mapo+dy*errw] += error * map[dx+mapw*dy];
1573 /* shift up the error matrix */
1574 for (dy = 0; dy < maph-1; ++dy)
1575 memcpy(err+dy*errw, err+(dy+1)*errw, sizeof(*err)*errw);
1576 memset(err+(maph-1)*errw, 0, sizeof(*err)*errw);
1582 /* builtin ordered dither maps */
1583 static unsigned char
1584 orddith_maps[][64] =
1587 this is purely random - it's pretty awful
1589 48, 72, 196, 252, 180, 92, 108, 52,
1590 228, 176, 64, 8, 236, 40, 20, 164,
1591 120, 128, 84, 116, 24, 28, 172, 220,
1592 68, 0, 188, 124, 184, 224, 192, 104,
1593 132, 100, 240, 200, 152, 160, 244, 44,
1594 96, 204, 144, 16, 140, 56, 232, 216,
1595 208, 4, 76, 212, 136, 248, 80, 168,
1596 156, 88, 32, 112, 148, 12, 36, 60,
1600 perl spot.perl '($x-3.5)*($x-3.5)+($y-3.5)*($y-3.5)'
1602 240, 232, 200, 136, 140, 192, 228, 248,
1603 220, 148, 100, 76, 80, 104, 152, 212,
1604 180, 116, 56, 32, 36, 60, 120, 176,
1605 156, 64, 28, 0, 8, 44, 88, 160,
1606 128, 92, 24, 12, 4, 40, 68, 132,
1607 184, 96, 48, 20, 16, 52, 108, 188,
1608 216, 144, 112, 72, 84, 124, 164, 224,
1609 244, 236, 196, 168, 172, 204, 208, 252,
1613 'min(dist(1.5, 1.5),dist(5.5,1.5),dist(1.5,5.5),dist(5.5,5.5))'
1615 196, 72, 104, 220, 200, 80, 112, 224,
1616 76, 4, 24, 136, 84, 8, 32, 144,
1617 108, 28, 52, 168, 116, 36, 56, 176,
1618 216, 140, 172, 244, 228, 148, 180, 248,
1619 204, 92, 124, 236, 192, 68, 96, 208,
1620 88, 12, 44, 156, 64, 0, 16, 128,
1621 120, 40, 60, 188, 100, 20, 48, 160,
1622 232, 152, 184, 252, 212, 132, 164, 240,
1625 perl spot.perl '$y-3'
1627 160, 164, 168, 172, 176, 180, 184, 188,
1628 128, 132, 136, 140, 144, 148, 152, 156,
1629 32, 36, 40, 44, 48, 52, 56, 60,
1630 0, 4, 8, 12, 16, 20, 24, 28,
1631 64, 68, 72, 76, 80, 84, 88, 92,
1632 96, 100, 104, 108, 112, 116, 120, 124,
1633 192, 196, 200, 204, 208, 212, 216, 220,
1634 224, 228, 232, 236, 240, 244, 248, 252,
1637 perl spot.perl '$x-3'
1639 180, 100, 40, 12, 44, 104, 184, 232,
1640 204, 148, 60, 16, 64, 128, 208, 224,
1641 212, 144, 76, 8, 80, 132, 216, 244,
1642 160, 112, 68, 20, 84, 108, 172, 236,
1643 176, 96, 72, 28, 88, 152, 188, 228,
1644 200, 124, 92, 0, 32, 116, 164, 240,
1645 168, 120, 36, 24, 48, 136, 192, 248,
1646 196, 140, 52, 4, 56, 156, 220, 252,
1649 perl spot.perl '$y+$x-7'
1651 248, 232, 224, 192, 140, 92, 52, 28,
1652 240, 220, 196, 144, 108, 60, 12, 64,
1653 216, 180, 148, 116, 76, 20, 80, 128,
1654 204, 152, 104, 44, 16, 72, 100, 160,
1655 164, 96, 68, 24, 56, 112, 168, 176,
1656 124, 40, 8, 36, 88, 136, 184, 212,
1657 84, 4, 32, 120, 156, 188, 228, 236,
1658 0, 48, 132, 172, 200, 208, 244, 252,
1661 perl spot.perl '$y-$x'
1663 0, 32, 116, 172, 184, 216, 236, 252,
1664 56, 8, 72, 132, 136, 200, 228, 240,
1665 100, 36, 12, 40, 92, 144, 204, 220,
1666 168, 120, 60, 16, 44, 96, 156, 176,
1667 180, 164, 112, 48, 28, 52, 128, 148,
1668 208, 192, 152, 88, 84, 20, 64, 104,
1669 232, 224, 196, 140, 108, 68, 24, 76,
1670 248, 244, 212, 188, 160, 124, 80, 4,
1674 good for display, bad for print
1677 0, 128, 32, 192, 8, 136, 40, 200,
1678 224, 64, 160, 112, 232, 72, 168, 120,
1679 48, 144, 16, 208, 56, 152, 24, 216,
1680 176, 96, 240, 80, 184, 104, 248, 88,
1681 12, 140, 44, 204, 4, 132, 36, 196,
1682 236, 76, 172, 124, 228, 68, 164, 116,
1683 60, 156, 28, 220, 52, 148, 20, 212,
1684 188, 108, 252, 92, 180, 100, 244, 84,
1689 transparent_ordered(i_quantize *quant, i_palidx *data, i_img *img,
1690 i_palidx trans_index)
1692 unsigned char *spot;
1695 int trans_chan = img->channels > 2 ? 3 : 1;
1696 if (quant->tr_orddith == od_custom)
1697 spot = quant->tr_custom;
1699 spot = orddith_maps[quant->tr_orddith];
1701 line = mymalloc(img->xsize * sizeof(i_sample_t));
1702 for (y = 0; y < img->ysize; ++y) {
1703 i_gsamp(img, 0, img->xsize, y, line, &trans_chan, 1);
1704 for (x = 0; x < img->xsize; ++x) {
1705 if (line[x] < spot[(x&7)+(y&7)*8])
1706 data[x+y*img->xsize] = trans_index;