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
7 static void makemap_addi(i_quantize *, i_img **imgs, int count);
11 setcol(i_color *cl,unsigned char r,unsigned char g,unsigned char b,unsigned char a) {
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.
24 This means we don't need any special processing at this level to
25 handle multiple colour maps.
29 quant_makemap(i_quantize *quant, i_img **imgs, int count) {
31 /* giflib does it's own color table generation */
32 if (quant->translate == pt_giflib)
35 switch (quant->make_colors & mc_mask) {
37 /* use user's specified map */
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);
53 makemap_addi(quant, imgs, count);
59 static void translate_giflib(i_quantize *, i_img *, i_palidx *);
61 static void translate_closest(i_quantize *, i_img *, i_palidx *);
62 static void translate_errdiff(i_quantize *, i_img *, i_palidx *);
63 static void translate_addi(i_quantize *, i_img *, i_palidx *);
65 /* Quantize the image given the palette in quant.
67 The giflib quantizer ignores the palette.
69 i_palidx *quant_translate(i_quantize *quant, i_img *img) {
71 mm_log((1, "quant_translate(quant %p, img %p)\n", quant, img));
73 result = mymalloc(img->xsize * img->ysize);
75 switch (quant->translate) {
78 translate_giflib(quant, img, result);
83 translate_closest(quant, img, result);
87 translate_errdiff(quant, img, result);
92 translate_addi(quant, img, result);
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; }
107 quant_replicate(i_img *im, i_palidx *output, i_quantize *quant);
109 /* Use the gif_lib quantization functions to quantize the image */
110 static void translate_giflib(i_quantize *quant, i_img *img, i_palidx *out) {
111 int x,y,ColorMapSize,colours_in;
115 GifByteType *RedBuffer = NULL, *GreenBuffer = NULL, *BlueBuffer = NULL;
116 GifByteType *RedP, *GreenP, *BlueP;
117 ColorMapObject *OutputColorMap = NULL;
121 mm_log((1,"i_writegif(quant %p, img %p, out %p)\n", quant, img, out));
123 /*if (!(im->channels==1 || im->channels==3)) { fprintf(stderr,"Unable to write gif, improper colorspace.\n"); exit(3); }*/
125 ColorMapSize = quant->mc_size;
127 Size = ((long) img->xsize) * img->ysize * sizeof(GifByteType);
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.");*/
135 /* ******************************************************* */
136 /* count the number of colours in the image */
137 colours_in=i_count_colors(img, OutputColorMap->ColorCount);
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 */
148 mm_log((2,"image has %d colours, more then %d. Quantizing\n",colours_in,ColorMapSize));
150 if (img->channels >= 3) {
151 if ((RedBuffer = (GifByteType *) mymalloc((unsigned int) Size)) == NULL) {
152 m_fatal(0,"Failed to allocate memory required, aborted.");
155 if ((GreenBuffer = (GifByteType *) mymalloc((unsigned int) Size)) == NULL) {
156 m_fatal(0,"Failed to allocate memory required, aborted.");
161 if ((BlueBuffer = (GifByteType *) mymalloc((unsigned int) Size)) == NULL) {
162 m_fatal(0,"Failed to allocate memory required, aborted.");
169 GreenP = GreenBuffer;
172 for (y=0; y< img->ysize; y++) for (x=0; x < img->xsize; x++) {
173 i_gpix(img,x,y,&col);
175 *GreenP++ = col.rgb.g;
176 *BlueP++ = col.rgb.b;
181 if ((RedBuffer = (GifByteType *) mymalloc((unsigned int) Size))==NULL) {
182 m_fatal(0,"Failed to allocate memory required, aborted.");
186 GreenBuffer=BlueBuffer=RedBuffer;
188 for (y=0; y< img->ysize; y++) for (x=0; x < img->xsize; x++) {
189 i_gpix(img,x,y,&col);
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"));
201 if (img->channels == 3) { myfree(GreenBuffer); myfree(BlueBuffer); }
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;
209 quant->mc_count = ColorMapSize;
214 quant_replicate(i_img *im, GifByteType *output, i_quantize *quant) {
215 int x, y, alloced, r, g=0, b=0, idx ;
219 for(y=0; y<im->ysize; y++) {
220 for(x=0; x<im->xsize; x++) {
222 GET_RGB(im, x,y, r,g,b, col);
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) {
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",
239 quant->mc_colors[idx].rgb.r=r;
240 quant->mc_colors[idx].rgb.g=g;
241 quant->mc_colors[idx].rgb.b=b;
243 *output=idx; /* fill output buffer */
244 output++; /* with colour indexes */
247 quant->mc_count = alloced;
253 static void translate_closest(i_quantize *quant, i_img *img, i_palidx *out) {
255 translate_addi(quant, img, out);
258 #define PWR2(x) ((x)*(x))
260 typedef int (*cmpfunc)(const void*, const void*);
283 static void prescan(i_img **im,int count, int cnum, cvec *clr);
284 static void reorder(pbox prescan[512]);
285 static int pboxcmp(const pbox *a,const pbox *b);
286 static void boxcenter(int box,cvec *cv);
287 static float frandn(void);
288 static void boxrand(int box,cvec *cv);
289 static void bbox(int box,int *r0,int *r1,int *g0,int *g1,int *b0,int *b1);
290 static void cr_hashindex(cvec clr[256],int cnum,hashbox hb[512]);
291 static int mindist(int boxnum,cvec *cv);
292 static int maxdist(int boxnum,cvec *cv);
294 /* Some of the simpler functions are kept here to aid the compiler -
295 maybe some of them will be inlined. */
298 pixbox(i_color *ic) { return ((ic->channel[0] & 224)<<1)+ ((ic->channel[1]&224)>>2) + ((ic->channel[2] &224) >> 5); }
302 if (in>255) { return 255; }
303 else if (in>0) return in;
310 return rand()/(RAND_MAX+1.0);
315 eucl_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]); }
319 ceucl_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]); }
323 This quantization algorithm and implementation routines are by Arnar
324 M. Hrafnkelson. In case any new ideas are here they are mine since
325 this was written from scratch.
327 The algorithm uses local means in the following way:
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.
334 In order to speed this process up (i.e. nearest neighbor problem) We
335 divied the r,g,b space up in equally large 512 boxes. The boxes are
336 numbered from 0 to 511. Their numbering is so that for a given vector
337 it is known that it belongs to the box who is formed by concatenating the
338 3 most significant bits from each component of the RGB triplet.
340 For each box we find the list of points from the colormap who might be
341 closest to any given point within the box. The exact solution
342 involves finding the Voronoi map (or the dual the Delauny
343 triangulation) and has many issues including numerical stability.
345 So we use this approximation:
347 1. Find which point has the shortest maximum distance to the box.
348 2. Find all points that have a shorter minimum distance than that to the box
350 This is a very simple task and is not computationally heavy if one
351 takes into account that the minimum distances from a pixel to a box is
352 always found by checking if it's inside the box or is closest to some
353 side or a corner. Finding the maximum distance is also either a side
356 This approach results 2-3 times more than the actual points needed but
357 is still a good gain over the complete space. Usually when one has a
358 256 Colorcolor map a search over 30 is often obtained.
360 A bit of an enhancement to this approach is to keep a seperate list
361 for each side of the cube, but this will require even more memory.
363 Arnar M. Hrafnkelsson (addi@umich.edu);
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>.
374 makemap_addi(i_quantize *quant, i_img **imgs, int count) {
376 int cnum, i, x, y, bst_idx=0, ld, cd, iter, currhb, img_num;
381 clr = (cvec *)mymalloc(sizeof(cvec) * quant->mc_size);
382 for (i=0; i < quant->mc_count; ++i) {
383 clr[i].r = quant->mc_colors[i].rgb.r;
384 clr[i].g = quant->mc_colors[i].rgb.g;
385 clr[i].b = quant->mc_colors[i].rgb.b;
389 /* mymalloc doesn't clear memory, so I think we need this */
390 for (; i < quant->mc_size; ++i) {
394 cnum = quant->mc_size;
397 prescan(imgs, count, cnum, clr);
398 cr_hashindex(clr, cnum, hb);
400 for(iter=0;iter<3;iter++) {
403 for (img_num = 0; img_num < count; ++img_num) {
404 i_img *im = imgs[img_num];
405 for(y=0;y<im->ysize;y++) for(x=0;x<im->xsize;x++) {
409 /* printf("box = %d \n",currhb); */
410 for(i=0;i<hb[currhb].cnt;i++) {
411 /* 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 cd=eucl_d(&clr[hb[currhb].vec[i]],&val);
415 ld=cd; /* shortest distance yet */
416 bst_idx=hb[currhb].vec[i]; /* index of closest vector yet */
420 clr[bst_idx].mcount++;
422 clr[bst_idx].dr+=val.channel[0];
423 clr[bst_idx].dg+=val.channel[1];
424 clr[bst_idx].db+=val.channel[2];
427 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 /* for(i=0;i<cnum;i++) printf("vec(%d)=(%d,%d,%d) dest=(%d,%d,%d) matchcount=%d\n",
430 i,clr[i].r,clr[i].g,clr[i].b,clr[i].dr,clr[i].dg,clr[i].db,clr[i].mcount); */
432 /* printf("total error: %.2f\n",sqrt(accerr)); */
434 for(i=0;i<cnum;i++) {
435 if (clr[i].fixed) continue; /* skip reserved colors */
439 clr[i].r=clr[i].r*(1-dlt)+dlt*clr[i].dr;
440 clr[i].g=clr[i].g*(1-dlt)+dlt*clr[i].dg;
441 clr[i].b=clr[i].b*(1-dlt)+dlt*clr[i].db;
443 /* let's try something else */
455 cr_hashindex(clr,cnum,hb);
460 for(i=0;i<cnum;i++) {
461 cd=eucl_d(&clr[i],&val);
469 /* if defined, we only include colours with an mcount or that were
470 supplied in the fixed palette, giving us a smaller output palette */
471 #define ONLY_USE_USED
473 /* transfer the colors back */
475 for (i = 0; i < cnum; ++i) {
476 if (clr[i].fixed || clr[i].used) {
477 /*printf("Adding %d (%d,%d,%d)\n", i, clr[i].r, clr[i].g, clr[i].b);*/
478 quant->mc_colors[quant->mc_count].rgb.r = clr[i].r;
479 quant->mc_colors[quant->mc_count].rgb.g = clr[i].g;
480 quant->mc_colors[quant->mc_count].rgb.b = clr[i].b;
485 /* transfer the colors back */
486 for (i = 0; i < cnum; ++i) {
487 quant->mc_colors[i].rgb.r = clr[i].r;
488 quant->mc_colors[i].rgb.g = clr[i].g;
489 quant->mc_colors[i].rgb.b = clr[i].b;
491 quant->mc_count = cnum;
494 /* don't want to keep this */
500 /* Define one of the following 4 symbols to choose a colour search method
501 The idea is to try these out, including benchmarking, to see which
502 is fastest in a good spread of circumstances.
503 I'd expect IM_CFLINSEARCH to be fastest for very small palettes, and
504 IM_CFHASHBOX for large images with large palettes.
506 Some other possibilities include:
507 - search over entries sorted by luminance
509 Initially I was planning on testing using the macros and then
510 integrating the code directly into each function, but this means if
511 we find a bug at a late stage we will need to update N copies of
512 the same code. Also, keeping the code in the macros means that the
513 code in the translation functions is much more to the point,
514 there's no distracting colour search code to remove attention from
515 what makes _this_ translation function different. It may be
516 advisable to move the setup code into functions at some point, but
517 it should be possible to do this fairly transparently.
519 If IM_CF_COPTS is defined then CFLAGS must have an appropriate
522 Each option needs to define 4 macros:
523 CF_VARS - variables to define in the function
524 CF_SETUP - code to setup for the colour search, eg. allocating and
525 initializing lookup tables
526 CF_FIND - code that looks for the color in val and puts the best
527 matching index in bst_idx
528 CF_CLEANUP - code to clean up, eg. releasing memory
531 /*#define IM_CFLINSEARCH*/
533 /*#define IM_CFSORTCHAN*/
534 /*#define IM_CFRAND2DIST*/
539 /* The original version I wrote for this used the sort.
540 If this is defined then we use a sort to extract the indices for
544 /* assume i is available */
545 #define CF_VARS hashbox hb[512]; \
551 static long *gdists; /* qsort is annoying */
552 /* int might be smaller than long, so we need to do a real compare
553 rather than a subtraction*/
554 static int distcomp(void const *a, void const *b) {
555 long ra = gdists[*(int const *)a];
556 long rb = gdists[*(int const *)b];
567 /* for each hashbox build a list of colours that are in the hb or is closer
569 This is pretty involved. The original gifquant generated the hashbox
570 as part of it's normal processing, but since the map generation is now
571 separated from the translation we need to do this on the spot.
572 Any optimizations, even if they don't produce perfect results would be
575 static void hbsetup(i_quantize *quant, hashbox *hb) {
576 long *dists, mind, maxd, cd;
577 int cr, cb, cg, hbnum, i;
580 int *indices = mymalloc(quant->mc_count * sizeof(int));
583 dists = mymalloc(quant->mc_count * sizeof(long));
584 for (cr = 0; cr < 8; ++cr) {
585 for (cg = 0; cg < 8; ++cg) {
586 for (cb = 0; cb < 8; ++cb) {
587 /* centre of the hashbox */
588 cenc.channel[0] = cr*pboxjump+pboxjump/2;
589 cenc.channel[1] = cg*pboxjump+pboxjump/2;
590 cenc.channel[2] = cb*pboxjump+pboxjump/2;
591 hbnum = pixbox(&cenc);
593 /* order indices in the order of distance from the hashbox */
594 for (i = 0; i < quant->mc_count; ++i) {
598 dists[i] = ceucl_d(&cenc, quant->mc_colors+i);
601 /* it should be possible to do this without a sort
602 but so far I'm too lazy */
604 qsort(indices, quant->mc_count, sizeof(int), distcomp);
605 /* any colors that can match are within mind+diagonal size of
607 mind = dists[indices[0]];
609 maxd = (sqrt(mind)+pboxjump)*(sqrt(mind)+pboxjump);
610 while (i < quant->mc_count && dists[indices[i]] < maxd) {
611 hb[hbnum].vec[hb[hbnum].cnt++] = indices[i++];
614 /* work out the minimum */
616 for (i = 0; i < quant->mc_count; ++i) {
617 if (dists[i] < mind) mind = dists[i];
619 /* transfer any colours that might be closest to a colour in
621 maxd = (sqrt(mind)+pboxjump)*(sqrt(mind)+pboxjump);
622 for (i = 0; i < quant->mc_count; ++i) {
624 hb[hbnum].vec[hb[hbnum].cnt++] = i;
635 #define CF_SETUP hbsetup(quant, hb)
638 currhb = pixbox(&val); \
640 for (i = 0; i < hb[currhb].cnt; ++i) { \
641 cd = ceucl_d(quant->mc_colors+hb[currhb].vec[i], &val); \
642 if (cd < ld) { ld = cd; bst_idx = hb[currhb].vec[i]; } \
649 #ifdef IM_CFLINSEARCH
650 /* as simple as it gets */
651 #define CF_VARS long ld, cd
652 #define CF_SETUP /* none needed */
655 for (i = 0; i < quant->mc_count; ++i) { \
656 cd = ceucl_d(quant->mc_colors+i, &val); \
657 if (cd < ld) { ld = cd; bst_idx = i; } \
663 static int gsortchan;
664 static i_quantize *gquant;
665 static int chansort(void const *a, void const *b) {
666 return gquant->mc_colors[*(int const *)a].channel[gsortchan] -
667 gquant->mc_colors[*(int const *)b].channel[gsortchan];
669 #define CF_VARS int *indices, sortchan, diff; \
671 int vindex[256] /* where to find value i of chan */
673 static void chansetup(i_img *img, i_quantize *quant, int *csortchan,
674 int *vindex, int **cindices) {
675 int *indices, sortchan, chan, i, chval;
676 int chanmins[MAXCHANNELS], chanmaxs[MAXCHANNELS], maxrange;
678 /* find the channel with the maximum range */
679 /* the maximum stddev would probably be better */
680 for (chan = 0; chan < img->channels; ++chan) {
681 chanmins[chan] = 256; chanmaxs[chan] = 0;
682 for (i = 0; i < quant->mc_count; ++i) {
683 if (quant->mc_colors[i].channel[chan] < chanmins[chan])
684 chanmins[chan] = quant->mc_colors[i].channel[chan];
685 if (quant->mc_colors[i].channel[chan] > chanmaxs[chan])
686 chanmaxs[chan] = quant->mc_colors[i].channel[chan];
690 for (chan = 0; chan < img->channels; ++chan) {
691 if (chanmaxs[chan]-chanmins[chan] > maxrange) {
692 maxrange = chanmaxs[chan]-chanmins[chan];
696 indices = mymalloc(quant->mc_count * sizeof(int)) ;
697 for (i = 0; i < quant->mc_count; ++i) {
700 gsortchan = sortchan;
702 qsort(indices, quant->mc_count, sizeof(int), chansort) ;
703 /* now a lookup table to find entries faster */
704 for (chval=0, i=0; i < quant->mc_count; ++i) {
705 while (chval < 256 &&
706 chval < quant->mc_colors[indices[i]].channel[sortchan]) {
710 while (chval < 256) {
711 vindex[chval++] = quant->mc_count-1;
713 *csortchan = sortchan;
718 chansetup(img, quant, &sortchan, vindex, &indices)
720 int chanfind(i_color val, i_quantize *quant, int *indices, int *vindex,
722 int i, bst_idx, diff, maxdiff;
725 i = vindex[val.channel[sortchan]];
726 bst_idx = indices[i];
729 maxdiff = quant->mc_count;
730 while (diff < maxdiff) {
731 if (i+diff < quant->mc_count) {
732 cd = ceucl_d(&val, quant->mc_colors+indices[i+diff]);
734 bst_idx = indices[i+diff];
740 cd = ceucl_d(&val, quant->mc_colors+indices[i-diff]);
742 bst_idx = indices[i-diff];
754 bst_idx = chanfind(val, quant, indices, vindex, sortchan)
757 #define CF_CLEANUP myfree(indices)
761 #ifdef IM_CFRAND2DIST
763 /* This is based on a method described by Addi in the #imager channel
764 on the 28/2/2001. I was about 1am Sydney time at the time, so I
765 wasn't at my most cogent. Well, that's my excuse :)
767 <TonyC> what I have at the moment is: hashboxes, with optimum hash box
768 filling; simple linear search; and a lookup in the widest channel
769 (currently the channel with the maximum range)
770 <Addi> There is one more way that might be simple to implement.
771 <Addi> You want to hear?
773 <purl> somebody said that was not true
774 <Addi> For each of the colors in the palette start by creating a
775 sorted list of the form:
776 <Addi> [distance, color]
777 <Addi> Where they are sorted by distance.
778 <TonyC> distance to where?
779 <Addi> Where the elements in the lists are the distances and colors of
780 the other colors in the palette
782 <Addi> So if you are at color 0
783 <Addi> ok - now to search for the closest color when you are creating
784 the final image is done like this:
785 <Addi> a) pick a random color from the palette
786 <Addi> b) calculate the distance to it
787 <Addi> c) only check the vectors that are within double the distance
788 in the list of the color you picked from the palette.
789 <Addi> Does that seem logical?
790 <Addi> Lets imagine that we only have grayscale to make an example:
791 <Addi> Our palette has 1 4 10 20 as colors.
792 <Addi> And we want to quantize the color 11
793 <Addi> lets say we picked 10 randomly
794 <Addi> the double distance is 2
795 <Addi> since abs(10-11)*2 is 2
796 <Addi> And the list at vector 10 is this:
797 <Addi> [0, 10], [6 4], [9, 1], [10, 20]
798 <Addi> so we look at the first one (but not the second one since 6 is
799 at a greater distance than 2.
800 <Addi> Any of that make sense?
801 <TonyC> yes, though are you suggesting another random jump to one of
802 the colours with the possible choices? or an exhaustive search?
803 <Addi> TonyC: It's possible to come up with a recursive/iterative
804 enhancement but this is the 'basic' version.
805 <Addi> Which would do an iterative search.
806 <Addi> You can come up with conditions where it pays to switch to a new one.
807 <Addi> And the 'random' start can be switched over to a small tree.
808 <Addi> So you would have a little index at the start.
809 <Addi> to get you into the general direction
810 <Addi> Perhaps just an 8 split.
811 <Addi> that is - split each dimension in half.
813 <TonyC> I get the idea
814 <Addi> But this would seem to be a good approach in our case since we
815 usually have few codevectors.
816 <Addi> So we only need 256*256 entries in a table.
817 <Addi> We could even only index some of them that were deemed as good
819 <TonyC> I was considering adding paletted output support for PNG and
820 TIFF at some point, which support 16-bit palettes
828 typedef struct i_dists {
836 static int dists_sort(void const *a, void const *b) {
837 return ((i_dists *)a)->dist - ((i_dists *)b)->dist;
840 static void rand2dist_setup(i_quantize *quant, i_dists **cdists) {
842 mymalloc(sizeof(i_dists)*quant->mc_count*quant->mc_count);
845 for (i = 0; i < quant->mc_count; ++i) {
846 i_dists *ldists = dists + quant->mc_count * i;
847 i_color val = quant->mc_colors[i];
848 for (j = 0; j < quant->mc_count; ++j) {
850 ldists[j].dist = ceucl_d(&val, quant->mc_colors+j);
852 qsort(ldists, quant->mc_count, sizeof(i_dists), dists_sort);
858 bst_idx = rand() % quant->mc_count; \
859 rand2dist_setup(quant, &dists)
861 static int rand2dist_find(i_color val, i_quantize *quant, i_dists *dists, int index) {
868 cdists = dists + index * quant->mc_count;
870 maxld = 8 * ceucl_d(&val, quant->mc_colors+index);
871 for (i = 0; i < quant->mc_count && cdists[i].dist <= maxld; ++i) {
872 cd = ceucl_d(&val, quant->mc_colors+cdists[i].index);
874 bst_idx = cdists[i].index;
881 #define CF_FIND bst_idx = rand2dist_find(val, quant, dists, bst_idx)
883 #define CF_CLEANUP myfree(dists)
888 static void translate_addi(i_quantize *quant, i_img *img, i_palidx *out) {
889 int x, y, i, k, bst_idx;
891 int pixdev = quant->perturb;
898 for(y=0;y<img->ysize;y++) for(x=0;x<img->xsize;x++) {
899 i_gpix(img,x,y,&val);
900 val.channel[0]=g_sat(val.channel[0]+(int)(pixdev*frandn()));
901 val.channel[1]=g_sat(val.channel[1]+(int)(pixdev*frandn()));
902 val.channel[2]=g_sat(val.channel[2]+(int)(pixdev*frandn()));
908 for(y=0;y<img->ysize;y++) for(x=0;x<img->xsize;x++) {
909 i_gpix(img,x,y,&val);
917 static int floyd_map[] =
923 static int jarvis_map[] =
930 static int stucki_map[] =
939 int width, height, orig;
942 static struct errdiff_map maps[] =
944 { floyd_map, 3, 2, 1 },
945 { jarvis_map, 5, 3, 2 },
946 { stucki_map, 5, 3, 2 },
949 typedef struct errdiff_tag {
953 /* perform an error diffusion dither */
956 translate_errdiff(i_quantize *quant, i_img *img, i_palidx *out) {
958 int mapw, maph, mapo;
964 int minr, maxr, ming, maxg, minb, maxb, cr, cg, cb;
969 if ((quant->errdiff & ed_mask) == ed_custom) {
971 mapw = quant->ed_width;
972 maph = quant->ed_height;
973 mapo = quant->ed_orig;
976 int index = quant->errdiff & ed_mask;
977 if (index >= ed_custom) index = ed_floyd;
978 map = maps[index].map;
979 mapw = maps[index].width;
980 maph = maps[index].height;
981 mapo = maps[index].orig;
984 errw = img->xsize+mapw;
985 err = mymalloc(sizeof(*err) * maph * errw);
987 memset(err, 0, sizeof(*err) * maph * errw);
990 for (i = 0; i < maph * mapw; ++i)
993 for (dy = 0; dy < maph; ++dy) {
994 for (dx = 0; dx < mapw; ++dx) {
995 printf("%2d", map[dx+dy*mapw]);
1002 for (y = 0; y < img->ysize; ++y) {
1003 for (x = 0; x < img->xsize; ++x) {
1007 i_gpix(img, x, y, &val);
1009 perr.r = perr.r < 0 ? -((-perr.r)/difftotal) : perr.r/difftotal;
1010 perr.g = perr.g < 0 ? -((-perr.g)/difftotal) : perr.g/difftotal;
1011 perr.b = perr.b < 0 ? -((-perr.b)/difftotal) : perr.b/difftotal;
1012 /*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);*/
1013 val.channel[0] = g_sat(val.channel[0]-perr.r);
1014 val.channel[1] = g_sat(val.channel[1]-perr.g);
1015 val.channel[2] = g_sat(val.channel[2]-perr.b);
1018 perr.r = quant->mc_colors[bst_idx].channel[0] - val.channel[0];
1019 perr.g = quant->mc_colors[bst_idx].channel[1] - val.channel[1];
1020 perr.b = quant->mc_colors[bst_idx].channel[2] - val.channel[2];
1021 /*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);*/
1022 for (dx = 0; dx < mapw; ++dx) {
1023 for (dy = 0; dy < maph; ++dy) {
1024 err[x+dx+dy*errw].r += perr.r * map[dx+mapw*dy];
1025 err[x+dx+dy*errw].g += perr.g * map[dx+mapw*dy];
1026 err[x+dx+dy*errw].b += perr.b * map[dx+mapw*dy];
1031 /* shift up the error matrix */
1032 for (dy = 0; dy < maph-1; ++dy) {
1033 memcpy(err+dy*errw, err+(dy+1)*errw, sizeof(*err)*errw);
1035 memset(err+(maph-1)*errw, 0, sizeof(*err)*errw);
1039 /* Prescan finds the boxes in the image that have the highest number of colors
1040 and that result is used as the initial value for the vectores */
1043 static void prescan(i_img **imgs,int count, int cnum, cvec *clr) {
1048 for(i=0;i<512;i++) {
1054 /* process each image */
1055 for (i = 0; i < count; ++i) {
1056 i_img *im = imgs[i];
1057 for(y=0;y<im->ysize;y++) for(x=0;x<im->xsize;x++) {
1058 i_gpix(im,x,y,&val);
1059 prebox[pixbox(&val)].pixcnt++;
1063 for(i=0;i<512;i++) prebox[i].pdc=prebox[i].pixcnt;
1064 qsort(prebox,512,sizeof(pbox),(cmpfunc)pboxcmp);
1066 for(i=0;i<cnum;i++) {
1067 /* printf("Color %d\n",i);
1068 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); }
1073 /* 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); } */
1079 /* printf("prebox[%d].cand=%d\n",k,prebox[k].cand); */
1080 if (clr[i].fixed) { i++; continue; } /* reserved go to next */
1081 if (j>=prebox[k].cand) { k++; j=1; } else {
1082 if (prebox[k].cand == 2) boxcenter(prebox[k].boxnum,&(clr[i]));
1083 else boxrand(prebox[k].boxnum,&(clr[i]));
1084 /* 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); */
1092 static void reorder(pbox prescan[512]) {
1100 c.pdc=c.pixcnt/(c.cand*c.cand);
1101 /* c.pdc=c.pixcnt/c.cand; */
1102 while(c.pdc < prescan[nidx+1].pdc && nidx < 511) {
1103 prescan[nidx]=prescan[nidx+1];
1110 pboxcmp(const pbox *a,const pbox *b) {
1111 if (a->pixcnt > b->pixcnt) return -1;
1112 if (a->pixcnt < b->pixcnt) return 1;
1117 boxcenter(int box,cvec *cv) {
1118 cv->r=15+((box&448)>>1);
1119 cv->g=15+((box&56)<<2);
1120 cv->b=15+((box&7)<<5);
1124 bbox(int box,int *r0,int *r1,int *g0,int *g1,int *b0,int *b1) {
1134 boxrand(int box,cvec *cv) {
1135 cv->r=6+(rand()%25)+((box&448)>>1);
1136 cv->g=6+(rand()%25)+((box&56)<<2);
1137 cv->b=6+(rand()%25)+((box&7)<<5);
1147 while (w >= 1 || w == 0) {
1148 u1 = 2 * frand() - 1;
1149 u2 = 2 * frand() - 1;
1153 w = sqrt((-2*log(w))/w);
1157 /* Create hash index */
1160 cr_hashindex(cvec clr[256],int cnum,hashbox hb[512]) {
1162 int bx,mind,cd,cumcnt,bst_idx,i;
1163 /* printf("indexing... \n");*/
1166 for(bx=0; bx<512; bx++) {
1168 for(i=0; i<cnum; i++) {
1169 cd = maxdist(bx,&clr[i]);
1170 if (cd < mind) { mind=cd; bst_idx=i; }
1174 for(i=0;i<cnum;i++) if (mindist(bx,&clr[i])<mind) hb[bx].vec[hb[bx].cnt++]=i;
1175 /*printf("box %d -> approx -> %d\n",bx,hb[bx].cnt); */
1176 /* statbox(bx,cnum,clr); */
1180 /* printf("Average search space: %d\n",cumcnt/512); */
1184 maxdist(int boxnum,cvec *cv) {
1185 int r0,r1,g0,g1,b0,b1;
1192 bbox(boxnum,&r0,&r1,&g0,&g1,&b0,&b1);
1194 mr=max(abs(b-b0),abs(b-b1));
1195 mg=max(abs(g-g0),abs(g-g1));
1196 mb=max(abs(r-r0),abs(r-r1));
1198 return PWR2(mr)+PWR2(mg)+PWR2(mb);
1202 mindist(int boxnum,cvec *cv) {
1203 int r0,r1,g0,g1,b0,b1;
1210 bbox(boxnum,&r0,&r1,&g0,&g1,&b0,&b1);
1212 /* printf("box %d, (%d,%d,%d)-(%d,%d,%d) vec (%d,%d,%d) ",boxnum,r0,g0,b0,r1,g1,b1,r,g,b); */
1214 if (r0<=r && r<=r1 && g0<=g && g<=g1 && b0<=b && b<=b1) return 0;
1216 mr=min(abs(b-b0),abs(b-b1));
1217 mg=min(abs(g-g0),abs(g-g1));
1218 mb=min(abs(r-r0),abs(r-r1));
1224 if (r0<=r && r<=r1 && g0<=g && g<=g1) return mb;
1225 if (r0<=r && r<=r1 && b0<=b && b<=b1) return mg;
1226 if (b0<=b && b<=b1 && g0<=g && g<=g1) return mr;
1228 if (r0<=r && r<=r1) return mg+mb;
1229 if (g0<=g && g<=g1) return mr+mb;
1230 if (b0<=b && b<=b1) return mg+mr;
1235 static void transparent_threshold(i_quantize *, i_palidx *, i_img *, i_palidx);
1236 static void transparent_errdiff(i_quantize *, i_palidx *, i_img *, i_palidx);
1237 static void transparent_ordered(i_quantize *, i_palidx *, i_img *, i_palidx);
1239 void quant_transparent(i_quantize *quant, i_palidx *data, i_img *img,
1240 i_palidx trans_index)
1242 switch (quant->transp) {
1247 quant->tr_threshold = 128;
1250 transparent_threshold(quant, data, img, trans_index);
1254 transparent_errdiff(quant, data, img, trans_index);
1258 transparent_ordered(quant, data, img, trans_index);
1264 transparent_threshold(i_quantize *quant, i_palidx *data, i_img *img,
1265 i_palidx trans_index)
1269 for (y = 0; y < img->ysize; ++y) {
1270 for (x = 0; x < img->xsize; ++x) {
1272 i_gpix(img, x, y, &val);
1273 if (val.rgba.a < quant->tr_threshold)
1274 data[y*img->xsize+x] = trans_index;
1280 transparent_errdiff(i_quantize *quant, i_palidx *data, i_img *img,
1281 i_palidx trans_index)
1285 int mapw, maph, mapo;
1286 int errw, *err, *errp;
1287 int difftotal, out, error;
1288 int x, y, dx, dy, i;
1290 /* no custom map for transparency (yet) */
1291 index = quant->tr_errdiff & ed_mask;
1292 if (index >= ed_custom) index = ed_floyd;
1293 map = maps[index].map;
1294 mapw = maps[index].width;
1295 maph = maps[index].height;
1296 mapo = maps[index].orig;
1298 errw = img->xsize+mapw-1;
1299 err = mymalloc(sizeof(*err) * maph * errw);
1301 memset(err, 0, sizeof(*err) * maph * errw);
1304 for (i = 0; i < maph * mapw; ++i)
1305 difftotal += map[i];
1306 for (y = 0; y < img->ysize; ++y) {
1307 for (x = 0; x < img->xsize; ++x) {
1309 i_gpix(img, x, y, &val);
1310 val.rgba.a = g_sat(val.rgba.a-errp[x]/difftotal);
1311 if (val.rgba.a < 128) {
1313 data[y*img->xsize+x] = trans_index;
1318 error = out - val.rgba.a;
1319 for (dx = 0; dx < mapw; ++dx) {
1320 for (dy = 0; dy < maph; ++dy) {
1321 errp[x+dx-mapo+dy*errw] += error * map[dx+mapw*dy];
1325 /* shift up the error matrix */
1326 for (dy = 0; dy < maph-1; ++dy)
1327 memcpy(err+dy*errw, err+(dy+1)*errw, sizeof(*err)*errw);
1328 memset(err+(maph-1)*errw, 0, sizeof(*err)*errw);
1332 /* builtin ordered dither maps */
1333 unsigned char orddith_maps[][64] =
1336 this is purely random - it's pretty awful
1338 48, 72, 196, 252, 180, 92, 108, 52,
1339 228, 176, 64, 8, 236, 40, 20, 164,
1340 120, 128, 84, 116, 24, 28, 172, 220,
1341 68, 0, 188, 124, 184, 224, 192, 104,
1342 132, 100, 240, 200, 152, 160, 244, 44,
1343 96, 204, 144, 16, 140, 56, 232, 216,
1344 208, 4, 76, 212, 136, 248, 80, 168,
1345 156, 88, 32, 112, 148, 12, 36, 60,
1349 perl spot.perl '($x-3.5)*($x-3.5)+($y-3.5)*($y-3.5)'
1351 240, 232, 200, 136, 140, 192, 228, 248,
1352 220, 148, 100, 76, 80, 104, 152, 212,
1353 180, 116, 56, 32, 36, 60, 120, 176,
1354 156, 64, 28, 0, 8, 44, 88, 160,
1355 128, 92, 24, 12, 4, 40, 68, 132,
1356 184, 96, 48, 20, 16, 52, 108, 188,
1357 216, 144, 112, 72, 84, 124, 164, 224,
1358 244, 236, 196, 168, 172, 204, 208, 252,
1362 'min(dist(1.5, 1.5),dist(5.5,1.5),dist(1.5,5.5),dist(5.5,5.5))'
1364 196, 72, 104, 220, 200, 80, 112, 224,
1365 76, 4, 24, 136, 84, 8, 32, 144,
1366 108, 28, 52, 168, 116, 36, 56, 176,
1367 216, 140, 172, 244, 228, 148, 180, 248,
1368 204, 92, 124, 236, 192, 68, 96, 208,
1369 88, 12, 44, 156, 64, 0, 16, 128,
1370 120, 40, 60, 188, 100, 20, 48, 160,
1371 232, 152, 184, 252, 212, 132, 164, 240,
1374 perl spot.perl '$y-3'
1376 160, 164, 168, 172, 176, 180, 184, 188,
1377 128, 132, 136, 140, 144, 148, 152, 156,
1378 32, 36, 40, 44, 48, 52, 56, 60,
1379 0, 4, 8, 12, 16, 20, 24, 28,
1380 64, 68, 72, 76, 80, 84, 88, 92,
1381 96, 100, 104, 108, 112, 116, 120, 124,
1382 192, 196, 200, 204, 208, 212, 216, 220,
1383 224, 228, 232, 236, 240, 244, 248, 252,
1386 perl spot.perl '$x-3'
1388 180, 100, 40, 12, 44, 104, 184, 232,
1389 204, 148, 60, 16, 64, 128, 208, 224,
1390 212, 144, 76, 8, 80, 132, 216, 244,
1391 160, 112, 68, 20, 84, 108, 172, 236,
1392 176, 96, 72, 28, 88, 152, 188, 228,
1393 200, 124, 92, 0, 32, 116, 164, 240,
1394 168, 120, 36, 24, 48, 136, 192, 248,
1395 196, 140, 52, 4, 56, 156, 220, 252,
1398 perl spot.perl '$y+$x-7'
1400 248, 232, 224, 192, 140, 92, 52, 28,
1401 240, 220, 196, 144, 108, 60, 12, 64,
1402 216, 180, 148, 116, 76, 20, 80, 128,
1403 204, 152, 104, 44, 16, 72, 100, 160,
1404 164, 96, 68, 24, 56, 112, 168, 176,
1405 124, 40, 8, 36, 88, 136, 184, 212,
1406 84, 4, 32, 120, 156, 188, 228, 236,
1407 0, 48, 132, 172, 200, 208, 244, 252,
1410 perl spot.perl '$y-$x'
1412 0, 32, 116, 172, 184, 216, 236, 252,
1413 56, 8, 72, 132, 136, 200, 228, 240,
1414 100, 36, 12, 40, 92, 144, 204, 220,
1415 168, 120, 60, 16, 44, 96, 156, 176,
1416 180, 164, 112, 48, 28, 52, 128, 148,
1417 208, 192, 152, 88, 84, 20, 64, 104,
1418 232, 224, 196, 140, 108, 68, 24, 76,
1419 248, 244, 212, 188, 160, 124, 80, 4,
1423 good for display, bad for print
1426 0, 128, 32, 192, 8, 136, 40, 200,
1427 224, 64, 160, 112, 232, 72, 168, 120,
1428 48, 144, 16, 208, 56, 152, 24, 216,
1429 176, 96, 240, 80, 184, 104, 248, 88,
1430 12, 140, 44, 204, 4, 132, 36, 196,
1431 236, 76, 172, 124, 228, 68, 164, 116,
1432 60, 156, 28, 220, 52, 148, 20, 212,
1433 188, 108, 252, 92, 180, 100, 244, 84,
1438 transparent_ordered(i_quantize *quant, i_palidx *data, i_img *img,
1439 i_palidx trans_index)
1441 unsigned char *spot;
1443 if (quant->tr_orddith == od_custom)
1444 spot = quant->tr_custom;
1446 spot = orddith_maps[quant->tr_orddith];
1447 for (y = 0; y < img->ysize; ++y) {
1448 for (x = 0; x < img->xsize; ++x) {
1450 i_gpix(img, x, y, &val);
1451 if (val.rgba.a < spot[(x&7)+(y&7)*8])
1452 data[x+y*img->xsize] = trans_index;