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) {
32 /* giflib does it's own color table generation */
33 if (quant->translate == pt_giflib)
36 switch (quant->make_colors & mc_mask) {
38 /* use user's specified map */
44 for (r = 0; r < 256; r+=0x33)
45 for (g = 0; g < 256; g+=0x33)
46 for (b = 0; b < 256; b += 0x33)
47 setcol(quant->mc_colors+i++, r, g, b, 0);
54 makemap_addi(quant, imgs, count);
60 static void translate_giflib(i_quantize *, i_img *, i_palidx *);
62 static void translate_closest(i_quantize *, i_img *, i_palidx *);
63 static void translate_errdiff(i_quantize *, i_img *, i_palidx *);
64 static void translate_addi(i_quantize *, i_img *, i_palidx *);
66 /* Quantize the image given the palette in quant.
68 The giflib quantizer ignores the palette.
70 i_palidx *quant_translate(i_quantize *quant, i_img *img) {
72 mm_log((1, "quant_translate(quant %p, img %p)\n", quant, img));
74 result = mymalloc(img->xsize * img->ysize);
76 switch (quant->translate) {
79 translate_giflib(quant, img, result);
84 translate_closest(quant, img, result);
88 translate_errdiff(quant, img, result);
93 translate_addi(quant, img, result);
103 #define GET_RGB(im, x, y, ri, gi, bi, col) \
104 i_gpix((im),(x),(y),&(col)); (ri)=(col).rgb.r; \
105 if((im)->channels==3) { (bi)=(col).rgb.b; (gi)=(col).rgb.g; }
108 quant_replicate(i_img *im, i_palidx *output, i_quantize *quant);
110 /* Use the gif_lib quantization functions to quantize the image */
111 static void translate_giflib(i_quantize *quant, i_img *img, i_palidx *out) {
112 int x,y,ColorMapSize,colours_in;
116 GifByteType *RedBuffer = NULL, *GreenBuffer = NULL, *BlueBuffer = NULL;
117 GifByteType *RedP, *GreenP, *BlueP;
118 ColorMapObject *OutputColorMap = NULL;
122 mm_log((1,"i_writegif(quant %p, img %p, out %p)\n", quant, img, out));
124 /*if (!(im->channels==1 || im->channels==3)) { fprintf(stderr,"Unable to write gif, improper colorspace.\n"); exit(3); }*/
126 ColorMapSize = quant->mc_size;
128 Size = ((long) img->xsize) * img->ysize * sizeof(GifByteType);
131 if ((OutputColorMap = MakeMapObject(ColorMapSize, NULL)) == NULL)
132 m_fatal(0,"Failed to allocate memory for Output colormap.");
133 /* if ((OutputBuffer = (GifByteType *) mymalloc(im->xsize * im->ysize * sizeof(GifByteType))) == NULL)
134 m_fatal(0,"Failed to allocate memory for output buffer.");*/
136 /* ******************************************************* */
137 /* count the number of colours in the image */
138 colours_in=i_count_colors(img, OutputColorMap->ColorCount);
140 if(colours_in != -1) { /* less then the number wanted */
141 /* so we copy them over as-is */
142 mm_log((2,"image has %d colours, which fits in %d. Copying\n",
143 colours_in,ColorMapSize));
144 quant_replicate(img, out, quant);
145 /* saves the colors, so don't fall through */
149 mm_log((2,"image has %d colours, more then %d. Quantizing\n",colours_in,ColorMapSize));
151 if (img->channels >= 3) {
152 if ((RedBuffer = (GifByteType *) mymalloc((unsigned int) Size)) == NULL) {
153 m_fatal(0,"Failed to allocate memory required, aborted.");
156 if ((GreenBuffer = (GifByteType *) mymalloc((unsigned int) Size)) == NULL) {
157 m_fatal(0,"Failed to allocate memory required, aborted.");
162 if ((BlueBuffer = (GifByteType *) mymalloc((unsigned int) Size)) == NULL) {
163 m_fatal(0,"Failed to allocate memory required, aborted.");
170 GreenP = GreenBuffer;
173 for (y=0; y< img->ysize; y++) for (x=0; x < img->xsize; x++) {
174 i_gpix(img,x,y,&col);
176 *GreenP++ = col.rgb.g;
177 *BlueP++ = col.rgb.b;
182 if ((RedBuffer = (GifByteType *) mymalloc((unsigned int) Size))==NULL) {
183 m_fatal(0,"Failed to allocate memory required, aborted.");
187 GreenBuffer=BlueBuffer=RedBuffer;
189 for (y=0; y< img->ysize; y++) for (x=0; x < img->xsize; x++) {
190 i_gpix(img,x,y,&col);
195 if (QuantizeBuffer(img->xsize, img->ysize, &ColorMapSize, RedBuffer, GreenBuffer, BlueBuffer,
196 out, OutputColorMap->Colors) == GIF_ERROR) {
197 mm_log((1,"Error in QuantizeBuffer, unable to write image.\n"));
202 if (img->channels == 3) { free(GreenBuffer); free(BlueBuffer); }
204 /* copy over the color map */
205 for (i = 0; i < ColorMapSize; ++i) {
206 quant->mc_colors[i].rgb.r = OutputColorMap->Colors[i].Red;
207 quant->mc_colors[i].rgb.g = OutputColorMap->Colors[i].Green;
208 quant->mc_colors[i].rgb.b = OutputColorMap->Colors[i].Blue;
210 quant->mc_count = ColorMapSize;
215 quant_replicate(i_img *im, GifByteType *output, i_quantize *quant) {
216 int x, y, alloced, r, g=0, b=0, idx ;
220 for(y=0; y<im->ysize; y++) {
221 for(x=0; x<im->xsize; x++) {
223 GET_RGB(im, x,y, r,g,b, col);
225 for(idx=0; idx<alloced; idx++) { /* linear search for an index */
226 if(quant->mc_colors[idx].rgb.r==r &&
227 quant->mc_colors[idx].rgb.g==g &&
228 quant->mc_colors[idx].rgb.b==b) {
233 if(idx >= alloced) { /* if we haven't already, we */
234 idx=alloced++; /* add the colour to the map */
235 if(quant->mc_size < alloced) {
236 mm_log((1,"Tried to allocate more then %d colours.\n",
240 quant->mc_colors[idx].rgb.r=r;
241 quant->mc_colors[idx].rgb.g=g;
242 quant->mc_colors[idx].rgb.b=b;
244 *output=idx; /* fill output buffer */
245 output++; /* with colour indexes */
248 quant->mc_count = alloced;
254 static void translate_closest(i_quantize *quant, i_img *img, i_palidx *out) {
256 translate_addi(quant, img, out);
259 #define PWR2(x) ((x)*(x))
261 typedef int (*cmpfunc)(const void*, const void*);
284 static void prescan(i_img **im,int count, int cnum, cvec *clr);
285 static void reorder(pbox prescan[512]);
286 static int pboxcmp(const pbox *a,const pbox *b);
287 static void boxcenter(int box,cvec *cv);
288 static float frandn(void);
289 static void boxrand(int box,cvec *cv);
290 static void bbox(int box,int *r0,int *r1,int *g0,int *g1,int *b0,int *b1);
291 static void cr_hashindex(cvec clr[256],int cnum,hashbox hb[512]);
292 static int mindist(int boxnum,cvec *cv);
293 static int maxdist(int boxnum,cvec *cv);
295 /* Some of the simpler functions are kept here to aid the compiler -
296 maybe some of them will be inlined. */
299 pixbox(i_color *ic) { return ((ic->channel[0] & 224)<<1)+ ((ic->channel[1]&224)>>2) + ((ic->channel[2] &224) >> 5); }
303 if (in>255) { return 255; }
304 else if (in>0) return in;
311 return rand()/(RAND_MAX+1.0);
316 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]); }
320 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]); }
324 This quantization algorithm and implementation routines are by Arnar
325 M. Hrafnkelson. In case any new ideas are here they are mine since
326 this was written from scratch.
328 The algorithm uses local means in the following way:
330 For each point in the colormap we find which image points
331 have that point as it's closest point. We calculate the mean
332 of those points and in the next iteration it will be the new
333 entry in the colormap.
335 In order to speed this process up (i.e. nearest neighbor problem) We
336 divied the r,g,b space up in equally large 512 boxes. The boxes are
337 numbered from 0 to 511. Their numbering is so that for a given vector
338 it is known that it belongs to the box who is formed by concatenating the
339 3 most significant bits from each component of the RGB triplet.
341 For each box we find the list of points from the colormap who might be
342 closest to any given point within the box. The exact solution
343 involves finding the Voronoi map (or the dual the Delauny
344 triangulation) and has many issues including numerical stability.
346 So we use this approximation:
348 1. Find which point has the shortest maximum distance to the box.
349 2. Find all points that have a shorter minimum distance than that to the box
351 This is a very simple task and is not computationally heavy if one
352 takes into account that the minimum distances from a pixel to a box is
353 always found by checking if it's inside the box or is closest to some
354 side or a corner. Finding the maximum distance is also either a side
357 This approach results 2-3 times more than the actual points needed but
358 is still a good gain over the complete space. Usually when one has a
359 256 Colorcolor map a search over 30 is often obtained.
361 A bit of an enhancement to this approach is to keep a seperate list
362 for each side of the cube, but this will require even more memory.
364 Arnar M. Hrafnkelsson (addi@umich.edu);
368 Extracted from gifquant.c, removed dependencies on gif_lib,
369 and added support for multiple images.
370 starting from 1nov2000 by TonyC <tony@develop-help.com>.
375 makemap_addi(i_quantize *quant, i_img **imgs, int count) {
377 int cnum, i, x, y, bst_idx=0, ld, cd, iter, currhb, img_num;
382 clr = (cvec *)mymalloc(sizeof(cvec) * quant->mc_size);
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;
390 /* mymalloc doesn't clear memory, so I think we need this */
391 for (; i < quant->mc_size; ++i) {
395 cnum = quant->mc_size;
398 prescan(imgs, count, cnum, clr);
399 cr_hashindex(clr, cnum, hb);
401 for(iter=0;iter<3;iter++) {
404 for (img_num = 0; img_num < count; ++img_num) {
405 i_img *im = imgs[img_num];
406 for(y=0;y<im->ysize;y++) for(x=0;x<im->xsize;x++) {
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); */
414 cd=eucl_d(&clr[hb[currhb].vec[i]],&val);
416 ld=cd; /* shortest distance yet */
417 bst_idx=hb[currhb].vec[i]; /* index of closest vector yet */
421 clr[bst_idx].mcount++;
423 clr[bst_idx].dr+=val.channel[0];
424 clr[bst_idx].dg+=val.channel[1];
425 clr[bst_idx].db+=val.channel[2];
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; }
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); */
433 /* printf("total error: %.2f\n",sqrt(accerr)); */
435 for(i=0;i<cnum;i++) {
436 if (clr[i].fixed) continue; /* skip reserved colors */
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;
444 /* let's try something else */
456 cr_hashindex(clr,cnum,hb);
461 for(i=0;i<cnum;i++) {
462 cd=eucl_d(&clr[i],&val);
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
474 /* transfer the colors back */
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;
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;
492 quant->mc_count = cnum;
495 /* don't want to keep this */
501 /* Define one of the following 4 symbols to choose a colour search method
502 The idea is to try these out, including benchmarking, to see which
503 is fastest in a good spread of circumstances.
504 I'd expect IM_CFLINSEARCH to be fastest for very small palettes, and
505 IM_CFHASHBOX for large images with large palettes.
507 Some other possibilities include:
508 - search over entries sorted by luminance
510 Initially I was planning on testing using the macros and then
511 integrating the code directly into each function, but this means if
512 we find a bug at a late stage we will need to update N copies of
513 the same code. Also, keeping the code in the macros means that the
514 code in the translation functions is much more to the point,
515 there's no distracting colour search code to remove attention from
516 what makes _this_ translation function different. It may be
517 advisable to move the setup code into functions at some point, but
518 it should be possible to do this fairly transparently.
520 If IM_CF_COPTS is defined then CFLAGS must have an appropriate
523 Each option needs to define 4 macros:
524 CF_VARS - variables to define in the function
525 CF_SETUP - code to setup for the colour search, eg. allocating and
526 initializing lookup tables
527 CF_FIND - code that looks for the color in val and puts the best
528 matching index in bst_idx
529 CF_CLEANUP - code to clean up, eg. releasing memory
532 /*#define IM_CFLINSEARCH*/
534 /*#define IM_CFSORTCHAN*/
535 /*#define IM_CFRAND2DIST*/
540 /* The original version I wrote for this used the sort.
541 If this is defined then we use a sort to extract the indices for
545 /* assume i is available */
546 #define CF_VARS hashbox hb[512]; \
552 static long *gdists; /* qsort is annoying */
553 /* int might be smaller than long, so we need to do a real compare
554 rather than a subtraction*/
555 static int distcomp(void const *a, void const *b) {
556 long ra = gdists[*(int const *)a];
557 long rb = gdists[*(int const *)b];
568 /* for each hashbox build a list of colours that are in the hb or is closer
570 This is pretty involved. The original gifquant generated the hashbox
571 as part of it's normal processing, but since the map generation is now
572 separated from the translation we need to do this on the spot.
573 Any optimizations, even if they don't produce perfect results would be
576 static void hbsetup(i_quantize *quant, hashbox *hb) {
577 long *dists, mind, maxd, cd;
578 int cr, cb, cg, hbnum, i;
581 int *indices = mymalloc(quant->mc_count * sizeof(int));
584 dists = mymalloc(quant->mc_count * sizeof(long));
585 for (cr = 0; cr < 8; ++cr) {
586 for (cg = 0; cg < 8; ++cg) {
587 for (cb = 0; cb < 8; ++cb) {
588 /* centre of the hashbox */
589 cenc.channel[0] = cr*pboxjump+pboxjump/2;
590 cenc.channel[1] = cg*pboxjump+pboxjump/2;
591 cenc.channel[2] = cb*pboxjump+pboxjump/2;
592 hbnum = pixbox(&cenc);
594 /* order indices in the order of distance from the hashbox */
595 for (i = 0; i < quant->mc_count; ++i) {
599 dists[i] = ceucl_d(&cenc, quant->mc_colors+i);
602 /* it should be possible to do this without a sort
603 but so far I'm too lazy */
605 qsort(indices, quant->mc_count, sizeof(int), distcomp);
606 /* any colors that can match are within mind+diagonal size of
608 mind = dists[indices[0]];
610 maxd = (sqrt(mind)+pboxjump)*(sqrt(mind)+pboxjump);
611 while (i < quant->mc_count && dists[indices[i]] < maxd) {
612 hb[hbnum].vec[hb[hbnum].cnt++] = indices[i++];
615 /* work out the minimum */
617 for (i = 0; i < quant->mc_count; ++i) {
618 if (dists[i] < mind) mind = dists[i];
620 /* transfer any colours that might be closest to a colour in
622 maxd = (sqrt(mind)+pboxjump)*(sqrt(mind)+pboxjump);
623 for (i = 0; i < quant->mc_count; ++i) {
625 hb[hbnum].vec[hb[hbnum].cnt++] = i;
636 #define CF_SETUP hbsetup(quant, hb)
639 currhb = pixbox(&val); \
641 for (i = 0; i < hb[currhb].cnt; ++i) { \
642 cd = ceucl_d(quant->mc_colors+hb[currhb].vec[i], &val); \
643 if (cd < ld) { ld = cd; bst_idx = hb[currhb].vec[i]; } \
650 #ifdef IM_CFLINSEARCH
651 /* as simple as it gets */
652 #define CF_VARS long ld, cd
653 #define CF_SETUP /* none needed */
656 for (i = 0; i < quant->mc_count; ++i) { \
657 cd = ceucl_d(quant->mc_colors+i, &val); \
658 if (cd < ld) { ld = cd; bst_idx = i; } \
664 static int gsortchan;
665 static i_quantize *gquant;
666 static int chansort(void const *a, void const *b) {
667 return gquant->mc_colors[*(int const *)a].channel[gsortchan] -
668 gquant->mc_colors[*(int const *)b].channel[gsortchan];
670 #define CF_VARS int *indices, sortchan, diff; \
672 int vindex[256] /* where to find value i of chan */
674 static void chansetup(i_img *img, i_quantize *quant, int *csortchan,
675 int *vindex, int **cindices) {
676 int *indices, sortchan, chan, i, chval;
677 int chanmins[MAXCHANNELS], chanmaxs[MAXCHANNELS], maxrange;
679 /* find the channel with the maximum range */
680 /* the maximum stddev would probably be better */
681 for (chan = 0; chan < img->channels; ++chan) {
682 chanmins[chan] = 256; chanmaxs[chan] = 0;
683 for (i = 0; i < quant->mc_count; ++i) {
684 if (quant->mc_colors[i].channel[chan] < chanmins[chan])
685 chanmins[chan] = quant->mc_colors[i].channel[chan];
686 if (quant->mc_colors[i].channel[chan] > chanmaxs[chan])
687 chanmaxs[chan] = quant->mc_colors[i].channel[chan];
691 for (chan = 0; chan < img->channels; ++chan) {
692 if (chanmaxs[chan]-chanmins[chan] > maxrange) {
693 maxrange = chanmaxs[chan]-chanmins[chan];
697 indices = mymalloc(quant->mc_count * sizeof(int)) ;
698 for (i = 0; i < quant->mc_count; ++i) {
701 gsortchan = sortchan;
703 qsort(indices, quant->mc_count, sizeof(int), chansort) ;
704 /* now a lookup table to find entries faster */
705 for (chval=0, i=0; i < quant->mc_count; ++i) {
706 while (chval < 256 &&
707 chval < quant->mc_colors[indices[i]].channel[sortchan]) {
711 while (chval < 256) {
712 vindex[chval++] = quant->mc_count-1;
714 *csortchan = sortchan;
719 chansetup(img, quant, &sortchan, vindex, &indices)
721 int chanfind(i_color val, i_quantize *quant, int *indices, int *vindex,
723 int i, bst_idx, diff, maxdiff;
726 i = vindex[val.channel[sortchan]];
727 bst_idx = indices[i];
730 maxdiff = quant->mc_count;
731 while (diff < maxdiff) {
732 if (i+diff < quant->mc_count) {
733 cd = ceucl_d(&val, quant->mc_colors+indices[i+diff]);
735 bst_idx = indices[i+diff];
741 cd = ceucl_d(&val, quant->mc_colors+indices[i-diff]);
743 bst_idx = indices[i-diff];
755 bst_idx = chanfind(val, quant, indices, vindex, sortchan)
758 #define CF_CLEANUP myfree(indices)
762 #ifdef IM_CFRAND2DIST
764 /* This is based on a method described by Addi in the #imager channel
765 on the 28/2/2001. I was about 1am Sydney time at the time, so I
766 wasn't at my most cogent. Well, that's my excuse :)
768 <TonyC> what I have at the moment is: hashboxes, with optimum hash box
769 filling; simple linear search; and a lookup in the widest channel
770 (currently the channel with the maximum range)
771 <Addi> There is one more way that might be simple to implement.
772 <Addi> You want to hear?
774 <purl> somebody said that was not true
775 <Addi> For each of the colors in the palette start by creating a
776 sorted list of the form:
777 <Addi> [distance, color]
778 <Addi> Where they are sorted by distance.
779 <TonyC> distance to where?
780 <Addi> Where the elements in the lists are the distances and colors of
781 the other colors in the palette
783 <Addi> So if you are at color 0
784 <Addi> ok - now to search for the closest color when you are creating
785 the final image is done like this:
786 <Addi> a) pick a random color from the palette
787 <Addi> b) calculate the distance to it
788 <Addi> c) only check the vectors that are within double the distance
789 in the list of the color you picked from the palette.
790 <Addi> Does that seem logical?
791 <Addi> Lets imagine that we only have grayscale to make an example:
792 <Addi> Our palette has 1 4 10 20 as colors.
793 <Addi> And we want to quantize the color 11
794 <Addi> lets say we picked 10 randomly
795 <Addi> the double distance is 2
796 <Addi> since abs(10-11)*2 is 2
797 <Addi> And the list at vector 10 is this:
798 <Addi> [0, 10], [6 4], [9, 1], [10, 20]
799 <Addi> so we look at the first one (but not the second one since 6 is
800 at a greater distance than 2.
801 <Addi> Any of that make sense?
802 <TonyC> yes, though are you suggesting another random jump to one of
803 the colours with the possible choices? or an exhaustive search?
804 <Addi> TonyC: It's possible to come up with a recursive/iterative
805 enhancement but this is the 'basic' version.
806 <Addi> Which would do an iterative search.
807 <Addi> You can come up with conditions where it pays to switch to a new one.
808 <Addi> And the 'random' start can be switched over to a small tree.
809 <Addi> So you would have a little index at the start.
810 <Addi> to get you into the general direction
811 <Addi> Perhaps just an 8 split.
812 <Addi> that is - split each dimension in half.
814 <TonyC> I get the idea
815 <Addi> But this would seem to be a good approach in our case since we
816 usually have few codevectors.
817 <Addi> So we only need 256*256 entries in a table.
818 <Addi> We could even only index some of them that were deemed as good
820 <TonyC> I was considering adding paletted output support for PNG and
821 TIFF at some point, which support 16-bit palettes
829 typedef struct i_dists {
837 static int dists_sort(void const *a, void const *b) {
838 return ((i_dists *)a)->dist - ((i_dists *)b)->dist;
841 static void rand2dist_setup(i_quantize *quant, i_dists **cdists) {
843 mymalloc(sizeof(i_dists)*quant->mc_count*quant->mc_count);
846 for (i = 0; i < quant->mc_count; ++i) {
847 i_dists *ldists = dists + quant->mc_count * i;
848 i_color val = quant->mc_colors[i];
849 for (j = 0; j < quant->mc_count; ++j) {
851 ldists[j].dist = ceucl_d(&val, quant->mc_colors+j);
853 qsort(ldists, quant->mc_count, sizeof(i_dists), dists_sort);
859 bst_idx = rand() % quant->mc_count; \
860 rand2dist_setup(quant, &dists)
862 static int rand2dist_find(i_color val, i_quantize *quant, i_dists *dists, int index) {
869 cdists = dists + index * quant->mc_count;
871 maxld = 8 * ceucl_d(&val, quant->mc_colors+index);
872 for (i = 0; i < quant->mc_count && cdists[i].dist <= maxld; ++i) {
873 cd = ceucl_d(&val, quant->mc_colors+cdists[i].index);
875 bst_idx = cdists[i].index;
882 #define CF_FIND bst_idx = rand2dist_find(val, quant, dists, bst_idx)
884 #define CF_CLEANUP myfree(dists)
889 static void translate_addi(i_quantize *quant, i_img *img, i_palidx *out) {
890 int x, y, i, k, bst_idx;
892 int pixdev = quant->perturb;
899 for(y=0;y<img->ysize;y++) for(x=0;x<img->xsize;x++) {
900 i_gpix(img,x,y,&val);
901 val.channel[0]=g_sat(val.channel[0]+(int)(pixdev*frandn()));
902 val.channel[1]=g_sat(val.channel[1]+(int)(pixdev*frandn()));
903 val.channel[2]=g_sat(val.channel[2]+(int)(pixdev*frandn()));
909 for(y=0;y<img->ysize;y++) for(x=0;x<img->xsize;x++) {
910 i_gpix(img,x,y,&val);
918 static int floyd_map[] =
924 static int jarvis_map[] =
931 static int stucki_map[] =
940 int width, height, orig;
943 static struct errdiff_map maps[] =
945 { floyd_map, 3, 2, 1 },
946 { jarvis_map, 5, 3, 2 },
947 { stucki_map, 5, 3, 2 },
950 typedef struct errdiff_tag {
954 /* perform an error diffusion dither */
957 translate_errdiff(i_quantize *quant, i_img *img, i_palidx *out) {
959 int mapw, maph, mapo;
965 int minr, maxr, ming, maxg, minb, maxb, cr, cg, cb;
970 if ((quant->errdiff & ed_mask) == ed_custom) {
972 mapw = quant->ed_width;
973 maph = quant->ed_height;
974 mapo = quant->ed_orig;
977 int index = quant->errdiff & ed_mask;
978 if (index >= ed_custom) index = ed_floyd;
979 map = maps[index].map;
980 mapw = maps[index].width;
981 maph = maps[index].height;
982 mapo = maps[index].orig;
985 errw = img->xsize+mapw;
986 err = mymalloc(sizeof(*err) * maph * errw);
988 memset(err, 0, sizeof(*err) * maph * errw);
991 for (i = 0; i < maph * mapw; ++i)
994 for (dy = 0; dy < maph; ++dy) {
995 for (dx = 0; dx < mapw; ++dx) {
996 printf("%2d", map[dx+dy*mapw]);
1003 for (y = 0; y < img->ysize; ++y) {
1004 for (x = 0; x < img->xsize; ++x) {
1008 i_gpix(img, x, y, &val);
1010 perr.r = perr.r < 0 ? -((-perr.r)/difftotal) : perr.r/difftotal;
1011 perr.g = perr.g < 0 ? -((-perr.g)/difftotal) : perr.g/difftotal;
1012 perr.b = perr.b < 0 ? -((-perr.b)/difftotal) : perr.b/difftotal;
1013 /*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);*/
1014 val.channel[0] = g_sat(val.channel[0]-perr.r);
1015 val.channel[1] = g_sat(val.channel[1]-perr.g);
1016 val.channel[2] = g_sat(val.channel[2]-perr.b);
1019 perr.r = quant->mc_colors[bst_idx].channel[0] - val.channel[0];
1020 perr.g = quant->mc_colors[bst_idx].channel[1] - val.channel[1];
1021 perr.b = quant->mc_colors[bst_idx].channel[2] - val.channel[2];
1022 /*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);*/
1023 for (dx = 0; dx < mapw; ++dx) {
1024 for (dy = 0; dy < maph; ++dy) {
1025 err[x+dx+dy*errw].r += perr.r * map[dx+mapw*dy];
1026 err[x+dx+dy*errw].g += perr.g * map[dx+mapw*dy];
1027 err[x+dx+dy*errw].b += perr.b * map[dx+mapw*dy];
1032 /* shift up the error matrix */
1033 for (dy = 0; dy < maph-1; ++dy) {
1034 memcpy(err+dy*errw, err+(dy+1)*errw, sizeof(*err)*errw);
1036 memset(err+(maph-1)*errw, 0, sizeof(*err)*errw);
1040 /* Prescan finds the boxes in the image that have the highest number of colors
1041 and that result is used as the initial value for the vectores */
1044 static void prescan(i_img **imgs,int count, int cnum, cvec *clr) {
1049 for(i=0;i<512;i++) {
1055 /* process each image */
1056 for (i = 0; i < count; ++i) {
1057 i_img *im = imgs[i];
1058 for(y=0;y<im->ysize;y++) for(x=0;x<im->xsize;x++) {
1059 i_gpix(im,x,y,&val);
1060 prebox[pixbox(&val)].pixcnt++;
1064 for(i=0;i<512;i++) prebox[i].pdc=prebox[i].pixcnt;
1065 qsort(prebox,512,sizeof(pbox),(cmpfunc)pboxcmp);
1067 for(i=0;i<cnum;i++) {
1068 /* printf("Color %d\n",i);
1069 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); }
1074 /* 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); } */
1080 /* printf("prebox[%d].cand=%d\n",k,prebox[k].cand); */
1081 if (clr[i].fixed) { i++; continue; } /* reserved go to next */
1082 if (j>=prebox[k].cand) { k++; j=1; } else {
1083 if (prebox[k].cand == 2) boxcenter(prebox[k].boxnum,&(clr[i]));
1084 else boxrand(prebox[k].boxnum,&(clr[i]));
1085 /* 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); */
1093 static void reorder(pbox prescan[512]) {
1101 c.pdc=c.pixcnt/(c.cand*c.cand);
1102 /* c.pdc=c.pixcnt/c.cand; */
1103 while(c.pdc < prescan[nidx+1].pdc && nidx < 511) {
1104 prescan[nidx]=prescan[nidx+1];
1111 pboxcmp(const pbox *a,const pbox *b) {
1112 if (a->pixcnt > b->pixcnt) return -1;
1113 if (a->pixcnt < b->pixcnt) return 1;
1118 boxcenter(int box,cvec *cv) {
1119 cv->r=15+((box&448)>>1);
1120 cv->g=15+((box&56)<<2);
1121 cv->b=15+((box&7)<<5);
1125 bbox(int box,int *r0,int *r1,int *g0,int *g1,int *b0,int *b1) {
1135 boxrand(int box,cvec *cv) {
1136 cv->r=6+(rand()%25)+((box&448)>>1);
1137 cv->g=6+(rand()%25)+((box&56)<<2);
1138 cv->b=6+(rand()%25)+((box&7)<<5);
1148 while (w >= 1 || w == 0) {
1149 u1 = 2 * frand() - 1;
1150 u2 = 2 * frand() - 1;
1154 w = sqrt((-2*log(w))/w);
1158 /* Create hash index */
1161 cr_hashindex(cvec clr[256],int cnum,hashbox hb[512]) {
1163 int bx,mind,cd,cumcnt,bst_idx,i;
1164 /* printf("indexing... \n");*/
1167 for(bx=0; bx<512; bx++) {
1169 for(i=0; i<cnum; i++) {
1170 cd = maxdist(bx,&clr[i]);
1171 if (cd < mind) { mind=cd; bst_idx=i; }
1175 for(i=0;i<cnum;i++) if (mindist(bx,&clr[i])<mind) hb[bx].vec[hb[bx].cnt++]=i;
1176 /*printf("box %d -> approx -> %d\n",bx,hb[bx].cnt); */
1177 /* statbox(bx,cnum,clr); */
1181 /* printf("Average search space: %d\n",cumcnt/512); */
1185 maxdist(int boxnum,cvec *cv) {
1186 int r0,r1,g0,g1,b0,b1;
1193 bbox(boxnum,&r0,&r1,&g0,&g1,&b0,&b1);
1195 mr=max(abs(b-b0),abs(b-b1));
1196 mg=max(abs(g-g0),abs(g-g1));
1197 mb=max(abs(r-r0),abs(r-r1));
1199 return PWR2(mr)+PWR2(mg)+PWR2(mb);
1203 mindist(int boxnum,cvec *cv) {
1204 int r0,r1,g0,g1,b0,b1;
1211 bbox(boxnum,&r0,&r1,&g0,&g1,&b0,&b1);
1213 /* printf("box %d, (%d,%d,%d)-(%d,%d,%d) vec (%d,%d,%d) ",boxnum,r0,g0,b0,r1,g1,b1,r,g,b); */
1215 if (r0<=r && r<=r1 && g0<=g && g<=g1 && b0<=b && b<=b1) return 0;
1217 mr=min(abs(b-b0),abs(b-b1));
1218 mg=min(abs(g-g0),abs(g-g1));
1219 mb=min(abs(r-r0),abs(r-r1));
1225 if (r0<=r && r<=r1 && g0<=g && g<=g1) return mb;
1226 if (r0<=r && r<=r1 && b0<=b && b<=b1) return mg;
1227 if (b0<=b && b<=b1 && g0<=g && g<=g1) return mr;
1229 if (r0<=r && r<=r1) return mg+mb;
1230 if (g0<=g && g<=g1) return mr+mb;
1231 if (b0<=b && b<=b1) return mg+mr;
1236 static void transparent_threshold(i_quantize *, i_palidx *, i_img *, i_palidx);
1237 static void transparent_errdiff(i_quantize *, i_palidx *, i_img *, i_palidx);
1238 static void transparent_ordered(i_quantize *, i_palidx *, i_img *, i_palidx);
1240 void quant_transparent(i_quantize *quant, i_palidx *data, i_img *img,
1241 i_palidx trans_index)
1243 switch (quant->transp) {
1248 quant->tr_threshold = 128;
1251 transparent_threshold(quant, data, img, trans_index);
1255 transparent_errdiff(quant, data, img, trans_index);
1259 transparent_ordered(quant, data, img, trans_index);
1265 transparent_threshold(i_quantize *quant, i_palidx *data, i_img *img,
1266 i_palidx trans_index)
1270 for (y = 0; y < img->ysize; ++y) {
1271 for (x = 0; x < img->xsize; ++x) {
1273 i_gpix(img, x, y, &val);
1274 if (val.rgba.a < quant->tr_threshold)
1275 data[y*img->xsize+x] = trans_index;
1281 transparent_errdiff(i_quantize *quant, i_palidx *data, i_img *img,
1282 i_palidx trans_index)
1286 int mapw, maph, mapo;
1287 int errw, *err, *errp;
1288 int difftotal, out, error;
1289 int x, y, dx, dy, i;
1291 /* no custom map for transparency (yet) */
1292 index = quant->tr_errdiff & ed_mask;
1293 if (index >= ed_custom) index = ed_floyd;
1294 map = maps[index].map;
1295 mapw = maps[index].width;
1296 maph = maps[index].height;
1297 mapo = maps[index].orig;
1299 errw = img->xsize+mapw-1;
1300 err = mymalloc(sizeof(*err) * maph * errw);
1302 memset(err, 0, sizeof(*err) * maph * errw);
1305 for (i = 0; i < maph * mapw; ++i)
1306 difftotal += map[i];
1307 for (y = 0; y < img->ysize; ++y) {
1308 for (x = 0; x < img->xsize; ++x) {
1310 i_gpix(img, x, y, &val);
1311 val.rgba.a = g_sat(val.rgba.a-errp[x]/difftotal);
1312 if (val.rgba.a < 128) {
1314 data[y*img->xsize+x] = trans_index;
1319 error = out - val.rgba.a;
1320 for (dx = 0; dx < mapw; ++dx) {
1321 for (dy = 0; dy < maph; ++dy) {
1322 errp[x+dx-mapo+dy*errw] += error * map[dx+mapw*dy];
1326 /* shift up the error matrix */
1327 for (dy = 0; dy < maph-1; ++dy)
1328 memcpy(err+dy*errw, err+(dy+1)*errw, sizeof(*err)*errw);
1329 memset(err+(maph-1)*errw, 0, sizeof(*err)*errw);
1333 /* builtin ordered dither maps */
1334 unsigned char orddith_maps[][64] =
1337 this is purely random - it's pretty awful
1339 48, 72, 196, 252, 180, 92, 108, 52,
1340 228, 176, 64, 8, 236, 40, 20, 164,
1341 120, 128, 84, 116, 24, 28, 172, 220,
1342 68, 0, 188, 124, 184, 224, 192, 104,
1343 132, 100, 240, 200, 152, 160, 244, 44,
1344 96, 204, 144, 16, 140, 56, 232, 216,
1345 208, 4, 76, 212, 136, 248, 80, 168,
1346 156, 88, 32, 112, 148, 12, 36, 60,
1350 perl spot.perl '($x-3.5)*($x-3.5)+($y-3.5)*($y-3.5)'
1352 240, 232, 200, 136, 140, 192, 228, 248,
1353 220, 148, 100, 76, 80, 104, 152, 212,
1354 180, 116, 56, 32, 36, 60, 120, 176,
1355 156, 64, 28, 0, 8, 44, 88, 160,
1356 128, 92, 24, 12, 4, 40, 68, 132,
1357 184, 96, 48, 20, 16, 52, 108, 188,
1358 216, 144, 112, 72, 84, 124, 164, 224,
1359 244, 236, 196, 168, 172, 204, 208, 252,
1363 'min(dist(1.5, 1.5),dist(5.5,1.5),dist(1.5,5.5),dist(5.5,5.5))'
1365 196, 72, 104, 220, 200, 80, 112, 224,
1366 76, 4, 24, 136, 84, 8, 32, 144,
1367 108, 28, 52, 168, 116, 36, 56, 176,
1368 216, 140, 172, 244, 228, 148, 180, 248,
1369 204, 92, 124, 236, 192, 68, 96, 208,
1370 88, 12, 44, 156, 64, 0, 16, 128,
1371 120, 40, 60, 188, 100, 20, 48, 160,
1372 232, 152, 184, 252, 212, 132, 164, 240,
1375 perl spot.perl '$y-3'
1377 160, 164, 168, 172, 176, 180, 184, 188,
1378 128, 132, 136, 140, 144, 148, 152, 156,
1379 32, 36, 40, 44, 48, 52, 56, 60,
1380 0, 4, 8, 12, 16, 20, 24, 28,
1381 64, 68, 72, 76, 80, 84, 88, 92,
1382 96, 100, 104, 108, 112, 116, 120, 124,
1383 192, 196, 200, 204, 208, 212, 216, 220,
1384 224, 228, 232, 236, 240, 244, 248, 252,
1387 perl spot.perl '$x-3'
1389 180, 100, 40, 12, 44, 104, 184, 232,
1390 204, 148, 60, 16, 64, 128, 208, 224,
1391 212, 144, 76, 8, 80, 132, 216, 244,
1392 160, 112, 68, 20, 84, 108, 172, 236,
1393 176, 96, 72, 28, 88, 152, 188, 228,
1394 200, 124, 92, 0, 32, 116, 164, 240,
1395 168, 120, 36, 24, 48, 136, 192, 248,
1396 196, 140, 52, 4, 56, 156, 220, 252,
1399 perl spot.perl '$y+$x-7'
1401 248, 232, 224, 192, 140, 92, 52, 28,
1402 240, 220, 196, 144, 108, 60, 12, 64,
1403 216, 180, 148, 116, 76, 20, 80, 128,
1404 204, 152, 104, 44, 16, 72, 100, 160,
1405 164, 96, 68, 24, 56, 112, 168, 176,
1406 124, 40, 8, 36, 88, 136, 184, 212,
1407 84, 4, 32, 120, 156, 188, 228, 236,
1408 0, 48, 132, 172, 200, 208, 244, 252,
1411 perl spot.perl '$y-$x'
1413 0, 32, 116, 172, 184, 216, 236, 252,
1414 56, 8, 72, 132, 136, 200, 228, 240,
1415 100, 36, 12, 40, 92, 144, 204, 220,
1416 168, 120, 60, 16, 44, 96, 156, 176,
1417 180, 164, 112, 48, 28, 52, 128, 148,
1418 208, 192, 152, 88, 84, 20, 64, 104,
1419 232, 224, 196, 140, 108, 68, 24, 76,
1420 248, 244, 212, 188, 160, 124, 80, 4,
1424 good for display, bad for print
1427 0, 128, 32, 192, 8, 136, 40, 200,
1428 224, 64, 160, 112, 232, 72, 168, 120,
1429 48, 144, 16, 208, 56, 152, 24, 216,
1430 176, 96, 240, 80, 184, 104, 248, 88,
1431 12, 140, 44, 204, 4, 132, 36, 196,
1432 236, 76, 172, 124, 228, 68, 164, 116,
1433 60, 156, 28, 220, 52, 148, 20, 212,
1434 188, 108, 252, 92, 180, 100, 244, 84,
1439 transparent_ordered(i_quantize *quant, i_palidx *data, i_img *img,
1440 i_palidx trans_index)
1442 unsigned char *spot;
1444 if (quant->tr_orddith == od_custom)
1445 spot = quant->tr_custom;
1447 spot = orddith_maps[quant->tr_orddith];
1448 for (y = 0; y < img->ysize; ++y) {
1449 for (x = 0; x < img->xsize; ++x) {
1451 i_gpix(img, x, y, &val);
1452 if (val.rgba.a < spot[(x&7)+(y&7)*8])
1453 data[x+y*img->xsize] = trans_index;