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