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