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 hb = mymalloc(sizeof(hashbox) * 512);
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 */
502 /* Define one of the following 4 symbols to choose a colour search method
503 The idea is to try these out, including benchmarking, to see which
504 is fastest in a good spread of circumstances.
505 I'd expect IM_CFLINSEARCH to be fastest for very small palettes, and
506 IM_CFHASHBOX for large images with large palettes.
508 Some other possibilities include:
509 - search over entries sorted by luminance
511 Initially I was planning on testing using the macros and then
512 integrating the code directly into each function, but this means if
513 we find a bug at a late stage we will need to update N copies of
514 the same code. Also, keeping the code in the macros means that the
515 code in the translation functions is much more to the point,
516 there's no distracting colour search code to remove attention from
517 what makes _this_ translation function different. It may be
518 advisable to move the setup code into functions at some point, but
519 it should be possible to do this fairly transparently.
521 If IM_CF_COPTS is defined then CFLAGS must have an appropriate
524 Each option needs to define 4 macros:
525 CF_VARS - variables to define in the function
526 CF_SETUP - code to setup for the colour search, eg. allocating and
527 initializing lookup tables
528 CF_FIND - code that looks for the color in val and puts the best
529 matching index in bst_idx
530 CF_CLEANUP - code to clean up, eg. releasing memory
533 /*#define IM_CFLINSEARCH*/
535 /*#define IM_CFSORTCHAN*/
536 /*#define IM_CFRAND2DIST*/
541 /* The original version I wrote for this used the sort.
542 If this is defined then we use a sort to extract the indices for
546 /* assume i is available */
547 #define CF_VARS hashbox *hb = mymalloc(sizeof(hashbox) * 512); \
553 static long *gdists; /* qsort is annoying */
554 /* int might be smaller than long, so we need to do a real compare
555 rather than a subtraction*/
556 static int distcomp(void const *a, void const *b) {
557 long ra = gdists[*(int const *)a];
558 long rb = gdists[*(int const *)b];
569 /* for each hashbox build a list of colours that are in the hb or is closer
571 This is pretty involved. The original gifquant generated the hashbox
572 as part of it's normal processing, but since the map generation is now
573 separated from the translation we need to do this on the spot.
574 Any optimizations, even if they don't produce perfect results would be
577 static void hbsetup(i_quantize *quant, hashbox *hb) {
578 long *dists, mind, maxd, cd;
579 int cr, cb, cg, hbnum, i;
582 int *indices = mymalloc(quant->mc_count * sizeof(int));
585 dists = mymalloc(quant->mc_count * sizeof(long));
586 for (cr = 0; cr < 8; ++cr) {
587 for (cg = 0; cg < 8; ++cg) {
588 for (cb = 0; cb < 8; ++cb) {
589 /* centre of the hashbox */
590 cenc.channel[0] = cr*pboxjump+pboxjump/2;
591 cenc.channel[1] = cg*pboxjump+pboxjump/2;
592 cenc.channel[2] = cb*pboxjump+pboxjump/2;
593 hbnum = pixbox(&cenc);
595 /* order indices in the order of distance from the hashbox */
596 for (i = 0; i < quant->mc_count; ++i) {
600 dists[i] = ceucl_d(&cenc, quant->mc_colors+i);
603 /* it should be possible to do this without a sort
604 but so far I'm too lazy */
606 qsort(indices, quant->mc_count, sizeof(int), distcomp);
607 /* any colors that can match are within mind+diagonal size of
609 mind = dists[indices[0]];
611 maxd = (sqrt(mind)+pboxjump)*(sqrt(mind)+pboxjump);
612 while (i < quant->mc_count && dists[indices[i]] < maxd) {
613 hb[hbnum].vec[hb[hbnum].cnt++] = indices[i++];
616 /* work out the minimum */
618 for (i = 0; i < quant->mc_count; ++i) {
619 if (dists[i] < mind) mind = dists[i];
621 /* transfer any colours that might be closest to a colour in
623 maxd = (sqrt(mind)+pboxjump)*(sqrt(mind)+pboxjump);
624 for (i = 0; i < quant->mc_count; ++i) {
626 hb[hbnum].vec[hb[hbnum].cnt++] = i;
637 #define CF_SETUP hbsetup(quant, hb)
640 currhb = pixbox(&val); \
642 for (i = 0; i < hb[currhb].cnt; ++i) { \
643 cd = ceucl_d(quant->mc_colors+hb[currhb].vec[i], &val); \
644 if (cd < ld) { ld = cd; bst_idx = hb[currhb].vec[i]; } \
647 #define CF_CLEANUP myfree(hb)
651 #ifdef IM_CFLINSEARCH
652 /* as simple as it gets */
653 #define CF_VARS long ld, cd
654 #define CF_SETUP /* none needed */
657 for (i = 0; i < quant->mc_count; ++i) { \
658 cd = ceucl_d(quant->mc_colors+i, &val); \
659 if (cd < ld) { ld = cd; bst_idx = i; } \
665 static int gsortchan;
666 static i_quantize *gquant;
667 static int chansort(void const *a, void const *b) {
668 return gquant->mc_colors[*(int const *)a].channel[gsortchan] -
669 gquant->mc_colors[*(int const *)b].channel[gsortchan];
671 #define CF_VARS int *indices, sortchan, diff; \
673 int vindex[256] /* where to find value i of chan */
675 static void chansetup(i_img *img, i_quantize *quant, int *csortchan,
676 int *vindex, int **cindices) {
677 int *indices, sortchan, chan, i, chval;
678 int chanmins[MAXCHANNELS], chanmaxs[MAXCHANNELS], maxrange;
680 /* find the channel with the maximum range */
681 /* the maximum stddev would probably be better */
682 for (chan = 0; chan < img->channels; ++chan) {
683 chanmins[chan] = 256; chanmaxs[chan] = 0;
684 for (i = 0; i < quant->mc_count; ++i) {
685 if (quant->mc_colors[i].channel[chan] < chanmins[chan])
686 chanmins[chan] = quant->mc_colors[i].channel[chan];
687 if (quant->mc_colors[i].channel[chan] > chanmaxs[chan])
688 chanmaxs[chan] = quant->mc_colors[i].channel[chan];
692 for (chan = 0; chan < img->channels; ++chan) {
693 if (chanmaxs[chan]-chanmins[chan] > maxrange) {
694 maxrange = chanmaxs[chan]-chanmins[chan];
698 indices = mymalloc(quant->mc_count * sizeof(int)) ;
699 for (i = 0; i < quant->mc_count; ++i) {
702 gsortchan = sortchan;
704 qsort(indices, quant->mc_count, sizeof(int), chansort) ;
705 /* now a lookup table to find entries faster */
706 for (chval=0, i=0; i < quant->mc_count; ++i) {
707 while (chval < 256 &&
708 chval < quant->mc_colors[indices[i]].channel[sortchan]) {
712 while (chval < 256) {
713 vindex[chval++] = quant->mc_count-1;
715 *csortchan = sortchan;
720 chansetup(img, quant, &sortchan, vindex, &indices)
722 int chanfind(i_color val, i_quantize *quant, int *indices, int *vindex,
724 int i, bst_idx, diff, maxdiff;
727 i = vindex[val.channel[sortchan]];
728 bst_idx = indices[i];
731 maxdiff = quant->mc_count;
732 while (diff < maxdiff) {
733 if (i+diff < quant->mc_count) {
734 cd = ceucl_d(&val, quant->mc_colors+indices[i+diff]);
736 bst_idx = indices[i+diff];
742 cd = ceucl_d(&val, quant->mc_colors+indices[i-diff]);
744 bst_idx = indices[i-diff];
756 bst_idx = chanfind(val, quant, indices, vindex, sortchan)
759 #define CF_CLEANUP myfree(indices)
763 #ifdef IM_CFRAND2DIST
765 /* This is based on a method described by Addi in the #imager channel
766 on the 28/2/2001. I was about 1am Sydney time at the time, so I
767 wasn't at my most cogent. Well, that's my excuse :)
769 <TonyC> what I have at the moment is: hashboxes, with optimum hash box
770 filling; simple linear search; and a lookup in the widest channel
771 (currently the channel with the maximum range)
772 <Addi> There is one more way that might be simple to implement.
773 <Addi> You want to hear?
775 <purl> somebody said that was not true
776 <Addi> For each of the colors in the palette start by creating a
777 sorted list of the form:
778 <Addi> [distance, color]
779 <Addi> Where they are sorted by distance.
780 <TonyC> distance to where?
781 <Addi> Where the elements in the lists are the distances and colors of
782 the other colors in the palette
784 <Addi> So if you are at color 0
785 <Addi> ok - now to search for the closest color when you are creating
786 the final image is done like this:
787 <Addi> a) pick a random color from the palette
788 <Addi> b) calculate the distance to it
789 <Addi> c) only check the vectors that are within double the distance
790 in the list of the color you picked from the palette.
791 <Addi> Does that seem logical?
792 <Addi> Lets imagine that we only have grayscale to make an example:
793 <Addi> Our palette has 1 4 10 20 as colors.
794 <Addi> And we want to quantize the color 11
795 <Addi> lets say we picked 10 randomly
796 <Addi> the double distance is 2
797 <Addi> since abs(10-11)*2 is 2
798 <Addi> And the list at vector 10 is this:
799 <Addi> [0, 10], [6 4], [9, 1], [10, 20]
800 <Addi> so we look at the first one (but not the second one since 6 is
801 at a greater distance than 2.
802 <Addi> Any of that make sense?
803 <TonyC> yes, though are you suggesting another random jump to one of
804 the colours with the possible choices? or an exhaustive search?
805 <Addi> TonyC: It's possible to come up with a recursive/iterative
806 enhancement but this is the 'basic' version.
807 <Addi> Which would do an iterative search.
808 <Addi> You can come up with conditions where it pays to switch to a new one.
809 <Addi> And the 'random' start can be switched over to a small tree.
810 <Addi> So you would have a little index at the start.
811 <Addi> to get you into the general direction
812 <Addi> Perhaps just an 8 split.
813 <Addi> that is - split each dimension in half.
815 <TonyC> I get the idea
816 <Addi> But this would seem to be a good approach in our case since we
817 usually have few codevectors.
818 <Addi> So we only need 256*256 entries in a table.
819 <Addi> We could even only index some of them that were deemed as good
821 <TonyC> I was considering adding paletted output support for PNG and
822 TIFF at some point, which support 16-bit palettes
830 typedef struct i_dists {
838 static int dists_sort(void const *a, void const *b) {
839 return ((i_dists *)a)->dist - ((i_dists *)b)->dist;
842 static void rand2dist_setup(i_quantize *quant, i_dists **cdists) {
844 mymalloc(sizeof(i_dists)*quant->mc_count*quant->mc_count);
847 for (i = 0; i < quant->mc_count; ++i) {
848 i_dists *ldists = dists + quant->mc_count * i;
849 i_color val = quant->mc_colors[i];
850 for (j = 0; j < quant->mc_count; ++j) {
852 ldists[j].dist = ceucl_d(&val, quant->mc_colors+j);
854 qsort(ldists, quant->mc_count, sizeof(i_dists), dists_sort);
860 bst_idx = rand() % quant->mc_count; \
861 rand2dist_setup(quant, &dists)
863 static int rand2dist_find(i_color val, i_quantize *quant, i_dists *dists, int index) {
870 cdists = dists + index * quant->mc_count;
872 maxld = 8 * ceucl_d(&val, quant->mc_colors+index);
873 for (i = 0; i < quant->mc_count && cdists[i].dist <= maxld; ++i) {
874 cd = ceucl_d(&val, quant->mc_colors+cdists[i].index);
876 bst_idx = cdists[i].index;
883 #define CF_FIND bst_idx = rand2dist_find(val, quant, dists, bst_idx)
885 #define CF_CLEANUP myfree(dists)
890 static void translate_addi(i_quantize *quant, i_img *img, i_palidx *out) {
891 int x, y, i, k, bst_idx;
893 int pixdev = quant->perturb;
900 for(y=0;y<img->ysize;y++) for(x=0;x<img->xsize;x++) {
901 i_gpix(img,x,y,&val);
902 val.channel[0]=g_sat(val.channel[0]+(int)(pixdev*frandn()));
903 val.channel[1]=g_sat(val.channel[1]+(int)(pixdev*frandn()));
904 val.channel[2]=g_sat(val.channel[2]+(int)(pixdev*frandn()));
910 for(y=0;y<img->ysize;y++) for(x=0;x<img->xsize;x++) {
911 i_gpix(img,x,y,&val);
919 static int floyd_map[] =
925 static int jarvis_map[] =
932 static int stucki_map[] =
941 int width, height, orig;
944 static struct errdiff_map maps[] =
946 { floyd_map, 3, 2, 1 },
947 { jarvis_map, 5, 3, 2 },
948 { stucki_map, 5, 3, 2 },
951 typedef struct errdiff_tag {
955 /* perform an error diffusion dither */
958 translate_errdiff(i_quantize *quant, i_img *img, i_palidx *out) {
960 int mapw, maph, mapo;
966 int minr, maxr, ming, maxg, minb, maxb, cr, cg, cb;
971 if ((quant->errdiff & ed_mask) == ed_custom) {
973 mapw = quant->ed_width;
974 maph = quant->ed_height;
975 mapo = quant->ed_orig;
978 int index = quant->errdiff & ed_mask;
979 if (index >= ed_custom) index = ed_floyd;
980 map = maps[index].map;
981 mapw = maps[index].width;
982 maph = maps[index].height;
983 mapo = maps[index].orig;
986 errw = img->xsize+mapw;
987 err = mymalloc(sizeof(*err) * maph * errw);
989 memset(err, 0, sizeof(*err) * maph * errw);
992 for (i = 0; i < maph * mapw; ++i)
995 for (dy = 0; dy < maph; ++dy) {
996 for (dx = 0; dx < mapw; ++dx) {
997 printf("%2d", map[dx+dy*mapw]);
1004 for (y = 0; y < img->ysize; ++y) {
1005 for (x = 0; x < img->xsize; ++x) {
1009 i_gpix(img, x, y, &val);
1011 perr.r = perr.r < 0 ? -((-perr.r)/difftotal) : perr.r/difftotal;
1012 perr.g = perr.g < 0 ? -((-perr.g)/difftotal) : perr.g/difftotal;
1013 perr.b = perr.b < 0 ? -((-perr.b)/difftotal) : perr.b/difftotal;
1014 /*printf("x %3d y %3d in(%3d, %3d, %3d) di(%4d,%4d,%4d)\n", x, y, val.channel[0], val.channel[1], val.channel[2], perr.r, perr.g, perr.b);*/
1015 val.channel[0] = g_sat(val.channel[0]-perr.r);
1016 val.channel[1] = g_sat(val.channel[1]-perr.g);
1017 val.channel[2] = g_sat(val.channel[2]-perr.b);
1020 perr.r = quant->mc_colors[bst_idx].channel[0] - val.channel[0];
1021 perr.g = quant->mc_colors[bst_idx].channel[1] - val.channel[1];
1022 perr.b = quant->mc_colors[bst_idx].channel[2] - val.channel[2];
1023 /*printf(" out(%3d, %3d, %3d) er(%4d, %4d, %4d)\n", quant->mc_colors[bst_idx].channel[0], quant->mc_colors[bst_idx].channel[1], quant->mc_colors[bst_idx].channel[2], perr.r, perr.g, perr.b);*/
1024 for (dx = 0; dx < mapw; ++dx) {
1025 for (dy = 0; dy < maph; ++dy) {
1026 err[x+dx+dy*errw].r += perr.r * map[dx+mapw*dy];
1027 err[x+dx+dy*errw].g += perr.g * map[dx+mapw*dy];
1028 err[x+dx+dy*errw].b += perr.b * map[dx+mapw*dy];
1033 /* shift up the error matrix */
1034 for (dy = 0; dy < maph-1; ++dy) {
1035 memcpy(err+dy*errw, err+(dy+1)*errw, sizeof(*err)*errw);
1037 memset(err+(maph-1)*errw, 0, sizeof(*err)*errw);
1042 /* Prescan finds the boxes in the image that have the highest number of colors
1043 and that result is used as the initial value for the vectores */
1046 static void prescan(i_img **imgs,int count, int cnum, cvec *clr) {
1051 for(i=0;i<512;i++) {
1057 /* process each image */
1058 for (i = 0; i < count; ++i) {
1059 i_img *im = imgs[i];
1060 for(y=0;y<im->ysize;y++) for(x=0;x<im->xsize;x++) {
1061 i_gpix(im,x,y,&val);
1062 prebox[pixbox(&val)].pixcnt++;
1066 for(i=0;i<512;i++) prebox[i].pdc=prebox[i].pixcnt;
1067 qsort(prebox,512,sizeof(pbox),(cmpfunc)pboxcmp);
1069 for(i=0;i<cnum;i++) {
1070 /* printf("Color %d\n",i);
1071 for(k=0;k<10;k++) { printf("box=%03d %04d %d %04d \n",prebox[k].boxnum,prebox[k].pixcnt,prebox[k].cand,prebox[k].pdc); }
1076 /* for(k=0;k<cnum;k++) { printf("box=%03d %04d %d %04d \n",prebox[k].boxnum,prebox[k].pixcnt,prebox[k].cand,prebox[k].pdc); } */
1082 /* printf("prebox[%d].cand=%d\n",k,prebox[k].cand); */
1083 if (clr[i].fixed) { i++; continue; } /* reserved go to next */
1084 if (j>=prebox[k].cand) { k++; j=1; } else {
1085 if (prebox[k].cand == 2) boxcenter(prebox[k].boxnum,&(clr[i]));
1086 else boxrand(prebox[k].boxnum,&(clr[i]));
1087 /* printf("(%d,%d) %d %d -> (%d,%d,%d)\n",k,j,prebox[k].boxnum,prebox[k].pixcnt,clr[i].r,clr[i].g,clr[i].b); */
1095 static void reorder(pbox prescan[512]) {
1103 c.pdc=c.pixcnt/(c.cand*c.cand);
1104 /* c.pdc=c.pixcnt/c.cand; */
1105 while(c.pdc < prescan[nidx+1].pdc && nidx < 511) {
1106 prescan[nidx]=prescan[nidx+1];
1113 pboxcmp(const pbox *a,const pbox *b) {
1114 if (a->pixcnt > b->pixcnt) return -1;
1115 if (a->pixcnt < b->pixcnt) return 1;
1120 boxcenter(int box,cvec *cv) {
1121 cv->r=15+((box&448)>>1);
1122 cv->g=15+((box&56)<<2);
1123 cv->b=15+((box&7)<<5);
1127 bbox(int box,int *r0,int *r1,int *g0,int *g1,int *b0,int *b1) {
1137 boxrand(int box,cvec *cv) {
1138 cv->r=6+(rand()%25)+((box&448)>>1);
1139 cv->g=6+(rand()%25)+((box&56)<<2);
1140 cv->b=6+(rand()%25)+((box&7)<<5);
1150 while (w >= 1 || w == 0) {
1151 u1 = 2 * frand() - 1;
1152 u2 = 2 * frand() - 1;
1156 w = sqrt((-2*log(w))/w);
1160 /* Create hash index */
1163 cr_hashindex(cvec clr[256],int cnum,hashbox hb[512]) {
1165 int bx,mind,cd,cumcnt,bst_idx,i;
1166 /* printf("indexing... \n");*/
1169 for(bx=0; bx<512; bx++) {
1171 for(i=0; i<cnum; i++) {
1172 cd = maxdist(bx,&clr[i]);
1173 if (cd < mind) { mind=cd; bst_idx=i; }
1177 for(i=0;i<cnum;i++) if (mindist(bx,&clr[i])<mind) hb[bx].vec[hb[bx].cnt++]=i;
1178 /*printf("box %d -> approx -> %d\n",bx,hb[bx].cnt); */
1179 /* statbox(bx,cnum,clr); */
1183 /* printf("Average search space: %d\n",cumcnt/512); */
1187 maxdist(int boxnum,cvec *cv) {
1188 int r0,r1,g0,g1,b0,b1;
1195 bbox(boxnum,&r0,&r1,&g0,&g1,&b0,&b1);
1197 mr=max(abs(b-b0),abs(b-b1));
1198 mg=max(abs(g-g0),abs(g-g1));
1199 mb=max(abs(r-r0),abs(r-r1));
1201 return PWR2(mr)+PWR2(mg)+PWR2(mb);
1205 mindist(int boxnum,cvec *cv) {
1206 int r0,r1,g0,g1,b0,b1;
1213 bbox(boxnum,&r0,&r1,&g0,&g1,&b0,&b1);
1215 /* printf("box %d, (%d,%d,%d)-(%d,%d,%d) vec (%d,%d,%d) ",boxnum,r0,g0,b0,r1,g1,b1,r,g,b); */
1217 if (r0<=r && r<=r1 && g0<=g && g<=g1 && b0<=b && b<=b1) return 0;
1219 mr=min(abs(b-b0),abs(b-b1));
1220 mg=min(abs(g-g0),abs(g-g1));
1221 mb=min(abs(r-r0),abs(r-r1));
1227 if (r0<=r && r<=r1 && g0<=g && g<=g1) return mb;
1228 if (r0<=r && r<=r1 && b0<=b && b<=b1) return mg;
1229 if (b0<=b && b<=b1 && g0<=g && g<=g1) return mr;
1231 if (r0<=r && r<=r1) return mg+mb;
1232 if (g0<=g && g<=g1) return mr+mb;
1233 if (b0<=b && b<=b1) return mg+mr;
1238 static void transparent_threshold(i_quantize *, i_palidx *, i_img *, i_palidx);
1239 static void transparent_errdiff(i_quantize *, i_palidx *, i_img *, i_palidx);
1240 static void transparent_ordered(i_quantize *, i_palidx *, i_img *, i_palidx);
1242 void quant_transparent(i_quantize *quant, i_palidx *data, i_img *img,
1243 i_palidx trans_index)
1245 switch (quant->transp) {
1250 quant->tr_threshold = 128;
1253 transparent_threshold(quant, data, img, trans_index);
1257 transparent_errdiff(quant, data, img, trans_index);
1261 transparent_ordered(quant, data, img, trans_index);
1267 transparent_threshold(i_quantize *quant, i_palidx *data, i_img *img,
1268 i_palidx trans_index)
1272 for (y = 0; y < img->ysize; ++y) {
1273 for (x = 0; x < img->xsize; ++x) {
1275 i_gpix(img, x, y, &val);
1276 if (val.rgba.a < quant->tr_threshold)
1277 data[y*img->xsize+x] = trans_index;
1283 transparent_errdiff(i_quantize *quant, i_palidx *data, i_img *img,
1284 i_palidx trans_index)
1288 int mapw, maph, mapo;
1289 int errw, *err, *errp;
1290 int difftotal, out, error;
1291 int x, y, dx, dy, i;
1293 /* no custom map for transparency (yet) */
1294 index = quant->tr_errdiff & ed_mask;
1295 if (index >= ed_custom) index = ed_floyd;
1296 map = maps[index].map;
1297 mapw = maps[index].width;
1298 maph = maps[index].height;
1299 mapo = maps[index].orig;
1301 errw = img->xsize+mapw-1;
1302 err = mymalloc(sizeof(*err) * maph * errw);
1304 memset(err, 0, sizeof(*err) * maph * errw);
1307 for (i = 0; i < maph * mapw; ++i)
1308 difftotal += map[i];
1309 for (y = 0; y < img->ysize; ++y) {
1310 for (x = 0; x < img->xsize; ++x) {
1312 i_gpix(img, x, y, &val);
1313 val.rgba.a = g_sat(val.rgba.a-errp[x]/difftotal);
1314 if (val.rgba.a < 128) {
1316 data[y*img->xsize+x] = trans_index;
1321 error = out - val.rgba.a;
1322 for (dx = 0; dx < mapw; ++dx) {
1323 for (dy = 0; dy < maph; ++dy) {
1324 errp[x+dx-mapo+dy*errw] += error * map[dx+mapw*dy];
1328 /* shift up the error matrix */
1329 for (dy = 0; dy < maph-1; ++dy)
1330 memcpy(err+dy*errw, err+(dy+1)*errw, sizeof(*err)*errw);
1331 memset(err+(maph-1)*errw, 0, sizeof(*err)*errw);
1335 /* builtin ordered dither maps */
1336 unsigned char orddith_maps[][64] =
1339 this is purely random - it's pretty awful
1341 48, 72, 196, 252, 180, 92, 108, 52,
1342 228, 176, 64, 8, 236, 40, 20, 164,
1343 120, 128, 84, 116, 24, 28, 172, 220,
1344 68, 0, 188, 124, 184, 224, 192, 104,
1345 132, 100, 240, 200, 152, 160, 244, 44,
1346 96, 204, 144, 16, 140, 56, 232, 216,
1347 208, 4, 76, 212, 136, 248, 80, 168,
1348 156, 88, 32, 112, 148, 12, 36, 60,
1352 perl spot.perl '($x-3.5)*($x-3.5)+($y-3.5)*($y-3.5)'
1354 240, 232, 200, 136, 140, 192, 228, 248,
1355 220, 148, 100, 76, 80, 104, 152, 212,
1356 180, 116, 56, 32, 36, 60, 120, 176,
1357 156, 64, 28, 0, 8, 44, 88, 160,
1358 128, 92, 24, 12, 4, 40, 68, 132,
1359 184, 96, 48, 20, 16, 52, 108, 188,
1360 216, 144, 112, 72, 84, 124, 164, 224,
1361 244, 236, 196, 168, 172, 204, 208, 252,
1365 'min(dist(1.5, 1.5),dist(5.5,1.5),dist(1.5,5.5),dist(5.5,5.5))'
1367 196, 72, 104, 220, 200, 80, 112, 224,
1368 76, 4, 24, 136, 84, 8, 32, 144,
1369 108, 28, 52, 168, 116, 36, 56, 176,
1370 216, 140, 172, 244, 228, 148, 180, 248,
1371 204, 92, 124, 236, 192, 68, 96, 208,
1372 88, 12, 44, 156, 64, 0, 16, 128,
1373 120, 40, 60, 188, 100, 20, 48, 160,
1374 232, 152, 184, 252, 212, 132, 164, 240,
1377 perl spot.perl '$y-3'
1379 160, 164, 168, 172, 176, 180, 184, 188,
1380 128, 132, 136, 140, 144, 148, 152, 156,
1381 32, 36, 40, 44, 48, 52, 56, 60,
1382 0, 4, 8, 12, 16, 20, 24, 28,
1383 64, 68, 72, 76, 80, 84, 88, 92,
1384 96, 100, 104, 108, 112, 116, 120, 124,
1385 192, 196, 200, 204, 208, 212, 216, 220,
1386 224, 228, 232, 236, 240, 244, 248, 252,
1389 perl spot.perl '$x-3'
1391 180, 100, 40, 12, 44, 104, 184, 232,
1392 204, 148, 60, 16, 64, 128, 208, 224,
1393 212, 144, 76, 8, 80, 132, 216, 244,
1394 160, 112, 68, 20, 84, 108, 172, 236,
1395 176, 96, 72, 28, 88, 152, 188, 228,
1396 200, 124, 92, 0, 32, 116, 164, 240,
1397 168, 120, 36, 24, 48, 136, 192, 248,
1398 196, 140, 52, 4, 56, 156, 220, 252,
1401 perl spot.perl '$y+$x-7'
1403 248, 232, 224, 192, 140, 92, 52, 28,
1404 240, 220, 196, 144, 108, 60, 12, 64,
1405 216, 180, 148, 116, 76, 20, 80, 128,
1406 204, 152, 104, 44, 16, 72, 100, 160,
1407 164, 96, 68, 24, 56, 112, 168, 176,
1408 124, 40, 8, 36, 88, 136, 184, 212,
1409 84, 4, 32, 120, 156, 188, 228, 236,
1410 0, 48, 132, 172, 200, 208, 244, 252,
1413 perl spot.perl '$y-$x'
1415 0, 32, 116, 172, 184, 216, 236, 252,
1416 56, 8, 72, 132, 136, 200, 228, 240,
1417 100, 36, 12, 40, 92, 144, 204, 220,
1418 168, 120, 60, 16, 44, 96, 156, 176,
1419 180, 164, 112, 48, 28, 52, 128, 148,
1420 208, 192, 152, 88, 84, 20, 64, 104,
1421 232, 224, 196, 140, 108, 68, 24, 76,
1422 248, 244, 212, 188, 160, 124, 80, 4,
1426 good for display, bad for print
1429 0, 128, 32, 192, 8, 136, 40, 200,
1430 224, 64, 160, 112, 232, 72, 168, 120,
1431 48, 144, 16, 208, 56, 152, 24, 216,
1432 176, 96, 240, 80, 184, 104, 248, 88,
1433 12, 140, 44, 204, 4, 132, 36, 196,
1434 236, 76, 172, 124, 228, 68, 164, 116,
1435 60, 156, 28, 220, 52, 148, 20, 212,
1436 188, 108, 252, 92, 180, 100, 244, 84,
1441 transparent_ordered(i_quantize *quant, i_palidx *data, i_img *img,
1442 i_palidx trans_index)
1444 unsigned char *spot;
1446 if (quant->tr_orddith == od_custom)
1447 spot = quant->tr_custom;
1449 spot = orddith_maps[quant->tr_orddith];
1450 for (y = 0; y < img->ysize; ++y) {
1451 for (x = 0; x < img->xsize; ++x) {
1453 i_gpix(img, x, y, &val);
1454 if (val.rgba.a < spot[(x&7)+(y&7)*8])
1455 data[x+y*img->xsize] = trans_index;