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,"translate_giflib(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);
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;