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