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