File Coverage

quant.c
Criterion Covered Total %
statement 234 645 36.2
branch 102 382 26.7
condition n/a
subroutine n/a
pod n/a
total 336 1027 32.7


line stmt bran cond sub pod time code
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
4             */
5             #include "imager.h"
6             #include "imageri.h"
7              
8             static void makemap_webmap(i_quantize *);
9             static void makemap_addi(i_quantize *, i_img **imgs, int count);
10             static void makemap_mediancut(i_quantize *, i_img **imgs, int count);
11             static void makemap_mono(i_quantize *);
12             static void makemap_gray(i_quantize *, int step);
13              
14             static int makemap_palette(i_quantize *, i_img **imgs, int count);
15              
16             static
17             void
18 1140           setcol(i_color *cl,unsigned char r,unsigned char g,unsigned char b,unsigned char a) {
19 1140           cl->rgba.r=r;
20 1140           cl->rgba.g=g;
21 1140           cl->rgba.b=b;
22 1140           cl->rgba.a=a;
23 1140           }
24              
25              
26              
27             /* make a colour map overwrites mc_existing/mc_count in quant Note
28             that i_makemap will be called once for each image if mc_perimage is
29             set and the format support multiple colour maps per image.
30              
31             This means we don't need any special processing at this level to
32             handle multiple colour maps.
33             */
34              
35             /*
36             =item i_quant_makemap(C, C, C)
37              
38             =category Image quantization
39              
40             Analyzes the C images in C according to the rules in
41             C to build a color map (optimal or not depending on
42             C<< quant->make_colors >>).
43              
44             =cut
45             */
46              
47             void
48 22           i_quant_makemap(i_quantize *quant, i_img **imgs, int count) {
49              
50 22 50         if (quant->translate == pt_giflib) {
51             /* giflib does it's own color table generation */
52             /* previously we used giflib's quantizer, but it didn't handle multiple
53             images, which made it hard to build a global color map
54             We've implemented our own median cut code so we can ignore
55             the giflib version */
56 0           makemap_mediancut(quant, imgs, count);
57 0           return;
58             }
59              
60 22           switch (quant->make_colors & mc_mask) {
61 7           case mc_none:
62             /* use user's specified map */
63 7           break;
64 4           case mc_web_map:
65 4           makemap_webmap(quant);
66 4           break;
67              
68 5           case mc_median_cut:
69 5           makemap_mediancut(quant, imgs, count);
70 5           break;
71              
72 3           case mc_mono:
73 3           makemap_mono(quant);
74 3           break;
75              
76 1           case mc_gray:
77 1           makemap_gray(quant, 1);
78 1           break;
79              
80 1           case mc_gray4:
81 1           makemap_gray(quant, 85);
82 1           break;
83              
84 1           case mc_gray16:
85 1           makemap_gray(quant, 17);
86 1           break;
87              
88 0           case mc_addi:
89             default:
90 0           makemap_addi(quant, imgs, count);
91 0           break;
92             }
93             }
94              
95             static void translate_closest(i_quantize *, i_img *, i_palidx *);
96             static int translate_errdiff(i_quantize *, i_img *, i_palidx *);
97             static void translate_addi(i_quantize *, i_img *, i_palidx *);
98              
99             /*
100             =item i_quant_translate(C, C)
101              
102             =category Image quantization
103              
104             Quantize the image given the palette in C.
105              
106             On success returns a pointer to a memory block of C<< img->xsize *
107             img->ysize >> C entries.
108              
109             On failure returns NULL.
110              
111             You should call myfree() on the returned block when you're done with
112             it.
113              
114             This function will fail if the supplied palette contains no colors.
115              
116             =cut
117             */
118             i_palidx *
119 18           i_quant_translate(i_quantize *quant, i_img *img) {
120             i_palidx *result;
121             size_t bytes;
122              
123 18           mm_log((1, "quant_translate(quant %p, img %p)\n", quant, img));
124              
125             /* there must be at least one color in the paletted (though even that
126             isn't very useful */
127 18 100         if (quant->mc_count == 0) {
128 1           i_push_error(0, "no colors available for translation");
129 1           return NULL;
130             }
131              
132 17           bytes = img->xsize * img->ysize;
133 17 50         if (bytes / img->ysize != img->xsize) {
134 0           i_push_error(0, "integer overflow calculating memory allocation");
135 0           return NULL;
136             }
137 17           result = mymalloc(bytes);
138              
139 17           switch (quant->translate) {
140 12           case pt_closest:
141             case pt_giflib:
142 12           translate_closest(quant, img, result);
143 12           break;
144            
145 5           case pt_errdiff:
146 5 50         if (!translate_errdiff(quant, img, result)) {
147 0           myfree(result);
148 0           return NULL;
149             }
150 5           break;
151            
152 0           case pt_perturb:
153             default:
154 0           translate_addi(quant, img, result);
155 0           break;
156             }
157            
158 17           return result;
159             }
160              
161 12           static void translate_closest(i_quantize *quant, i_img *img, i_palidx *out) {
162 12           quant->perturb = 0;
163 12           translate_addi(quant, img, out);
164 12           }
165              
166             #define PWR2(x) ((x)*(x))
167              
168             typedef int (*cmpfunc)(const void*, const void*);
169              
170             typedef struct {
171             unsigned char r,g,b;
172             char fixed;
173             char used;
174             int dr,dg,db;
175             int cdist;
176             int mcount;
177             } cvec;
178              
179             typedef struct {
180             int cnt;
181             int vec[256];
182             } hashbox;
183              
184             typedef struct {
185             int boxnum;
186             int pixcnt;
187             int cand;
188             int pdc;
189             } pbox;
190              
191             static void prescan(i_img **im,int count, int cnum, cvec *clr, i_sample_t *line);
192             static void reorder(pbox prescan[512]);
193             static int pboxcmp(const pbox *a,const pbox *b);
194             static void boxcenter(int box,cvec *cv);
195             static float frandn(void);
196             static void boxrand(int box,cvec *cv);
197             static void bbox(int box,int *r0,int *r1,int *g0,int *g1,int *b0,int *b1);
198             static void cr_hashindex(cvec clr[256],int cnum,hashbox hb[512]);
199             static int mindist(int boxnum,cvec *cv);
200             static int maxdist(int boxnum,cvec *cv);
201              
202             /* Some of the simpler functions are kept here to aid the compiler -
203             maybe some of them will be inlined. */
204              
205             static int
206 296878           pixbox(i_color *ic) { return ((ic->channel[0] & 224)<<1)+ ((ic->channel[1]&224)>>2) + ((ic->channel[2] &224) >> 5); }
207              
208             static int
209 0           pixbox_ch(i_sample_t *chans) { return ((chans[0] & 224)<<1)+ ((chans[1]&224)>>2) + ((chans[2] &224) >> 5); }
210              
211             static unsigned char
212 270300           g_sat(int in) {
213 270300 100         if (in>255) { return 255; }
214 247920 100         else if (in>0) return in;
215 204655           return 0;
216             }
217              
218             static
219             float
220 0           frand(void) {
221 0           return rand()/(RAND_MAX+1.0);
222             }
223              
224             #ifdef NOTEF
225             static
226             int
227             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]); }
228             #endif
229              
230             static
231             int
232 0           eucl_d_ch(cvec* cv,i_sample_t *chans) {
233 0           return PWR2(cv->r - chans[0]) + PWR2(cv->g - chans[1])
234 0           + PWR2(cv->b - chans[2]);
235             }
236              
237             static int
238 2192846           ceucl_d(i_color *c1, i_color *c2) {
239 2192846           return PWR2(c1->channel[0]-c2->channel[0])
240 2192846           +PWR2(c1->channel[1]-c2->channel[1])
241 2192846           +PWR2(c1->channel[2]-c2->channel[2]);
242             }
243              
244             static const int
245             gray_samples[] = { 0, 0, 0 };
246              
247             /*
248              
249             This quantization algorithm and implementation routines are by Arnar
250             M. Hrafnkelson. In case any new ideas are here they are mine since
251             this was written from scratch.
252              
253             The algorithm uses local means in the following way:
254              
255             For each point in the colormap we find which image points
256             have that point as it's closest point. We calculate the mean
257             of those points and in the next iteration it will be the new
258             entry in the colormap.
259            
260             In order to speed this process up (i.e. nearest neighbor problem) We
261             divied the r,g,b space up in equally large 512 boxes. The boxes are
262             numbered from 0 to 511. Their numbering is so that for a given vector
263             it is known that it belongs to the box who is formed by concatenating the
264             3 most significant bits from each component of the RGB triplet.
265              
266             For each box we find the list of points from the colormap who might be
267             closest to any given point within the box. The exact solution
268             involves finding the Voronoi map (or the dual the Delauny
269             triangulation) and has many issues including numerical stability.
270              
271             So we use this approximation:
272              
273             1. Find which point has the shortest maximum distance to the box.
274             2. Find all points that have a shorter minimum distance than that to the box
275              
276             This is a very simple task and is not computationally heavy if one
277             takes into account that the minimum distances from a pixel to a box is
278             always found by checking if it's inside the box or is closest to some
279             side or a corner. Finding the maximum distance is also either a side
280             or a corner.
281              
282             This approach results 2-3 times more than the actual points needed but
283             is still a good gain over the complete space. Usually when one has a
284             256 Colorcolor map a search over 30 is often obtained.
285              
286             A bit of an enhancement to this approach is to keep a seperate list
287             for each side of the cube, but this will require even more memory.
288              
289             Arnar M. Hrafnkelsson (addi@umich.edu);
290              
291             */
292             /*
293             Extracted from gifquant.c, removed dependencies on gif_lib,
294             and added support for multiple images.
295             starting from 1nov2000 by TonyC .
296              
297             */
298              
299             static void
300 0           makemap_addi(i_quantize *quant, i_img **imgs, int count) {
301             cvec *clr;
302 0           int cnum, i, bst_idx=0, ld, cd, iter, currhb, img_num;
303             i_img_dim x, y;
304             i_sample_t *val;
305             float dlt, accerr;
306             hashbox *hb;
307             i_mempool mp;
308 0           i_img_dim maxwidth = 0;
309             i_sample_t *line;
310             const int *sample_indices;
311              
312 0           mm_log((1, "makemap_addi(quant %p { mc_count=%d, mc_colors=%p }, imgs %p, count %d)\n",
313             quant, quant->mc_count, quant->mc_colors, imgs, count));
314              
315 0 0         if (makemap_palette(quant, imgs, count))
316 0           return;
317            
318 0           i_mempool_init(&mp);
319              
320 0           clr = i_mempool_alloc(&mp, sizeof(cvec) * quant->mc_size);
321 0           hb = i_mempool_alloc(&mp, sizeof(hashbox) * 512);
322 0 0         for (i=0; i < quant->mc_count; ++i) {
323 0           clr[i].r = quant->mc_colors[i].rgb.r;
324 0           clr[i].g = quant->mc_colors[i].rgb.g;
325 0           clr[i].b = quant->mc_colors[i].rgb.b;
326 0           clr[i].fixed = 1;
327 0           clr[i].mcount = 0;
328             }
329             /* mymalloc doesn't clear memory, so I think we need this */
330 0 0         for (; i < quant->mc_size; ++i) {
331             /*clr[i].r = clr[i].g = clr[i].b = 0;*/
332 0           clr[i].dr = 0;
333 0           clr[i].dg = 0;
334 0           clr[i].db = 0;
335 0           clr[i].fixed = 0;
336 0           clr[i].mcount = 0;
337             }
338 0           cnum = quant->mc_size;
339 0           dlt = 1;
340              
341 0 0         for (img_num = 0; img_num < count; ++img_num) {
342 0 0         if (imgs[img_num]->xsize > maxwidth)
343 0           maxwidth = imgs[img_num]->xsize;
344             }
345 0           line = i_mempool_alloc(&mp, 3 * maxwidth * sizeof(*line));
346              
347 0           prescan(imgs, count, cnum, clr, line);
348 0           cr_hashindex(clr, cnum, hb);
349              
350 0 0         for(iter=0;iter<3;iter++) {
351 0           accerr=0.0;
352            
353 0 0         for (img_num = 0; img_num < count; ++img_num) {
354 0           i_img *im = imgs[img_num];
355 0 0         sample_indices = im->channels >= 3 ? NULL : gray_samples;
356 0 0         for(y=0;yysize;y++) {
357 0           i_gsamp(im, 0, im->xsize, y, line, sample_indices, 3);
358 0           val = line;
359 0 0         for(x=0;xxsize;x++) {
360 0           ld=196608;
361             /*i_gpix(im,x,y,&val);*/
362 0           currhb=pixbox_ch(val);
363             /* printf("box = %d \n",currhb); */
364 0 0         for(i=0;i
365             /* 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); */
366            
367 0           cd=eucl_d_ch(&clr[hb[currhb].vec[i]],val);
368 0 0         if (cd
369 0           ld=cd; /* shortest distance yet */
370 0           bst_idx=hb[currhb].vec[i]; /* index of closest vector yet */
371             }
372             }
373            
374 0           clr[bst_idx].mcount++;
375 0           accerr+=(ld);
376 0           clr[bst_idx].dr+=val[0];
377 0           clr[bst_idx].dg+=val[1];
378 0           clr[bst_idx].db+=val[2];
379            
380 0           val += 3; /* next 3 samples (next pixel) */
381             }
382             }
383             }
384            
385 0 0         for(i=0;i
386 0 0         if (clr[i].mcount) {
387 0           clr[i].dr/=clr[i].mcount;
388 0           clr[i].dg/=clr[i].mcount;
389 0           clr[i].db/=clr[i].mcount;
390             }
391            
392             /* for(i=0;i
393             i,clr[i].r,clr[i].g,clr[i].b,clr[i].dr,clr[i].dg,clr[i].db,clr[i].mcount); */
394            
395             /* printf("total error: %.2f\n",sqrt(accerr)); */
396            
397 0 0         for(i=0;i
398 0 0         if (clr[i].fixed) continue; /* skip reserved colors */
399            
400 0 0         if (clr[i].mcount) {
401 0           clr[i].used = 1;
402 0           clr[i].r=clr[i].r*(1-dlt)+dlt*clr[i].dr;
403 0           clr[i].g=clr[i].g*(1-dlt)+dlt*clr[i].dg;
404 0           clr[i].b=clr[i].b*(1-dlt)+dlt*clr[i].db;
405             } else {
406             /* let's try something else */
407 0           clr[i].used = 0;
408             /* the " & 0xFF" prevents "uncontrolled value" warnings from CodeQL */
409 0           clr[i].r = rand() & 0xFF;
410 0           clr[i].g = rand() & 0xFF;
411 0           clr[i].b = rand() & 0xFF;
412             }
413            
414 0           clr[i].dr=0;
415 0           clr[i].dg=0;
416 0           clr[i].db=0;
417 0           clr[i].mcount=0;
418             }
419 0           cr_hashindex(clr,cnum,hb);
420             }
421              
422              
423             #ifdef NOTEF
424             for(i=0;i
425             cd=eucl_d(&clr[i],&val);
426             if (cd
427             ld=cd;
428             bst_idx=i;
429             }
430             }
431             #endif
432              
433             /* if defined, we only include colours with an mcount or that were
434             supplied in the fixed palette, giving us a smaller output palette */
435             #define ONLY_USE_USED
436             #ifdef ONLY_USE_USED
437             /* transfer the colors back */
438 0           quant->mc_count = 0;
439 0 0         for (i = 0; i < cnum; ++i) {
440 0 0         if (clr[i].fixed || clr[i].used) {
    0          
441             /*printf("Adding %d (%d,%d,%d)\n", i, clr[i].r, clr[i].g, clr[i].b);*/
442 0           quant->mc_colors[quant->mc_count].rgb.r = clr[i].r;
443 0           quant->mc_colors[quant->mc_count].rgb.g = clr[i].g;
444 0           quant->mc_colors[quant->mc_count].rgb.b = clr[i].b;
445 0           ++quant->mc_count;
446             }
447             }
448             #else
449             /* transfer the colors back */
450             for (i = 0; i < cnum; ++i) {
451             quant->mc_colors[i].rgb.r = clr[i].r;
452             quant->mc_colors[i].rgb.g = clr[i].g;
453             quant->mc_colors[i].rgb.b = clr[i].b;
454             }
455             quant->mc_count = cnum;
456             #endif
457              
458             #if 0
459             mm_log((1, "makemap_addi returns - quant.mc_count = %d\n", quant->mc_count));
460             for (i = 0; i < quant->mc_count; ++i)
461             mm_log((5, " map entry %d: (%d, %d, %d)\n", i, clr[i].r, clr[i].g, clr[i].b));
462             #endif
463              
464 0           i_mempool_destroy(&mp);
465              
466 0           mm_log((1, "makemap_addi() - %d colors\n", quant->mc_count));
467             }
468              
469             typedef struct {
470             i_sample_t rgb[3];
471             i_img_dim count;
472             } quant_color_entry;
473              
474             #define MEDIAN_CUT_COLORS 32768
475              
476             #define MED_CUT_INDEX(c) ((((c).rgb.r & 0xF8) << 7) | \
477             (((c).rgb.g & 0xF8) << 2) | (((c).rgb.b & 0xF8) >> 3))
478              
479             #define MED_CUT_GRAY_INDEX(c) ((((c).rgb.r & 0xF8) << 7) | \
480             (((c).rgb.r & 0xF8) << 2) | (((c).rgb.r & 0xF8) >> 3))
481              
482             /* scale these to cover the whole range */
483             #define MED_CUT_RED(index) ((((index) & 0x7C00) >> 10) * 255 / 31)
484             #define MED_CUT_GREEN(index) ((((index) & 0x3E0) >> 5) * 255 / 31)
485             #define MED_CUT_BLUE(index) (((index) & 0x1F) * 255 / 31)
486              
487             typedef struct {
488             i_sample_t min[3]; /* minimum for each channel */
489             i_sample_t max[3]; /* maximum for each channel */
490             i_sample_t width[3]; /* width for each channel */
491             int start, size; /* beginning and size of the partition */
492             i_img_dim pixels; /* number of pixels represented by this partition */
493             } medcut_partition;
494              
495             /*
496             =item calc_part(part, colors)
497              
498             Calculates the new color limits for the given partition.
499              
500             Giflib assumes that the limits for the non-split channels stay the
501             same, but this strikes me as incorrect, especially if the colors tend
502             to be color ramps.
503              
504             Of course this could be optimized by not recalculating the channel we
505             just sorted on, but it's not worth the effort right now.
506              
507             =cut
508             */
509 0           static void calc_part(medcut_partition *part, quant_color_entry *colors) {
510             int i, ch;
511            
512 0 0         for (ch = 0; ch < 3; ++ch) {
513 0           part->min[ch] = 255;
514 0           part->max[ch] = 0;
515             }
516 0 0         for (i = part->start; i < part->start + part->size; ++i) {
517 0 0         for (ch = 0; ch < 3; ++ch) {
518 0 0         if (part->min[ch] > colors[i].rgb[ch])
519 0           part->min[ch] = colors[i].rgb[ch];
520 0 0         if (part->max[ch] < colors[i].rgb[ch])
521 0           part->max[ch] = colors[i].rgb[ch];
522             }
523             }
524 0 0         for (ch = 0; ch < 3; ++ch) {
525 0           part->width[ch] = part->max[ch] - part->min[ch];
526             }
527 0           }
528              
529             /* simple functions to sort by each channel - we could use a global, but
530             that would be bad */
531              
532             static int
533 0           color_sort_red(void const *left, void const *right) {
534 0           return ((quant_color_entry *)left)->rgb[0] - ((quant_color_entry *)right)->rgb[0];
535             }
536              
537             static int
538 0           color_sort_green(void const *left, void const *right) {
539 0           return ((quant_color_entry *)left)->rgb[1] - ((quant_color_entry *)right)->rgb[1];
540             }
541              
542             static int
543 0           color_sort_blue(void const *left, void const *right) {
544 0           return ((quant_color_entry *)left)->rgb[2] - ((quant_color_entry *)right)->rgb[2];
545             }
546              
547             static int (*sorters[])(void const *, void const *) =
548             {
549             color_sort_red,
550             color_sort_green,
551             color_sort_blue,
552             };
553              
554             static void
555 5           makemap_mediancut(i_quantize *quant, i_img **imgs, int count) {
556             quant_color_entry *colors;
557             i_mempool mp;
558             int imgn, i, ch;
559             i_img_dim x, y, max_width;
560             i_color *line;
561             int color_count;
562             i_img_dim total_pixels;
563             medcut_partition *parts;
564             int part_num;
565             int in, out;
566             /* number of channels we search for the best channel to partition
567             this isn't terribly efficient, but it should work */
568             int chan_count;
569              
570 5           mm_log((1, "makemap_mediancut(quant %p { mc_count=%d, mc_colors=%p }, imgs %p, count %d)\n",
571             quant, quant->mc_count, quant->mc_colors, imgs, count));
572              
573 5 50         if (makemap_palette(quant, imgs, count))
574 0           return;
575              
576 5           i_mempool_init(&mp);
577              
578 5           colors = i_mempool_alloc(&mp, sizeof(*colors) * MEDIAN_CUT_COLORS);
579 163845 100         for (i = 0; i < MEDIAN_CUT_COLORS; ++i) {
580 163840           colors[i].rgb[0] = MED_CUT_RED(i);
581 163840           colors[i].rgb[1] = MED_CUT_GREEN(i);
582 163840           colors[i].rgb[2] = MED_CUT_BLUE(i);
583 163840           colors[i].count = 0;
584             }
585              
586 5           max_width = -1;
587 10 100         for (imgn = 0; imgn < count; ++imgn) {
588 5 50         if (imgs[imgn]->xsize > max_width)
589 5           max_width = imgs[imgn]->xsize;
590             }
591 5           line = i_mempool_alloc(&mp, sizeof(i_color) * max_width);
592              
593             /* build the stats */
594 5           total_pixels = 0;
595 5           chan_count = 1; /* assume we just have grayscale */
596 10 100         for (imgn = 0; imgn < count; ++imgn) {
597 5           total_pixels += imgs[imgn]->xsize * imgs[imgn]->ysize;
598 452 100         for (y = 0; y < imgs[imgn]->ysize; ++y) {
599 447           i_glin(imgs[imgn], 0, imgs[imgn]->xsize, y, line);
600 447 50         if (imgs[imgn]->channels > 2) {
601 447           chan_count = 3;
602 58121 100         for (x = 0; x < imgs[imgn]->xsize; ++x) {
603 57674           ++colors[MED_CUT_INDEX(line[x])].count;
604             }
605             }
606             else {
607             /* a gray-scale image, just use the first channel */
608 0 0         for (x = 0; x < imgs[imgn]->xsize; ++x) {
609 0           ++colors[MED_CUT_GRAY_INDEX(line[x])].count;
610             }
611             }
612             }
613             }
614              
615             /* eliminate the empty colors */
616 5           out = 0;
617 163845 100         for (in = 0; in < MEDIAN_CUT_COLORS; ++in) {
618 163840 100         if (colors[in].count) {
619 374           colors[out++] = colors[in];
620             }
621             }
622             /*printf("out %d\n", out);
623              
624             for (i = 0; i < out; ++i) {
625             if (colors[i].count) {
626             printf("%d: (%d,%d,%d) -> %d\n", i, colors[i].rgb[0], colors[i].rgb[1],
627             colors[i].rgb[2], colors[i].count);
628             }
629             }*/
630              
631 5 50         if (out < quant->mc_size) {
632             /* just copy them into the color table */
633 379 100         for (i = 0; i < out; ++i) {
634 1496 100         for (ch = 0; ch < 3; ++ch) {
635 1122           quant->mc_colors[i].channel[ch] = colors[i].rgb[ch];
636             }
637 374           quant->mc_colors[i].rgba.a = 255;
638             }
639 5           quant->mc_count = out;
640             }
641             else {
642             /* build the starting partition */
643 0           parts = i_mempool_alloc(&mp, sizeof(*parts) * quant->mc_size);
644 0           parts[0].start = 0;
645 0           parts[0].size = out;
646 0           parts[0].pixels = total_pixels;
647 0           calc_part(parts, colors);
648 0           color_count = 1;
649            
650 0 0         while (color_count < quant->mc_size) {
651             /* initialized to avoid compiler warnings */
652 0           int max_index = 0, max_ch = 0; /* index/channel with biggest spread */
653             int max_size;
654             medcut_partition *workpart;
655             i_img_dim cum_total;
656             i_img_dim half;
657            
658             /* find the partition with the most biggest span with more than
659             one color */
660 0           max_size = -1;
661 0 0         for (i = 0; i < color_count; ++i) {
662 0 0         for (ch = 0; ch < chan_count; ++ch) {
663 0 0         if (parts[i].width[ch] > max_size
664 0 0         && parts[i].size > 1) {
665 0           max_index = i;
666 0           max_ch = ch;
667 0           max_size = parts[i].width[ch];
668             }
669             }
670             }
671            
672             /* nothing else we can split */
673 0 0         if (max_size == -1)
674 0           break;
675            
676 0           workpart = parts+max_index;
677             /*printf("splitting partition %d (pixels %ld, start %d, size %d)\n", max_index, workpart->pixels, workpart->start, workpart->size);*/
678 0           qsort(colors + workpart->start, workpart->size, sizeof(*colors),
679             sorters[max_ch]);
680            
681             /* find the median or something like it we need to make sure both
682             sides of the split have at least one color in them, so we don't
683             test at the first or last entry */
684 0           i = workpart->start;
685 0           cum_total = colors[i].count;
686 0           ++i;
687 0           half = workpart->pixels / 2;
688 0           while (i < workpart->start + workpart->size - 1
689 0 0         && cum_total < half) {
    0          
690 0           cum_total += colors[i++].count;
691             }
692             /*printf("Split at %d to make %d (half %ld, cumtotal %ld)\n", i, color_count, half, cum_total);*/
693            
694             /* found the spot to split */
695 0           parts[color_count].start = i;
696 0           parts[color_count].size = workpart->start + workpart->size - i;
697 0           workpart->size = i - workpart->start;
698 0           parts[color_count].pixels = workpart->pixels - cum_total;
699 0           workpart->pixels = cum_total;
700            
701             /* recalculate the limits */
702 0           calc_part(workpart, colors);
703 0           calc_part(parts+color_count, colors);
704 0           ++color_count;
705             }
706            
707             /* fill in the color table - since we could still have partitions
708             that have more than one color, we need to average the colors */
709 0 0         for (part_num = 0; part_num < color_count; ++part_num) {
710             double sums[3];
711             medcut_partition *workpart;
712            
713 0           workpart = parts+part_num;
714 0 0         for (ch = 0; ch < 3; ++ch)
715 0           sums[ch] = 0;
716            
717 0 0         for (i = workpart->start; i < workpart->start + workpart->size; ++i) {
718 0 0         for (ch = 0; ch < 3; ++ch) {
719 0           sums[ch] += (int)(colors[i].rgb[ch]) * colors[i].count;
720             }
721             }
722 0 0         for (ch = 0; ch < 3; ++ch) {
723 0           quant->mc_colors[part_num].channel[ch] = sums[ch] / workpart->pixels;
724             }
725 0           quant->mc_colors[part_num].rgba.a = 255;
726             }
727 0           quant->mc_count = color_count;
728             }
729             /*printf("out %d colors\n", quant->mc_count);*/
730 5           i_mempool_destroy(&mp);
731              
732 5           mm_log((1, "makemap_mediancut() - %d colors\n", quant->mc_count));
733             }
734              
735             static void
736 3           makemap_mono(i_quantize *quant) {
737 3           quant->mc_colors[0].rgba.r = 0;
738 3           quant->mc_colors[0].rgba.g = 0;
739 3           quant->mc_colors[0].rgba.b = 0;
740 3           quant->mc_colors[0].rgba.a = 255;
741 3           quant->mc_colors[1].rgba.r = 255;
742 3           quant->mc_colors[1].rgba.g = 255;
743 3           quant->mc_colors[1].rgba.b = 255;
744 3           quant->mc_colors[1].rgba.a = 255;
745 3           quant->mc_count = 2;
746 3           }
747              
748             static void
749 3           makemap_gray(i_quantize *quant, int step) {
750 3           int gray = 0;
751 3           int i = 0;
752              
753 279 100         while (gray < 256) {
754 276           setcol(quant->mc_colors+i, gray, gray, gray, 255);
755 276           ++i;
756 276           gray += step;
757             }
758 3           quant->mc_count = i;
759 3           }
760              
761             static void
762 4           makemap_webmap(i_quantize *quant) {
763             int r, g, b;
764              
765 4           int i = 0;
766 28 100         for (r = 0; r < 256; r+=0x33)
767 168 100         for (g = 0; g < 256; g+=0x33)
768 1008 100         for (b = 0; b < 256; b += 0x33)
769 864           setcol(quant->mc_colors+i++, r, g, b, 255);
770 4           quant->mc_count = i;
771 4           }
772              
773             static int
774 0           in_palette(i_color *c, i_quantize *quant, int size) {
775             int i;
776              
777 0 0         for (i = 0; i < size; ++i) {
778 0 0         if (c->channel[0] == quant->mc_colors[i].channel[0]
779 0 0         && c->channel[1] == quant->mc_colors[i].channel[1]
780 0 0         && c->channel[2] == quant->mc_colors[i].channel[2]) {
781 0           return i;
782             }
783             }
784              
785 0           return -1;
786             }
787              
788             /*
789             =item makemap_palette(quant, imgs, count)
790              
791             Tests if all the given images are paletted and have a common palette,
792             if they do it builds that palette.
793              
794             A possible improvement might be to eliminate unused colors in the
795             images palettes.
796              
797             =cut
798             */
799              
800             static int
801 5           makemap_palette(i_quantize *quant, i_img **imgs, int count) {
802 5           int size = quant->mc_count;
803             int i;
804             int imgn;
805             char used[256];
806             int col_count;
807              
808 5           mm_log((1, "makemap_palette(quant %p { mc_count=%d, mc_colors=%p }, imgs %p, count %d)\n",
809             quant, quant->mc_count, quant->mc_colors, imgs, count));
810             /* we try to build a common palette here, if we can manage that, then
811             that's the palette we use */
812 5 50         for (imgn = 0; imgn < count; ++imgn) {
813             int eliminate_unused;
814 5 50         if (imgs[imgn]->type != i_palette_type) {
815 5           mm_log((1, "makemap_palette() -> 0 (non-palette image)\n"));
816 5           return 0;
817             }
818              
819 0 0         if (!i_tags_get_int(&imgs[imgn]->tags, "gif_eliminate_unused", 0,
820             &eliminate_unused)) {
821 0           eliminate_unused = 1;
822             }
823              
824 0 0         if (eliminate_unused) {
825 0           i_palidx *line = mymalloc(sizeof(i_palidx) * imgs[imgn]->xsize);
826             i_img_dim x, y;
827 0           memset(used, 0, sizeof(used));
828              
829 0 0         for (y = 0; y < imgs[imgn]->ysize; ++y) {
830 0 0         i_gpal(imgs[imgn], 0, imgs[imgn]->xsize, y, line);
831 0 0         for (x = 0; x < imgs[imgn]->xsize; ++x)
832 0           used[line[x]] = 1;
833             }
834              
835 0           myfree(line);
836             }
837             else {
838             /* assume all are in use */
839 0           memset(used, 1, sizeof(used));
840             }
841              
842 0 0         col_count = i_colorcount(imgs[imgn]);
843 0 0         for (i = 0; i < col_count; ++i) {
844             i_color c;
845            
846 0 0         i_getcolors(imgs[imgn], i, &c, 1);
847 0 0         if (used[i]) {
848 0 0         if (in_palette(&c, quant, size) < 0) {
849 0 0         if (size < quant->mc_size) {
850 0           quant->mc_colors[size++] = c;
851             }
852             else {
853 0           mm_log((1, "makemap_palette() -> 0 (too many colors)\n"));
854 0           return 0;
855             }
856             }
857             }
858             }
859             }
860              
861 0           mm_log((1, "makemap_palette() -> 1 (%d total colors)\n", size));
862 0           quant->mc_count = size;
863              
864 0           return 1;
865             }
866              
867             #define pboxjump 32
868              
869             /* Define one of the following 4 symbols to choose a colour search method
870             The idea is to try these out, including benchmarking, to see which
871             is fastest in a good spread of circumstances.
872             I'd expect IM_CFLINSEARCH to be fastest for very small palettes, and
873             IM_CFHASHBOX for large images with large palettes.
874              
875             Some other possibilities include:
876             - search over entries sorted by luminance
877              
878             Initially I was planning on testing using the macros and then
879             integrating the code directly into each function, but this means if
880             we find a bug at a late stage we will need to update N copies of
881             the same code. Also, keeping the code in the macros means that the
882             code in the translation functions is much more to the point,
883             there's no distracting colour search code to remove attention from
884             what makes _this_ translation function different. It may be
885             advisable to move the setup code into functions at some point, but
886             it should be possible to do this fairly transparently.
887              
888             If IM_CF_COPTS is defined then CFLAGS must have an appropriate
889             definition.
890              
891             Each option needs to define 4 macros:
892             CF_VARS - variables to define in the function
893             CF_SETUP - code to setup for the colour search, eg. allocating and
894             initializing lookup tables
895             CF_FIND - code that looks for the color in val and puts the best
896             matching index in bst_idx
897             CF_CLEANUP - code to clean up, eg. releasing memory
898             */
899             #ifndef IM_CF_COPTS
900             /*#define IM_CFLINSEARCH*/
901             #define IM_CFHASHBOX
902             /*#define IM_CFSORTCHAN*/
903             /*#define IM_CFRAND2DIST*/
904             #endif
905              
906             /* return true if the color map contains only grays */
907             static int
908 5           is_gray_map(const i_quantize *quant) {
909             int i;
910              
911 11 100         for (i = 0; i < quant->mc_count; ++i) {
912 10 100         if (quant->mc_colors[i].rgb.r != quant->mc_colors[i].rgb.g
913 8 100         || quant->mc_colors[i].rgb.r != quant->mc_colors[i].rgb.b) {
914 4           mm_log((1, " not a gray map\n"));
915 4           return 0;
916             }
917             }
918              
919 1           mm_log((1, " is a gray map\n"));
920 1           return 1;
921             }
922              
923             #ifdef IM_CFHASHBOX
924              
925             /* The original version I wrote for this used the sort.
926             If this is defined then we use a sort to extract the indices for
927             the hashbox */
928             #define HB_SORT
929              
930             /* assume i is available */
931             #define CF_VARS hashbox *hb = mymalloc(sizeof(hashbox) * 512); \
932             int currhb; \
933             long ld, cd
934              
935             #ifdef HB_SORT
936              
937             static long *gdists; /* qsort is annoying */
938             /* int might be smaller than long, so we need to do a real compare
939             rather than a subtraction*/
940 3787328           static int distcomp(void const *a, void const *b) {
941 3787328           long ra = gdists[*(int const *)a];
942 3787328           long rb = gdists[*(int const *)b];
943 3787328 100         if (ra < rb)
944 1740270           return -1;
945 2047058 100         else if (ra > rb)
946 1944402           return 1;
947             else
948 102656           return 0;
949             }
950              
951             #endif
952              
953             /* for each hashbox build a list of colours that are in the hb or is closer
954             than other colours
955             This is pretty involved. The original gifquant generated the hashbox
956             as part of it's normal processing, but since the map generation is now
957             separated from the translation we need to do this on the spot.
958             Any optimizations, even if they don't produce perfect results would be
959             welcome.
960             */
961 17           static void hbsetup(i_quantize *quant, hashbox *hb) {
962             long *dists, mind, maxd;
963             int cr, cb, cg, hbnum, i;
964             i_color cenc;
965             #ifdef HB_SORT
966 17           int *indices = mymalloc(quant->mc_count * sizeof(int));
967             #endif
968              
969 17           dists = mymalloc(quant->mc_count * sizeof(long));
970 153 100         for (cr = 0; cr < 8; ++cr) {
971 1224 100         for (cg = 0; cg < 8; ++cg) {
972 9792 100         for (cb = 0; cb < 8; ++cb) {
973             /* centre of the hashbox */
974 8704           cenc.channel[0] = cr*pboxjump+pboxjump/2;
975 8704           cenc.channel[1] = cg*pboxjump+pboxjump/2;
976 8704           cenc.channel[2] = cb*pboxjump+pboxjump/2;
977 8704           hbnum = pixbox(&cenc);
978 8704           hb[hbnum].cnt = 0;
979             /* order indices in the order of distance from the hashbox */
980 662528 100         for (i = 0; i < quant->mc_count; ++i) {
981             #ifdef HB_SORT
982 653824           indices[i] = i;
983             #endif
984 653824           dists[i] = ceucl_d(&cenc, quant->mc_colors+i);
985             }
986             #ifdef HB_SORT
987             /* it should be possible to do this without a sort
988             but so far I'm too lazy */
989 8704           gdists = dists;
990 8704           qsort(indices, quant->mc_count, sizeof(int), distcomp);
991             /* any colors that can match are within mind+diagonal size of
992             a hashbox */
993 8704           mind = dists[indices[0]];
994 8704           i = 0;
995 8704           maxd = (sqrt(mind)+pboxjump)*(sqrt(mind)+pboxjump);
996 50213 100         while (i < quant->mc_count && dists[indices[i]] < maxd) {
    100          
997 41509           hb[hbnum].vec[hb[hbnum].cnt++] = indices[i++];
998             }
999             #else
1000             /* work out the minimum */
1001             mind = 256*256*3;
1002             for (i = 0; i < quant->mc_count; ++i) {
1003             if (dists[i] < mind) mind = dists[i];
1004             }
1005             /* transfer any colours that might be closest to a colour in
1006             this hashbox */
1007             maxd = (sqrt(mind)+pboxjump)*(sqrt(mind)+pboxjump);
1008             for (i = 0; i < quant->mc_count; ++i) {
1009             if (dists[i] < maxd)
1010             hb[hbnum].vec[hb[hbnum].cnt++] = i;
1011             }
1012             #endif
1013             }
1014             }
1015             }
1016             #ifdef HB_SORT
1017 17           myfree(indices);
1018             #endif
1019 17           myfree(dists) ;
1020 17           }
1021             #define CF_SETUP hbsetup(quant, hb)
1022              
1023             #define CF_FIND \
1024             currhb = pixbox(&val); \
1025             ld = 196608; \
1026             for (i = 0; i < hb[currhb].cnt; ++i) { \
1027             cd = ceucl_d(quant->mc_colors+hb[currhb].vec[i], &val); \
1028             if (cd < ld) { ld = cd; bst_idx = hb[currhb].vec[i]; } \
1029             }
1030              
1031             #define CF_CLEANUP myfree(hb)
1032            
1033             #endif
1034              
1035             #ifdef IM_CFLINSEARCH
1036             /* as simple as it gets */
1037             #define CF_VARS long ld, cd
1038             #define CF_SETUP /* none needed */
1039             #define CF_FIND \
1040             ld = 196608; \
1041             for (i = 0; i < quant->mc_count; ++i) { \
1042             cd = ceucl_d(quant->mc_colors+i, &val); \
1043             if (cd < ld) { ld = cd; bst_idx = i; } \
1044             }
1045             #define CF_CLEANUP
1046             #endif
1047              
1048             #ifdef IM_CFSORTCHAN
1049             static int gsortchan;
1050             static i_quantize *gquant;
1051             static int chansort(void const *a, void const *b) {
1052             return gquant->mc_colors[*(int const *)a].channel[gsortchan] -
1053             gquant->mc_colors[*(int const *)b].channel[gsortchan];
1054             }
1055             #define CF_VARS int *indices, sortchan, diff; \
1056             long ld, cd; \
1057             int vindex[256] /* where to find value i of chan */
1058              
1059             static void chansetup(i_img *img, i_quantize *quant, int *csortchan,
1060             int *vindex, int **cindices) {
1061             int *indices, sortchan, chan, i, chval;
1062             int chanmins[MAXCHANNELS], chanmaxs[MAXCHANNELS], maxrange;
1063              
1064             /* find the channel with the maximum range */
1065             /* the maximum stddev would probably be better */
1066             for (chan = 0; chan < img->channels; ++chan) {
1067             chanmins[chan] = 256; chanmaxs[chan] = 0;
1068             for (i = 0; i < quant->mc_count; ++i) {
1069             if (quant->mc_colors[i].channel[chan] < chanmins[chan])
1070             chanmins[chan] = quant->mc_colors[i].channel[chan];
1071             if (quant->mc_colors[i].channel[chan] > chanmaxs[chan])
1072             chanmaxs[chan] = quant->mc_colors[i].channel[chan];
1073             }
1074             }
1075             maxrange = -1;
1076             for (chan = 0; chan < img->channels; ++chan) {
1077             if (chanmaxs[chan]-chanmins[chan] > maxrange) {
1078             maxrange = chanmaxs[chan]-chanmins[chan];
1079             sortchan = chan;
1080             }
1081             }
1082             indices = mymalloc(quant->mc_count * sizeof(int)) ;
1083             for (i = 0; i < quant->mc_count; ++i) {
1084             indices[i] = i;
1085             }
1086             gsortchan = sortchan;
1087             gquant = quant;
1088             qsort(indices, quant->mc_count, sizeof(int), chansort) ;
1089             /* now a lookup table to find entries faster */
1090             for (chval=0, i=0; i < quant->mc_count; ++i) {
1091             while (chval < 256 &&
1092             chval < quant->mc_colors[indices[i]].channel[sortchan]) {
1093             vindex[chval++] = i;
1094             }
1095             }
1096             while (chval < 256) {
1097             vindex[chval++] = quant->mc_count-1;
1098             }
1099             *csortchan = sortchan;
1100             *cindices = indices;
1101             }
1102              
1103             #define CF_SETUP \
1104             chansetup(img, quant, &sortchan, vindex, &indices)
1105              
1106             int chanfind(i_color val, i_quantize *quant, int *indices, int *vindex,
1107             int sortchan) {
1108             int i, bst_idx, diff, maxdiff;
1109             long ld, cd;
1110              
1111             i = vindex[val.channel[sortchan]];
1112             bst_idx = indices[i];
1113             ld = 196608;
1114             diff = 0;
1115             maxdiff = quant->mc_count;
1116             while (diff < maxdiff) {
1117             if (i+diff < quant->mc_count) {
1118             cd = ceucl_d(&val, quant->mc_colors+indices[i+diff]);
1119             if (cd < ld) {
1120             bst_idx = indices[i+diff];
1121             ld = cd;
1122             maxdiff = sqrt(ld);
1123             }
1124             }
1125             if (i-diff >= 0) {
1126             cd = ceucl_d(&val, quant->mc_colors+indices[i-diff]);
1127             if (cd < ld) {
1128             bst_idx = indices[i-diff];
1129             ld = cd;
1130             maxdiff = sqrt(ld);
1131             }
1132             }
1133             ++diff;
1134             }
1135              
1136             return bst_idx;
1137             }
1138              
1139             #define CF_FIND \
1140             bst_idx = chanfind(val, quant, indices, vindex, sortchan)
1141            
1142              
1143             #define CF_CLEANUP myfree(indices)
1144              
1145             #endif
1146              
1147             #ifdef IM_CFRAND2DIST
1148              
1149             /* This is based on a method described by Addi in the #imager channel
1150             on the 28/2/2001. I was about 1am Sydney time at the time, so I
1151             wasn't at my most cogent. Well, that's my excuse :)
1152              
1153             what I have at the moment is: hashboxes, with optimum hash box
1154             filling; simple linear search; and a lookup in the widest channel
1155             (currently the channel with the maximum range)
1156             There is one more way that might be simple to implement.
1157             You want to hear?
1158             what's that?
1159             somebody said that was not true
1160             For each of the colors in the palette start by creating a
1161             sorted list of the form:
1162             [distance, color]
1163             Where they are sorted by distance.
1164             distance to where?
1165             Where the elements in the lists are the distances and colors of
1166             the other colors in the palette
1167             ok
1168             So if you are at color 0
1169             ok - now to search for the closest color when you are creating
1170             the final image is done like this:
1171             a) pick a random color from the palette
1172             b) calculate the distance to it
1173             c) only check the vectors that are within double the distance
1174             in the list of the color you picked from the palette.
1175             Does that seem logical?
1176             Lets imagine that we only have grayscale to make an example:
1177             Our palette has 1 4 10 20 as colors.
1178             And we want to quantize the color 11
1179             lets say we picked 10 randomly
1180             the double distance is 2
1181             since abs(10-11)*2 is 2
1182             And the list at vector 10 is this:
1183             [0, 10], [6 4], [9, 1], [10, 20]
1184             so we look at the first one (but not the second one since 6 is
1185             at a greater distance than 2.
1186             Any of that make sense?
1187             yes, though are you suggesting another random jump to one of
1188             the colours with the possible choices? or an exhaustive search?
1189             TonyC: It's possible to come up with a recursive/iterative
1190             enhancement but this is the 'basic' version.
1191             Which would do an iterative search.
1192             You can come up with conditions where it pays to switch to a new one.
1193             And the 'random' start can be switched over to a small tree.
1194             So you would have a little index at the start.
1195             to get you into the general direction
1196             Perhaps just an 8 split.
1197             that is - split each dimension in half.
1198             yep
1199             I get the idea
1200             But this would seem to be a good approach in our case since we
1201             usually have few codevectors.
1202             So we only need 256*256 entries in a table.
1203             We could even only index some of them that were deemed as good
1204             candidates.
1205             I was considering adding paletted output support for PNG and
1206             TIFF at some point, which support 16-bit palettes
1207             ohh.
1208             'darn' ;)
1209              
1210              
1211             */
1212              
1213              
1214             typedef struct i_dists {
1215             int index;
1216             long dist;
1217             } i_dists;
1218              
1219             #define CF_VARS \
1220             i_dists *dists;
1221              
1222             static int dists_sort(void const *a, void const *b) {
1223             return ((i_dists *)a)->dist - ((i_dists *)b)->dist;
1224             }
1225              
1226             static void rand2dist_setup(i_quantize *quant, i_dists **cdists) {
1227             i_dists *dists =
1228             mymalloc(sizeof(i_dists)*quant->mc_count*quant->mc_count);
1229             int i, j;
1230             long cd;
1231             for (i = 0; i < quant->mc_count; ++i) {
1232             i_dists *ldists = dists + quant->mc_count * i;
1233             i_color val = quant->mc_colors[i];
1234             for (j = 0; j < quant->mc_count; ++j) {
1235             ldists[j].index = j;
1236             ldists[j].dist = ceucl_d(&val, quant->mc_colors+j);
1237             }
1238             qsort(ldists, quant->mc_count, sizeof(i_dists), dists_sort);
1239             }
1240             *cdists = dists;
1241             }
1242              
1243             #define CF_SETUP \
1244             bst_idx = rand() % quant->mc_count; \
1245             rand2dist_setup(quant, &dists)
1246              
1247             static int rand2dist_find(i_color val, i_quantize *quant, i_dists *dists, int index) {
1248             i_dists *cdists;
1249             long cd, ld;
1250             long maxld;
1251             int i;
1252             int bst_idx;
1253              
1254             cdists = dists + index * quant->mc_count;
1255             ld = 3 * 256 * 256;
1256             maxld = 8 * ceucl_d(&val, quant->mc_colors+index);
1257             for (i = 0; i < quant->mc_count && cdists[i].dist <= maxld; ++i) {
1258             cd = ceucl_d(&val, quant->mc_colors+cdists[i].index);
1259             if (cd < ld) {
1260             bst_idx = cdists[i].index;
1261             ld = cd;
1262             }
1263             }
1264             return bst_idx;
1265             }
1266              
1267             #define CF_FIND bst_idx = rand2dist_find(val, quant, dists, bst_idx)
1268              
1269             #define CF_CLEANUP myfree(dists)
1270              
1271              
1272             #endif
1273              
1274 12           static void translate_addi(i_quantize *quant, i_img *img, i_palidx *out) {
1275             i_img_dim x, y, k;
1276 12           int i, bst_idx = 0;
1277             i_color val;
1278 12           int pixdev = quant->perturb;
1279 12           CF_VARS;
1280              
1281 12           CF_SETUP;
1282              
1283 12 50         if (img->channels >= 3) {
1284 12 50         if (pixdev) {
1285 0           k=0;
1286 0 0         for(y=0;yysize;y++) for(x=0;xxsize;x++) {
    0          
1287 0           i_gpix(img,x,y,&val);
1288 0           val.channel[0]=g_sat(val.channel[0]+(int)(pixdev*frandn()));
1289 0           val.channel[1]=g_sat(val.channel[1]+(int)(pixdev*frandn()));
1290 0           val.channel[2]=g_sat(val.channel[2]+(int)(pixdev*frandn()));
1291 0 0         CF_FIND;
    0          
1292 0           out[k++]=bst_idx;
1293             }
1294             } else {
1295 12           k=0;
1296 199445 100         for(y=0;yysize;y++) for(x=0;xxsize;x++) {
    100          
1297 198074           i_gpix(img,x,y,&val);
1298 1357746 100         CF_FIND;
    100          
1299 198074           out[k++]=bst_idx;
1300             }
1301             }
1302             }
1303             else {
1304 0 0         if (pixdev) {
1305 0           k=0;
1306 0 0         for(y=0;yysize;y++) for(x=0;xxsize;x++) {
    0          
1307 0           i_gpix(img,x,y,&val);
1308 0           val.channel[1] = val.channel[2] =
1309 0           val.channel[0]=g_sat(val.channel[0]+(int)(pixdev*frandn()));
1310 0 0         CF_FIND;
    0          
1311 0           out[k++]=bst_idx;
1312             }
1313             } else {
1314 0           k=0;
1315 0 0         for(y=0;yysize;y++) for(x=0;xxsize;x++) {
    0          
1316 0           i_gpix(img,x,y,&val);
1317 0           val.channel[1] = val.channel[2] = val.channel[0];
1318 0 0         CF_FIND;
    0          
1319 0           out[k++]=bst_idx;
1320             }
1321             }
1322             }
1323 12           CF_CLEANUP;
1324 12           }
1325              
1326             static int floyd_map[] =
1327             {
1328             0, 0, 7,
1329             3, 5, 1
1330             };
1331              
1332             static int jarvis_map[] =
1333             {
1334             0, 0, 0, 7, 5,
1335             3, 5, 7, 5, 3,
1336             1, 3, 5, 3, 1
1337             };
1338              
1339             static int stucki_map[] =
1340             {
1341             0, 0, 0, 8, 4,
1342             2, 4, 8, 4, 2,
1343             1, 2, 4, 2, 1
1344             };
1345              
1346             struct errdiff_map {
1347             int *map;
1348             int width, height, orig;
1349             };
1350              
1351             static struct errdiff_map maps[] =
1352             {
1353             { floyd_map, 3, 2, 1 },
1354             { jarvis_map, 5, 3, 2 },
1355             { stucki_map, 5, 3, 2 },
1356             };
1357              
1358             typedef struct errdiff_tag {
1359             int r, g, b;
1360             } errdiff_t;
1361              
1362             /* perform an error diffusion dither */
1363             static int
1364 5           translate_errdiff(i_quantize *quant, i_img *img, i_palidx *out) {
1365             int *map;
1366             int mapw, maph, mapo;
1367             int i;
1368             errdiff_t *err;
1369             i_img_dim errw;
1370             int difftotal;
1371             i_img_dim x, y, dx, dy;
1372 5           int bst_idx = 0;
1373 5           int is_gray = is_gray_map(quant);
1374 5           CF_VARS;
1375              
1376 5 50         if ((quant->errdiff & ed_mask) == ed_custom) {
1377 0           map = quant->ed_map;
1378 0           mapw = quant->ed_width;
1379 0           maph = quant->ed_height;
1380 0           mapo = quant->ed_orig;
1381             }
1382             else {
1383 5           int index = quant->errdiff & ed_mask;
1384 5 50         if (index >= ed_custom) index = ed_floyd;
1385 5           map = maps[index].map;
1386 5           mapw = maps[index].width;
1387 5           maph = maps[index].height;
1388 5           mapo = maps[index].orig;
1389             }
1390            
1391 5           difftotal = 0;
1392 35 100         for (i = 0; i < maph * mapw; ++i) {
1393 30 50         if (map[i] < 0) {
1394 0           i_push_errorf(0, "errdiff_map values must be non-negative, errdiff[%d] is negative", i);
1395 0           goto fail;
1396             }
1397 30           difftotal += map[i];
1398             }
1399              
1400 5 50         if (!difftotal) {
1401 0           i_push_error(0, "error diffusion map must contain some non-zero values");
1402 0           goto fail;
1403             }
1404              
1405 5           errw = img->xsize+mapw;
1406 5           err = mymalloc(sizeof(*err) * maph * errw);
1407             /*errp = err+mapo;*/
1408 5           memset(err, 0, sizeof(*err) * maph * errw);
1409            
1410             /*printf("map:\n");
1411             for (dy = 0; dy < maph; ++dy) {
1412             for (dx = 0; dx < mapw; ++dx) {
1413             printf("%2d", map[dx+dy*mapw]);
1414             }
1415             putchar('\n');
1416             }*/
1417              
1418 5           CF_SETUP;
1419              
1420 615 100         for (y = 0; y < img->ysize; ++y) {
1421 90710 100         for (x = 0; x < img->xsize; ++x) {
1422             i_color val;
1423             errdiff_t perr;
1424 90100           i_gpix(img, x, y, &val);
1425 90100 50         if (img->channels < 3) {
1426 0           val.channel[1] = val.channel[2] = val.channel[0];
1427             }
1428 90100 100         else if (is_gray) {
1429 100           int gray = 0.5 + color_to_grey(&val);
1430 100           val.channel[0] = val.channel[1] = val.channel[2] = gray;
1431             }
1432 90100           perr = err[x+mapo];
1433 90100 100         perr.r = perr.r < 0 ? -((-perr.r)/difftotal) : perr.r/difftotal;
1434 90100 100         perr.g = perr.g < 0 ? -((-perr.g)/difftotal) : perr.g/difftotal;
1435 90100 100         perr.b = perr.b < 0 ? -((-perr.b)/difftotal) : perr.b/difftotal;
1436             /*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);*/
1437 90100           val.channel[0] = g_sat(val.channel[0]-perr.r);
1438 90100           val.channel[1] = g_sat(val.channel[1]-perr.g);
1439 90100           val.channel[2] = g_sat(val.channel[2]-perr.b);
1440 469450 100         CF_FIND;
    100          
1441             /* save error */
1442 90100           perr.r = quant->mc_colors[bst_idx].channel[0] - val.channel[0];
1443 90100           perr.g = quant->mc_colors[bst_idx].channel[1] - val.channel[1];
1444 90100           perr.b = quant->mc_colors[bst_idx].channel[2] - val.channel[2];
1445             /*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);*/
1446 360400 100         for (dx = 0; dx < mapw; ++dx) {
1447 810900 100         for (dy = 0; dy < maph; ++dy) {
1448 540600           err[x+dx+dy*errw].r += perr.r * map[dx+mapw*dy];
1449 540600           err[x+dx+dy*errw].g += perr.g * map[dx+mapw*dy];
1450 540600           err[x+dx+dy*errw].b += perr.b * map[dx+mapw*dy];
1451             }
1452             }
1453 90100           *out++ = bst_idx;
1454             }
1455             /* shift up the error matrix */
1456 1220 100         for (dy = 0; dy < maph-1; ++dy) {
1457 610           memcpy(err+dy*errw, err+(dy+1)*errw, sizeof(*err)*errw);
1458             }
1459 610           memset(err+(maph-1)*errw, 0, sizeof(*err)*errw);
1460             }
1461 5           CF_CLEANUP;
1462 5           myfree(err);
1463              
1464 5           return 1;
1465              
1466 0           fail:
1467 0           CF_CLEANUP;
1468              
1469 0           return 0;
1470             }
1471             /* Prescan finds the boxes in the image that have the highest number of colors
1472             and that result is used as the initial value for the vectores */
1473              
1474              
1475 0           static void prescan(i_img **imgs,int count, int cnum, cvec *clr, i_sample_t *line) {
1476             int i,k,j;
1477             i_img_dim x,y;
1478             i_sample_t *val;
1479             const int *chans;
1480              
1481             pbox prebox[512];
1482 0 0         for(i=0;i<512;i++) {
1483 0           prebox[i].boxnum=i;
1484 0           prebox[i].pixcnt=0;
1485 0           prebox[i].cand=1;
1486             }
1487              
1488             /* process each image */
1489 0 0         for (i = 0; i < count; ++i) {
1490 0           i_img *im = imgs[i];
1491 0 0         chans = im->channels >= 3 ? NULL : gray_samples;
1492 0 0         for(y=0;yysize;y++) {
1493 0           i_gsamp(im, 0, im->xsize, y, line, chans, 3);
1494 0           val = line;
1495 0 0         for(x=0;xxsize;x++) {
1496 0           prebox[pixbox_ch(val)].pixcnt++;
1497             }
1498             }
1499             }
1500              
1501 0 0         for(i=0;i<512;i++) prebox[i].pdc=prebox[i].pixcnt;
1502 0           qsort(prebox,512,sizeof(pbox),(cmpfunc)pboxcmp);
1503              
1504 0 0         for(i=0;i
1505             /* printf("Color %d\n",i);
1506             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); }
1507             printf("\n\n"); */
1508 0           reorder(prebox);
1509             }
1510            
1511             /* for(k=0;k
1512            
1513 0           k=0;
1514 0           j=1;
1515 0           i=0;
1516 0 0         while(i
1517             /* printf("prebox[%d].cand=%d\n",k,prebox[k].cand); */
1518 0 0         if (clr[i].fixed) { i++; continue; } /* reserved go to next */
1519 0 0         if (j>=prebox[k].cand) { k++; j=1; } else {
1520 0 0         if (prebox[k].cand == 2) boxcenter(prebox[k].boxnum,&(clr[i]));
1521 0           else boxrand(prebox[k].boxnum,&(clr[i]));
1522             /* 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); */
1523 0           j++;
1524 0           i++;
1525             }
1526             }
1527 0           }
1528            
1529              
1530 0           static void reorder(pbox prescan[512]) {
1531             int nidx;
1532             pbox c;
1533              
1534 0           nidx=0;
1535 0           c=prescan[0];
1536            
1537 0           c.cand++;
1538 0           c.pdc=c.pixcnt/(c.cand*c.cand);
1539             /* c.pdc=c.pixcnt/c.cand; */
1540 0 0         while(nidx < 511 && c.pdc < prescan[nidx+1].pdc) {
    0          
1541 0           prescan[nidx]=prescan[nidx+1];
1542 0           nidx++;
1543             }
1544 0           prescan[nidx]=c;
1545 0           }
1546              
1547             static int
1548 0           pboxcmp(const pbox *a,const pbox *b) {
1549 0 0         if (a->pixcnt > b->pixcnt) return -1;
1550 0 0         if (a->pixcnt < b->pixcnt) return 1;
1551 0           return 0;
1552             }
1553              
1554             static void
1555 0           boxcenter(int box,cvec *cv) {
1556 0           cv->r=15+((box&448)>>1);
1557 0           cv->g=15+((box&56)<<2);
1558 0           cv->b=15+((box&7)<<5);
1559 0           }
1560              
1561             static void
1562 0           bbox(int box,int *r0,int *r1,int *g0,int *g1,int *b0,int *b1) {
1563 0           *r0=(box&448)>>1;
1564 0           *r1=(*r0)|31;
1565 0           *g0=(box&56)<<2;
1566 0           *g1=(*g0)|31;
1567 0           *b0=(box&7)<<5;
1568 0           *b1=(*b0)|31;
1569 0           }
1570              
1571             static void
1572 0           boxrand(int box,cvec *cv) {
1573 0           cv->r=6+(rand()%25)+((box&448)>>1);
1574 0           cv->g=6+(rand()%25)+((box&56)<<2);
1575 0           cv->b=6+(rand()%25)+((box&7)<<5);
1576 0           }
1577              
1578             static float
1579 0           frandn(void) {
1580              
1581             float u1,u2,w;
1582            
1583 0           w=1;
1584            
1585 0 0         while (w >= 1 || w == 0) {
    0          
1586 0           u1 = 2 * frand() - 1;
1587 0           u2 = 2 * frand() - 1;
1588 0           w = u1*u1 + u2*u2;
1589             }
1590            
1591 0           w = sqrt((-2*log(w))/w);
1592 0           return u1*w;
1593             }
1594              
1595             /* Create hash index */
1596             static
1597             void
1598 0           cr_hashindex(cvec clr[256],int cnum,hashbox hb[512]) {
1599            
1600             int bx,mind,cd,cumcnt,i;
1601             /* printf("indexing... \n");*/
1602            
1603 0           cumcnt=0;
1604 0 0         for(bx=0; bx<512; bx++) {
1605 0           mind=196608;
1606 0 0         for(i=0; i
1607 0           cd = maxdist(bx,&clr[i]);
1608 0 0         if (cd < mind) { mind=cd; }
1609             }
1610            
1611 0           hb[bx].cnt=0;
1612 0 0         for(i=0;i
    0          
1613             /*printf("box %d -> approx -> %d\n",bx,hb[bx].cnt); */
1614             /* statbox(bx,cnum,clr); */
1615 0           cumcnt+=hb[bx].cnt;
1616             }
1617            
1618             /* printf("Average search space: %d\n",cumcnt/512); */
1619 0           }
1620              
1621             static int
1622 0           maxdist(int boxnum,cvec *cv) {
1623             int r0,r1,g0,g1,b0,b1;
1624             int r,g,b,mr,mg,mb;
1625              
1626 0           r=cv->r;
1627 0           g=cv->g;
1628 0           b=cv->b;
1629            
1630 0           bbox(boxnum,&r0,&r1,&g0,&g1,&b0,&b1);
1631              
1632 0           mr=i_max(abs(b-b0),abs(b-b1));
1633 0           mg=i_max(abs(g-g0),abs(g-g1));
1634 0           mb=i_max(abs(r-r0),abs(r-r1));
1635            
1636 0           return PWR2(mr)+PWR2(mg)+PWR2(mb);
1637             }
1638              
1639             static int
1640 0           mindist(int boxnum,cvec *cv) {
1641             int r0,r1,g0,g1,b0,b1;
1642             int r,g,b,mr,mg,mb;
1643              
1644 0           r=cv->r;
1645 0           g=cv->g;
1646 0           b=cv->b;
1647            
1648 0           bbox(boxnum,&r0,&r1,&g0,&g1,&b0,&b1);
1649              
1650             /* printf("box %d, (%d,%d,%d)-(%d,%d,%d) vec (%d,%d,%d) ",boxnum,r0,g0,b0,r1,g1,b1,r,g,b); */
1651              
1652 0 0         if (r0<=r && r<=r1 && g0<=g && g<=g1 && b0<=b && b<=b1) return 0;
    0          
    0          
    0          
    0          
    0          
1653              
1654 0           mr=i_min(abs(b-b0),abs(b-b1));
1655 0           mg=i_min(abs(g-g0),abs(g-g1));
1656 0           mb=i_min(abs(r-r0),abs(r-r1));
1657            
1658 0           mr=PWR2(mr);
1659 0           mg=PWR2(mg);
1660 0           mb=PWR2(mb);
1661              
1662 0 0         if (r0<=r && r<=r1 && g0<=g && g<=g1) return mb;
    0          
    0          
    0          
1663 0 0         if (r0<=r && r<=r1 && b0<=b && b<=b1) return mg;
    0          
    0          
    0          
1664 0 0         if (b0<=b && b<=b1 && g0<=g && g<=g1) return mr;
    0          
    0          
    0          
1665              
1666 0 0         if (r0<=r && r<=r1) return mg+mb;
    0          
1667 0 0         if (g0<=g && g<=g1) return mr+mb;
    0          
1668 0 0         if (b0<=b && b<=b1) return mg+mr;
    0          
1669              
1670 0           return mr+mg+mb;
1671             }
1672              
1673             static void transparent_threshold(i_quantize *, i_palidx *, i_img *, i_palidx);
1674             static void transparent_errdiff(i_quantize *, i_palidx *, i_img *, i_palidx);
1675             static void transparent_ordered(i_quantize *, i_palidx *, i_img *, i_palidx);
1676              
1677             /*
1678             =item i_quant_transparent(C, C, C, C)
1679              
1680             =category Image quantization
1681              
1682             Dither the alpha channel on C into the palette indexes in
1683             C. Pixels to be transparent are replaced with C.
1684              
1685             The method used depends on the tr_* members of C.
1686              
1687             =cut
1688             */
1689              
1690             void
1691 0           i_quant_transparent(i_quantize *quant, i_palidx *data, i_img *img,
1692             i_palidx trans_index)
1693             {
1694 0           switch (quant->transp) {
1695 0           case tr_none:
1696 0           break;
1697            
1698 0           default:
1699 0           quant->tr_threshold = 128;
1700             /* fall through */
1701 0           case tr_threshold:
1702 0           transparent_threshold(quant, data, img, trans_index);
1703 0           break;
1704            
1705 0           case tr_errdiff:
1706 0           transparent_errdiff(quant, data, img, trans_index);
1707 0           break;
1708              
1709 0           case tr_ordered:
1710 0           transparent_ordered(quant, data, img, trans_index);
1711 0           break;
1712             }
1713 0           }
1714              
1715             static void
1716 0           transparent_threshold(i_quantize *quant, i_palidx *data, i_img *img,
1717             i_palidx trans_index)
1718             {
1719             i_img_dim x, y;
1720 0           i_sample_t *line = mymalloc(img->xsize * sizeof(i_sample_t));
1721 0 0         int trans_chan = img->channels > 2 ? 3 : 1;
1722            
1723 0 0         for (y = 0; y < img->ysize; ++y) {
1724 0           i_gsamp(img, 0, img->xsize, y, line, &trans_chan, 1);
1725 0 0         for (x = 0; x < img->xsize; ++x) {
1726 0 0         if (line[x] < quant->tr_threshold)
1727 0           data[y*img->xsize+x] = trans_index;
1728             }
1729             }
1730 0           myfree(line);
1731 0           }
1732              
1733             static void
1734 0           transparent_errdiff(i_quantize *quant, i_palidx *data, i_img *img,
1735             i_palidx trans_index)
1736             {
1737             int *map;
1738             int index;
1739             int mapw, maph, mapo;
1740             int errw, *err, *errp;
1741             int difftotal, out, error;
1742             i_img_dim x, y, dx, dy;
1743             int i;
1744             i_sample_t *line;
1745 0 0         int trans_chan = img->channels > 2 ? 3 : 1;
1746              
1747             /* no custom map for transparency (yet) */
1748 0           index = quant->tr_errdiff & ed_mask;
1749 0 0         if (index >= ed_custom) index = ed_floyd;
1750 0           map = maps[index].map;
1751 0           mapw = maps[index].width;
1752 0           maph = maps[index].height;
1753 0           mapo = maps[index].orig;
1754              
1755 0           errw = img->xsize+mapw-1;
1756 0           err = mymalloc(sizeof(*err) * maph * errw);
1757 0           errp = err+mapo;
1758 0           memset(err, 0, sizeof(*err) * maph * errw);
1759              
1760 0           line = mymalloc(img->xsize * sizeof(i_sample_t));
1761 0           difftotal = 0;
1762 0 0         for (i = 0; i < maph * mapw; ++i)
1763 0           difftotal += map[i];
1764 0 0         for (y = 0; y < img->ysize; ++y) {
1765 0           i_gsamp(img, 0, img->xsize, y, line, &trans_chan, 1);
1766 0 0         for (x = 0; x < img->xsize; ++x) {
1767 0           line[x] = g_sat(line[x]-errp[x]/difftotal);
1768 0 0         if (line[x] < 128) {
1769 0           out = 0;
1770 0           data[y*img->xsize+x] = trans_index;
1771             }
1772             else {
1773 0           out = 255;
1774             }
1775 0           error = out - line[x];
1776 0 0         for (dx = 0; dx < mapw; ++dx) {
1777 0 0         for (dy = 0; dy < maph; ++dy) {
1778 0           errp[x+dx-mapo+dy*errw] += error * map[dx+mapw*dy];
1779             }
1780             }
1781             }
1782             /* shift up the error matrix */
1783 0 0         for (dy = 0; dy < maph-1; ++dy)
1784 0           memcpy(err+dy*errw, err+(dy+1)*errw, sizeof(*err)*errw);
1785 0           memset(err+(maph-1)*errw, 0, sizeof(*err)*errw);
1786             }
1787 0           myfree(err);
1788 0           myfree(line);
1789 0           }
1790              
1791             /* builtin ordered dither maps */
1792             static unsigned char
1793             orddith_maps[][64] =
1794             {
1795             { /* random
1796             this is purely random - it's pretty awful
1797             */
1798             48, 72, 196, 252, 180, 92, 108, 52,
1799             228, 176, 64, 8, 236, 40, 20, 164,
1800             120, 128, 84, 116, 24, 28, 172, 220,
1801             68, 0, 188, 124, 184, 224, 192, 104,
1802             132, 100, 240, 200, 152, 160, 244, 44,
1803             96, 204, 144, 16, 140, 56, 232, 216,
1804             208, 4, 76, 212, 136, 248, 80, 168,
1805             156, 88, 32, 112, 148, 12, 36, 60,
1806             },
1807             {
1808             /* dot8
1809             perl spot.perl '($x-3.5)*($x-3.5)+($y-3.5)*($y-3.5)'
1810             */
1811             240, 232, 200, 136, 140, 192, 228, 248,
1812             220, 148, 100, 76, 80, 104, 152, 212,
1813             180, 116, 56, 32, 36, 60, 120, 176,
1814             156, 64, 28, 0, 8, 44, 88, 160,
1815             128, 92, 24, 12, 4, 40, 68, 132,
1816             184, 96, 48, 20, 16, 52, 108, 188,
1817             216, 144, 112, 72, 84, 124, 164, 224,
1818             244, 236, 196, 168, 172, 204, 208, 252,
1819             },
1820             { /* dot4
1821             perl spot.perl \
1822             'min(dist(1.5, 1.5),dist(5.5,1.5),dist(1.5,5.5),dist(5.5,5.5))'
1823             */
1824             196, 72, 104, 220, 200, 80, 112, 224,
1825             76, 4, 24, 136, 84, 8, 32, 144,
1826             108, 28, 52, 168, 116, 36, 56, 176,
1827             216, 140, 172, 244, 228, 148, 180, 248,
1828             204, 92, 124, 236, 192, 68, 96, 208,
1829             88, 12, 44, 156, 64, 0, 16, 128,
1830             120, 40, 60, 188, 100, 20, 48, 160,
1831             232, 152, 184, 252, 212, 132, 164, 240,
1832             },
1833             { /* hline
1834             perl spot.perl '$y-3'
1835             */
1836             160, 164, 168, 172, 176, 180, 184, 188,
1837             128, 132, 136, 140, 144, 148, 152, 156,
1838             32, 36, 40, 44, 48, 52, 56, 60,
1839             0, 4, 8, 12, 16, 20, 24, 28,
1840             64, 68, 72, 76, 80, 84, 88, 92,
1841             96, 100, 104, 108, 112, 116, 120, 124,
1842             192, 196, 200, 204, 208, 212, 216, 220,
1843             224, 228, 232, 236, 240, 244, 248, 252,
1844             },
1845             { /* vline
1846             perl spot.perl '$x-3'
1847             */
1848             180, 100, 40, 12, 44, 104, 184, 232,
1849             204, 148, 60, 16, 64, 128, 208, 224,
1850             212, 144, 76, 8, 80, 132, 216, 244,
1851             160, 112, 68, 20, 84, 108, 172, 236,
1852             176, 96, 72, 28, 88, 152, 188, 228,
1853             200, 124, 92, 0, 32, 116, 164, 240,
1854             168, 120, 36, 24, 48, 136, 192, 248,
1855             196, 140, 52, 4, 56, 156, 220, 252,
1856             },
1857             { /* slashline
1858             perl spot.perl '$y+$x-7'
1859             */
1860             248, 232, 224, 192, 140, 92, 52, 28,
1861             240, 220, 196, 144, 108, 60, 12, 64,
1862             216, 180, 148, 116, 76, 20, 80, 128,
1863             204, 152, 104, 44, 16, 72, 100, 160,
1864             164, 96, 68, 24, 56, 112, 168, 176,
1865             124, 40, 8, 36, 88, 136, 184, 212,
1866             84, 4, 32, 120, 156, 188, 228, 236,
1867             0, 48, 132, 172, 200, 208, 244, 252,
1868             },
1869             { /* backline
1870             perl spot.perl '$y-$x'
1871             */
1872             0, 32, 116, 172, 184, 216, 236, 252,
1873             56, 8, 72, 132, 136, 200, 228, 240,
1874             100, 36, 12, 40, 92, 144, 204, 220,
1875             168, 120, 60, 16, 44, 96, 156, 176,
1876             180, 164, 112, 48, 28, 52, 128, 148,
1877             208, 192, 152, 88, 84, 20, 64, 104,
1878             232, 224, 196, 140, 108, 68, 24, 76,
1879             248, 244, 212, 188, 160, 124, 80, 4,
1880             },
1881             {
1882             /* tiny
1883             good for display, bad for print
1884             hand generated
1885             */
1886             0, 128, 32, 192, 8, 136, 40, 200,
1887             224, 64, 160, 112, 232, 72, 168, 120,
1888             48, 144, 16, 208, 56, 152, 24, 216,
1889             176, 96, 240, 80, 184, 104, 248, 88,
1890             12, 140, 44, 204, 4, 132, 36, 196,
1891             236, 76, 172, 124, 228, 68, 164, 116,
1892             60, 156, 28, 220, 52, 148, 20, 212,
1893             188, 108, 252, 92, 180, 100, 244, 84,
1894             },
1895             };
1896              
1897             static void
1898 0           transparent_ordered(i_quantize *quant, i_palidx *data, i_img *img,
1899             i_palidx trans_index)
1900             {
1901             unsigned char *spot;
1902             i_img_dim x, y;
1903             i_sample_t *line;
1904 0 0         int trans_chan = img->channels > 2 ? 3 : 1;
1905 0 0         if (quant->tr_orddith == od_custom)
1906 0           spot = quant->tr_custom;
1907             else
1908 0           spot = orddith_maps[quant->tr_orddith];
1909              
1910 0           line = mymalloc(img->xsize * sizeof(i_sample_t));
1911 0 0         for (y = 0; y < img->ysize; ++y) {
1912 0           i_gsamp(img, 0, img->xsize, y, line, &trans_chan, 1);
1913 0 0         for (x = 0; x < img->xsize; ++x) {
1914 0 0         if (line[x] < spot[(x&7)+(y&7)*8])
1915 0           data[x+y*img->xsize] = trans_index;
1916             }
1917             }
1918 0           myfree(line);
1919 0           }
1920