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