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