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