From 961d4b55769c82e6444d4c43b5af36c9344af009 Mon Sep 17 00:00:00 2001 From: "Mirar (Pontus Hagland)" <pike@sort.mirar.org> Date: Thu, 5 Dec 1996 23:53:27 +0100 Subject: [PATCH] operators, - abs(diff(a,b)) + max(a+b,255) & min(a,b) | max(a,b) quant optimized some (not good enough, but better then before...) Rev: src/modules/image/Makefile.src:1.10 Rev: src/modules/image/blit.c:1.8 Rev: src/modules/image/image.c:1.32 Rev: src/modules/image/image.h:1.15 Rev: src/modules/image/quant.c:1.16 --- src/modules/image/Makefile.src | 2 +- src/modules/image/blit.c | 8 +- src/modules/image/image.c | 50 ++- src/modules/image/image.h | 42 ++- src/modules/image/quant.c | 623 ++++++++++++++++++--------------- 5 files changed, 409 insertions(+), 316 deletions(-) diff --git a/src/modules/image/Makefile.src b/src/modules/image/Makefile.src index 3f7cb23d3e..cfb2140ca2 100644 --- a/src/modules/image/Makefile.src +++ b/src/modules/image/Makefile.src @@ -4,7 +4,7 @@ PREFLAGS=$(DEFINES) -I$(SRCDIR) -I$(SRCDIR)/../.. -I../.. CFLAGS=$(PREFLAGS) $(OTHERFLAGS) @DEFS@ FILES = image.o font.o quant.o lzw.o togif.o matrix.o pnm.o blit.o \ - pattern.o dct.o + pattern.o dct.o operator.o image.a: $(FILES) -rm -f image.a diff --git a/src/modules/image/blit.c b/src/modules/image/blit.c index ea8cca4189..f8672fabd6 100644 --- a/src/modules/image/blit.c +++ b/src/modules/image/blit.c @@ -1,4 +1,4 @@ -/* $Id: blit.c,v 1.7 1996/11/22 20:28:14 law Exp $ */ +/* $Id: blit.c,v 1.8 1996/12/05 22:53:23 law Exp $ */ #include "global.h" #include <math.h> @@ -106,13 +106,13 @@ void img_box_nocheck(INT32 x1,INT32 y1,INT32 x2,INT32 y2) mod=THIS->xsize-(x2-x1)-1; foo=THIS->img+x1+y1*THIS->xsize; - end=THIS->img+x2+y2*THIS->xsize; + end=THIS->img+x1+y2*THIS->xsize; rgb=THIS->rgb; if (!THIS->alpha) - for (; foo<end; foo+=mod) for (x=x1; x<=x2; x++) *(foo++)=rgb; + for (; foo<=end; foo+=mod) for (x=x1; x<=x2; x++) *(foo++)=rgb; else - for (; foo<end; foo+=mod) for (x=x1; x<=x2; x++,foo++) + for (; foo<=end; foo+=mod) for (x=x1; x<=x2; x++,foo++) set_rgb_group_alpha(*foo,rgb,THIS->alpha); } diff --git a/src/modules/image/image.c b/src/modules/image/image.c index 352d17f124..49e975eafb 100644 --- a/src/modules/image/image.c +++ b/src/modules/image/image.c @@ -1,4 +1,4 @@ -/* $Id: image.c,v 1.31 1996/12/03 21:58:37 law Exp $ */ +/* $Id: image.c,v 1.32 1996/12/05 22:53:25 law Exp $ */ #include "global.h" @@ -7,7 +7,7 @@ #include "stralloc.h" #include "global.h" -RCSID("$Id: image.c,v 1.31 1996/12/03 21:58:37 law Exp $"); +RCSID("$Id: image.c,v 1.32 1996/12/05 22:53:25 law Exp $"); #include "types.h" #include "macros.h" #include "object.h" @@ -1396,34 +1396,40 @@ static void image_map_closest(INT32 args) { struct colortable *ct; long i; - rgb_group *rgb; + rgb_group *d,*s; + struct object *o; if (!THIS->img) error("no image\n"); if (args<1 || sp[-args].type!=T_ARRAY) error("illegal argument to image->map_closest()\n"); + + push_int(THIS->xsize); + push_int(THIS->ysize); + o=clone(image_program,2); ct=colortable_from_array(sp[-args].u.array,"image->map_closest()\n"); pop_n_elems(args); i=THIS->xsize*THIS->ysize; - rgb=THIS->img; + s=THIS->img; + d=((struct image*)(o->storage))->img; while (i--) { - *rgb=ct->clut[colortable_rgb(ct,*rgb)]; - rgb++; + *d=ct->clut[colortable_rgb(ct,*s)]; + d++; *s++; } colortable_free(ct); - THISOBJ->refs++; - push_object(THISOBJ); + push_object(o); } static void image_map_fs(INT32 args) { struct colortable *ct; INT32 i,j; - rgb_group *rgb; + rgb_group *d,*s; + struct object *o; int *res,w; rgbl_group *errb; @@ -1432,6 +1438,10 @@ static void image_map_fs(INT32 args) || sp[-args].type!=T_ARRAY) error("illegal argument to image->map_fs()\n"); + push_int(THIS->xsize); + push_int(THIS->ysize); + o=clone(image_program,2); + res=(int*)xalloc(sizeof(int)*THIS->xsize); errb=(rgbl_group*)xalloc(sizeof(rgbl_group)*THIS->xsize); @@ -1444,20 +1454,21 @@ static void image_map_fs(INT32 args) errb[i].b=(rand()%(FS_SCALE*2+1))-FS_SCALE; i=THIS->ysize; - rgb=THIS->img; + s=THIS->img; + d=((struct image*)(o->storage))->img; w=0; while (i--) { - image_floyd_steinberg(rgb,THIS->xsize,errb,w=!w,res,ct); + image_floyd_steinberg(s,THIS->xsize,errb,w=!w,res,ct); for (j=0; j<THIS->xsize; j++) - *(rgb++)=ct->clut[res[j]]; + *(d++)=ct->clut[res[j]]; + s+=THIS->xsize; } free(errb); free(res); colortable_free(ct); - THISOBJ->refs++; - push_object(THISOBJ); + push_object(o); } void image_select_colors(INT32 args) @@ -1632,6 +1643,17 @@ void init_image_programs() add_function("dct",image_dct, "function(:object)",0); + + add_function("`-",image_operator_minus, + "function(object:object)",0); + add_function("`+",image_operator_plus, + "function(object:object)",0); + add_function("`*",image_operator_multiply, + "function(object:object)",0); + add_function("`&",image_operator_minimum, + "function(object:object)",0); + add_function("`|",image_operator_maximum, + "function(object:object)",0); set_init_callback(init_image_struct); set_exit_callback(exit_image_struct); diff --git a/src/modules/image/image.h b/src/modules/image/image.h index 3fde4326e9..3a1b038243 100644 --- a/src/modules/image/image.h +++ b/src/modules/image/image.h @@ -1,21 +1,8 @@ -/* $Id: image.h,v 1.14 1996/12/03 21:58:39 law Exp $ */ +/* $Id: image.h,v 1.15 1996/12/05 22:53:26 law Exp $ */ #define MAX_NUMCOL 32768 -#define QUANT_MAP_BITSR 4 -#define QUANT_MAP_SKIP_BITSR (8-(QUANT_MAP_BITSR)) -#define QUANT_MAP_THISR(X) ((X)>>QUANT_MAP_SKIP_BITSR) -#define QUANT_MAP_REALR (1L<<QUANT_MAP_BITSR) -#define QUANT_MAP_BITSG 4 -#define QUANT_MAP_SKIP_BITSG (8-(QUANT_MAP_BITSG)) -#define QUANT_MAP_THISG(X) ((X)>>QUANT_MAP_SKIP_BITSG) -#define QUANT_MAP_REALG (1L<<QUANT_MAP_BITSG) -#define QUANT_MAP_BITSB 4 -#define QUANT_MAP_SKIP_BITSB (8-(QUANT_MAP_BITSB)) -#define QUANT_MAP_THISB(X) ((X)>>QUANT_MAP_SKIP_BITSB) -#define QUANT_MAP_REALB (1L<<QUANT_MAP_BITSB) - -#define QUANT_SELECT_CACHE 4 +#define QUANT_SELECT_CACHE 6 #define COLOURTYPE unsigned char @@ -52,19 +39,22 @@ struct image struct colortable { int numcol; - struct map_entry - { - unsigned char cl; - unsigned char used; - struct map_entry *next; - } map[QUANT_MAP_REALR][QUANT_MAP_REALG][QUANT_MAP_REALB]; struct rgb_cache { rgb_group index; int value; } cache[QUANT_SELECT_CACHE]; + unsigned long *rgb_node; +/* bit + 31..30 29..22 21..0 + 0=color split value + 1=split red on this + 2=split green =x <=x >x + 3=split blue value value+1 + It will fail for more than 2097152 colors. Sorry... *grin* + */ rgb_group clut[1]; -}; +}; /* rgb_node follows, 2*numcol */ /* colortable declarations - from quant */ @@ -147,3 +137,11 @@ void image_noise_init(void); /* dct.c */ void image_dct(INT32 args); + +/* operator.c */ + +void image_operator_minus(INT32 args); +void image_operator_plus(INT32 args); +void image_operator_multiply(INT32 args); +void image_operator_maximum(INT32 args); +void image_operator_minimum(INT32 args); diff --git a/src/modules/image/quant.c b/src/modules/image/quant.c index 9060f9ec1e..751a6204fe 100644 --- a/src/modules/image/quant.c +++ b/src/modules/image/quant.c @@ -1,4 +1,4 @@ -/* $Id: quant.c,v 1.15 1996/12/02 16:49:39 per Exp $ */ +/* $Id: quant.c,v 1.16 1996/12/05 22:53:27 law Exp $ */ /* @@ -24,8 +24,9 @@ David K #include "image.h" /* +#define QUANT_DEBUG_GAP +#define QUANT_DEBUG_POINT #define QUANT_DEBUG -#define QUANT_DEBUG_DEEP #define QUANT_DEBUG_RGB */ @@ -57,6 +58,11 @@ static void chrono(char *x) /**********************************************************************/ +#define sq(x) ((x)*(x)) +#define DISTANCE(A,B) \ + (sq((A).r-(B).r)+sq((A).g-(B).g)+sq((A).b-(B).b)) + + typedef struct { rgb_group rgb; @@ -70,8 +76,6 @@ typedef struct rgb_entry tbl[1]; } rgb_hashtbl; -typedef struct colortable coltab; - #define hash(rgb,l) (((rgb).r*127+(rgb).g*997+(rgb).b*2111)&(l-1)) #define same_col(rgb1,rgb2) \ (((rgb1).r==(rgb2).r) && ((rgb1).g==(rgb2).g) && ((rgb1).b==(rgb2).b)) @@ -179,7 +183,7 @@ static rgb_group get_tbl_point(rgb_entry *tbl,int len) g+=((unsigned long)tbl[x].rgb.g)*tbl[x].count, b+=((unsigned long)tbl[x].rgb.b)*tbl[x].count; n+=tbl[x].count; -#ifdef QUANT_DEBUG +#ifdef QUANT_DEBUG_POINT fprintf(stderr,"(%d,%d,%d)*%lu; ", tbl[x].rgb.r, tbl[x].rgb.g, @@ -190,7 +194,7 @@ static rgb_group get_tbl_point(rgb_entry *tbl,int len) rgb.r=(unsigned char)(r/n); rgb.g=(unsigned char)(g/n); rgb.b=(unsigned char)(b/n); -#ifdef QUANT_DEBUG +#ifdef QUANT_DEBUG_POINT fprintf(stderr,"-> (%lu,%lu,%lu)/%lu = %d,%d,%d\n", r,g,b,n, rgb.r,rgb.g,rgb.b); @@ -237,7 +241,9 @@ static void sort_tbl(rgb_hashtbl *ht, unsigned long start, unsigned long len, int level, unsigned long idx, unsigned long gap, int ldir, - coltab *ct, rgb_group lower,rgb_group upper) + struct colortable *ct, rgb_group lower,rgb_group upper, + unsigned long **rn_next, + unsigned long *rgb_node) { rgb_entry *tbl = ht->tbl; @@ -254,14 +260,6 @@ static void sort_tbl(rgb_hashtbl *ht, fprintf(stderr,"\n%*s%d,%d,%d-%d,%d,%d ",level,"", lower.r,lower.g,lower.b,upper.r,upper.g,upper.b); - fprintf(stderr,"[%d,%d,%d] - [%d,%d,%d]\n", - QUANT_MAP_THISR(lower.r), - QUANT_MAP_THISG(lower.g), - QUANT_MAP_THISB(lower.b), - QUANT_MAP_THISR(upper.r), - QUANT_MAP_THISG(upper.g), - QUANT_MAP_THISB(upper.b)); - #endif if (len>1) @@ -269,33 +267,78 @@ static void sort_tbl(rgb_hashtbl *ht, /* check which direction has the most span */ /* we make it easy for us, only three directions: r,g,b */ + +#define PRIO_RED 2 +#define PRIO_GREEN 4 +#define PRIO_BLUE 1 + +#if 0 rgb_group min,max; max.r=min.r=tbl[start].rgb.r; max.g=min.g=tbl[start].rgb.g; max.b=min.b=tbl[start].rgb.b; - for (x=1; x<=len; x++) + for (x=1; x<len; x++) { - if (min.r>tbl[x].rgb.r) min.r=tbl[x].rgb.r; - if (min.g>tbl[x].rgb.g) min.g=tbl[x].rgb.g; - if (min.b>tbl[x].rgb.b) min.b=tbl[x].rgb.b; - if (max.r<tbl[x].rgb.r) max.r=tbl[x].rgb.r; - if (max.g<tbl[x].rgb.g) max.g=tbl[x].rgb.g; - if (max.b<tbl[x].rgb.b) max.b=tbl[x].rgb.b; + if (min.r>tbl[start+x].rgb.r) min.r=tbl[start+x].rgb.r; + if (min.g>tbl[start+x].rgb.g) min.g=tbl[start+x].rgb.g; + if (min.b>tbl[start+x].rgb.b) min.b=tbl[start+x].rgb.b; + if (max.r<tbl[start+x].rgb.r) max.r=tbl[start+x].rgb.r; + if (max.g<tbl[start+x].rgb.g) max.g=tbl[start+x].rgb.g; + if (max.b<tbl[start+x].rgb.b) max.b=tbl[start+x].rgb.b; } +#ifdef QUANT_DEBUG +fprintf(stderr,"space: %d,%d,%d-%d,%d,%d ", + min.r,min.g,min.b, + max.r,max.g,max.b); +#endif /* do this weighted, red=2 green=3 blue=1 */ - if ((max.r-min.r)*5>(max.g-min.g)*8) /* r>g */ - if ((max.r-min.r)*5>(max.b-min.b)) /* r>g, r>b */ + if ((max.r-min.r)*PRIO_RED>(max.g-min.g)*PRIO_GREEN) /* r>g */ + if ((max.r-min.r)*PRIO_RED>(max.b-min.b)*PRIO_BLUE) /* r>g, r>b */ dir=0; else /* r>g, b>r */ dir=2; else - if ((max.g-min.g)*8>(max.b-min.b)) /* g>r, g>b */ + if ((max.g-min.g)*PRIO_GREEN>(max.b-min.b)*PRIO_BLUE) /* g>r, g>b */ dir=1; else /* g>r, b>g */ dir=2; +#endif + + rgbl_group sum={0,0,0}; + rgb_group mid; + + for (x=0; x<len; x++) + { + sum.r+=tbl[start+x].rgb.r; + sum.g+=tbl[start+x].rgb.g; + sum.b+=tbl[start+x].rgb.b; + } + mid.r=(unsigned char)(sum.r/len); + mid.g=(unsigned char)(sum.g/len); + mid.b=(unsigned char)(sum.b/len); + + sum.r=sum.g=sum.b=0; + for (x=0; x<len; x++) + { + sum.r+=sq(tbl[start+x].rgb.r-mid.r); + sum.g+=sq(tbl[start+x].rgb.g-mid.g); + sum.b+=sq(tbl[start+x].rgb.b-mid.b); + } + + if (sum.r*PRIO_RED>sum.g*PRIO_GREEN) /* r>g */ + if (sum.r*PRIO_RED>sum.b*PRIO_BLUE) /* r>g, r>b */ + dir=0; + else /* r>g, b>r */ + dir=2; + else + if (sum.g*PRIO_GREEN>sum.b*PRIO_BLUE) /* g>r, g>b */ + dir=1; + else /* g>r, b>g */ + dir=2; + #ifdef QUANT_DEBUG fprintf(stderr," dir=%d ",dir); @@ -320,41 +363,96 @@ static void sort_tbl(rgb_hashtbl *ht, } - if (len>1 && gap>1) + if (len>1 && gap>1) /* recurse */ { unsigned long pos,g1,g2; rgb_group less,more,rgb; + unsigned char split_on=0; + int i; pos=get_tbl_median(tbl+start,len); - rgb=tbl[start+pos].rgb; -#ifdef QUANT_DEBUG - fprintf(stderr, " pos=%lu len=%lu\n",pos,len); -#endif + rgb=tbl[start+pos].rgb; less=upper; more=lower; switch (dir) { - case 0: more.r=rgb.r+1; less.r=rgb.r;break; - case 1: more.g=rgb.g+1; less.g=rgb.g;break; - case 2: more.b=rgb.b+1; less.b=rgb.b;break; + case 0: more.r=rgb.r+1; split_on=less.r=rgb.r; + while (pos<len-1 && tbl[start].rgb.r==tbl[start+pos].rgb.r) pos++; + while (pos>0 && tbl[start+len-1].rgb.r==tbl[start+pos].rgb.r) pos--; + break; + case 1: more.g=rgb.g+1; split_on=less.g=rgb.g; + while (pos<len-1 && tbl[start].rgb.g==tbl[start+pos].rgb.g) pos++; + while (pos>0 && tbl[start+len-1].rgb.g==tbl[start+pos].rgb.g) pos--; + break; + case 2: more.b=rgb.b+1; split_on=less.b=rgb.b; + while (pos<len-1 && tbl[start].rgb.b==tbl[start+pos].rgb.b) pos++; + while (pos>0 && tbl[start+len-1].rgb.b==tbl[start+pos].rgb.b) pos--; + break; } - g1=gap>>1; +#ifdef QUANT_DEBUG + fprintf(stderr, " pos=%lu len=%lu\n",pos,len); +#endif + +#ifdef QUANT_DEBUG_GAP + + fprintf(stderr,"\n left: "); + for (i=0; i<=pos; i++) + fprintf(stderr,"%d,%d,%d; ", + tbl[start+i].rgb.r,tbl[start+i].rgb.g,tbl[start+i].rgb.b); + fprintf(stderr,"\n right: "); + for (; i<len; i++) + fprintf(stderr,"%d,%d,%d; ", + tbl[start+i].rgb.r,tbl[start+i].rgb.g,tbl[start+i].rgb.b); + fprintf(stderr,"\n"); + +#endif + g1=gap>>1; + +#ifdef QUANT_DEBUG_GAP + fprintf(stderr,"gap: %d / %d pos+1=%d len-pos-1=%d gap-g1=%d\n", + g1,gap-g1,pos+1,len-pos-1,gap-g1); +#endif + if (pos+1<g1) g1=pos+1,g2=gap-g1; - else if (len-pos-1<gap-g1) g2=(len-pos)+1,g1=gap-g2; + else if (len-pos-1<gap-g1) g2=(len-pos-1),g1=gap-g2; else g2=gap-g1; - sort_tbl(ht,start,pos+1, - level+1,idx,g1,dir, - ct,lower,less); +#ifdef QUANT_DEBUG + fprintf(stderr,"gap: %d / %d ",g1,g2); +#endif if (gap>1) + { + /* split tree */ + + *rgb_node= + ( (*rn_next)-ct->rgb_node ) + | ( ((unsigned long)split_on) << 22 ) + | ( (dir+1)<<30 ); + rgb_node=*rn_next; + (*rn_next)+=2; + + sort_tbl(ht,start,pos+1, + level+1,idx,g1,dir, + ct,lower,less,rn_next,rgb_node++); + sort_tbl(ht,start+pos+1,len-pos-1, level+1,idx+g1,g2,dir, - ct,more,upper); + ct,more,upper,rn_next,rgb_node); + } + else + { + /* this shouldn't occur? /law */ + abort(); + sort_tbl(ht,start,pos+1, + level+1,idx,g1,dir, + ct,lower,less,rn_next,rgb_node); + } + return; } else { @@ -365,261 +463,215 @@ static void sort_tbl(rgb_hashtbl *ht, ct->clut[idx]=tbl[start].rgb; #ifdef QUANT_DEBUG - fprintf(stderr,"\n [%d,%d,%d] - [%d,%d,%d] %u\n", + fprintf(stderr,"-> end node [%d,%d,%d] - [%d,%d,%d] => %d,%d,%d\n", lower.r, lower.g, lower.b, upper.r, upper.g, upper.b, - (upper.r-lower.r+1)*(upper.g-lower.g+1)*(upper.b-lower.b+1)); - fprintf(stderr,"[%d,%d,%d] - [%d,%d,%d]\n", - QUANT_MAP_THISR(lower.r), - QUANT_MAP_THISG(lower.g), - QUANT_MAP_THISB(lower.b), - QUANT_MAP_THISR(upper.r), - QUANT_MAP_THISG(upper.g), - QUANT_MAP_THISB(upper.b)); + ct->clut[idx].r,ct->clut[idx].g,ct->clut[idx].b); #endif - -#ifdef QUANT_DEBUG -#ifndef QUANT_DEBUG_DEEP - fprintf(stderr,"[%d,%d,%d]-[%d,%d,%d] = %lu (%d,%d,%d)\n", - QUANT_MAP_THISR(lower.r), QUANT_MAP_THISR(lower.g), QUANT_MAP_THISB(lower.b), - QUANT_MAP_THISR(upper.r), QUANT_MAP_THISG(upper.g), QUANT_MAP_THISB(upper.b), - idx, ct->clut[idx].r,ct->clut[idx].g,ct->clut[idx].b); -#endif -#endif - - for(r = QUANT_MAP_THISR(lower.r); r <= QUANT_MAP_THISR(upper.r); r++) - for(g = QUANT_MAP_THISG(lower.g); g <= QUANT_MAP_THISG(upper.g); g++) - for(b = QUANT_MAP_THISB(lower.b); b <= QUANT_MAP_THISB(upper.b); b++) - { -#ifdef QUANT_DEBUG_DEEP - fprintf(stderr,"%*s[%d,%d,%d] = %lu (%d,%d,%d)\n",level,"", - r,g,b,idx, - ct->clut[idx].r,ct->clut[idx].g,ct->clut[idx].b); -#endif - if (ct->map[r][g][b].used) - { - struct map_entry *me; - me=(struct map_entry *)xalloc(sizeof(struct map_entry)); - me->used=1; - me->cl=idx; - me->next=ct->map[r][g][b].next; - ct->map[r][g][b].next=me; - } - else - { - ct->map[r][g][b].used=1; - ct->map[r][g][b].next=NULL; - ct->map[r][g][b].cl=idx; - } - } + + /* write end node */ + *rgb_node=idx; /* done */ } } +static struct colortable *colortable_allocate(int numcol) +{ + struct colortable *ct; + ct = malloc(sizeof(struct colortable)+ + (sizeof(rgb_group)+2*sizeof(unsigned long))*numcol); + if (!ct) error("Out of memory.\n"); + MEMSET(ct,0,sizeof(struct colortable)+ + (2*sizeof(unsigned long)+sizeof(rgb_group))*numcol); + ct->numcol=numcol; + ct->rgb_node=(unsigned long*)(ct->clut+numcol); + return ct; +} struct colortable *colortable_quant(struct image *img,int numcol) { - rgb_hashtbl *tbl; - INT32 i,j; - INT32 sz = img->xsize * img->ysize; - rgb_entry entry; - coltab *ct; - rgb_group black,white; - rgb_group *p; - INT32 entries=0; + rgb_hashtbl *tbl; + INT32 i,j; + INT32 sz = img->xsize * img->ysize; + rgb_entry entry; + struct colortable *ct=NULL; + rgb_group black,white; + rgb_group *p; + INT32 entries=0; + unsigned long *next_free_rgb_node; #ifdef QUANT_DEBUG - fprintf(stderr,"img_quant called\n"); + fprintf(stderr,"img_quant called\n"); #endif - CHRONO("quant"); + CHRONO("quant"); - if (numcol<2) numcol=2; - if (numcol>MAX_NUMCOL) numcol=MAX_NUMCOL; + if (numcol<2) numcol=2; + if (numcol>MAX_NUMCOL) numcol=MAX_NUMCOL; - ct = malloc(sizeof(struct colortable)+sizeof(rgb_group)*numcol); - if (!ct) error("Out of memory.\n"); - MEMSET(ct,0,sizeof(struct colortable)+sizeof(rgb_group)*numcol); - ct->numcol=numcol; + ct = colortable_allocate(numcol); #ifdef QUANT_DEBUG - fprintf(stderr,"Moving colors into hashtable\n"); + fprintf(stderr,"Moving colors into hashtable\n"); #endif - CHRONO("hash init"); + CHRONO("hash init"); - tbl = img_rehash(NULL, 8192); + tbl = img_rehash(NULL, 8192); - if (1) - { - p=img->img; - i=sz; - do - { - register rgb_entry *rgbe,*end; - int len,trig; + if (1) + { + p=img->img; + i=sz; + do + { + register rgb_entry *rgbe,*end; + int len,trig; #ifdef QUANT_DEBUG - fprintf(stderr,"hash: %d pixels left...\n",i); + fprintf(stderr,"hash: %d pixels left...\n",i); #endif - CHRONO("hash..."); + CHRONO("hash..."); - len=tbl->len; - trig=(len*2)/10; /* 20% full => rehash bigger */ - end=(rgbe=tbl->tbl)+tbl->len; + len=tbl->len; + trig=(len*2)/10; /* 20% full => rehash bigger */ + end=(rgbe=tbl->tbl)+tbl->len; - while (i--) - if ( (entries+=hash_enter(rgbe,end,len,*(p++))) > trig ) - { + while (i--) + if ( (entries+=hash_enter(rgbe,end,len,*(p++))) > trig ) + { #ifdef QUANT_DEBUG - fprintf(stderr,"rehash: 20%% = %d / %d...\n",entries,len); + fprintf(stderr,"rehash: 20%% = %d / %d...\n",entries,len); #endif - CHRONO("rehash..."); - tbl=img_rehash(tbl,len<<2); /* multiple size by 4 */ - break; - } - } - while (i>=0); - } + CHRONO("rehash..."); + tbl=img_rehash(tbl,len<<2); /* multiple size by 4 */ + break; + } + } + while (i>=0); + } - /* Compact the hash table */ - CHRONO("compact"); + /* Compact the hash table */ + CHRONO("compact"); #ifdef QUANT_DEBUG - fprintf(stderr,"Compacting\n"); + fprintf(stderr,"Compacting\n"); #endif - i = tbl->len - 1; - j = 0; - while (i > entries) - { - while ((i >= entries) && tbl->tbl[i].count == 0) i--; - while ((j < entries) && tbl->tbl[j].count != 0) j++; - if (j<i) - { - tbl->tbl[j] = tbl->tbl[i]; - tbl->tbl[i].count = 0; - } - } - - white.r=white.g=white.b=255; - black.r=black.g=black.b=0; + i = tbl->len - 1; + j = 0; + while (i > entries) + { + while ((i >= entries) && tbl->tbl[i].count == 0) i--; + while ((j < entries) && tbl->tbl[j].count != 0) j++; + if (j<i) + { + tbl->tbl[j] = tbl->tbl[i]; + tbl->tbl[i].count = 0; + } + } + + white.r=white.g=white.b=255; + black.r=black.g=black.b=0; #ifdef QUANT_DEBUG - fprintf(stderr,"%d colors found, sorting and quantizing...\n",j); + fprintf(stderr,"%d colors found, sorting and quantizing...\n",j); #endif - CHRONO("sort"); - if (j<numcol) ct->numcol=numcol=j; - sort_tbl(tbl, 0, j, 0, 0, numcol, -1, ct, black, white); + CHRONO("sort"); + if (j<numcol) ct->numcol=numcol=j; + + next_free_rgb_node=ct->rgb_node+1; + sort_tbl(tbl, 0, j, 0, 0, numcol, -1, ct, black, white, + &next_free_rgb_node,ct->rgb_node); #ifdef QUANT_DEBUG - fprintf(stderr,"img_quant done, %d colors selected\n", numcol); + fprintf(stderr,"img_quant done, %d colors selected\n", numcol); #endif - CHRONO("done"); + CHRONO("done"); - free(tbl); - CHRONO("really done"); - return ct; + free(tbl); + CHRONO("really done"); + return ct; } struct colortable *colortable_from_array(struct array *arr,char *from) { - rgb_hashtbl *tbl; - INT32 i,j; - coltab *ct; - rgb_group black,white; - rgb_group *p; - INT32 entries=0; - struct svalue s,s2; + rgb_hashtbl *tbl; + INT32 i,j; + struct colortable *ct=NULL; + rgb_group black,white; + rgb_group *p; + INT32 entries=0; + struct svalue s,s2; + unsigned long *next_free_rgb_node; #ifdef QUANT_DEBUG - fprintf(stderr,"ctfa called\n"); + fprintf(stderr,"ctfa called\n"); #endif - CHRONO("ctfa"); + CHRONO("ctfa"); - white.r=white.g=white.b=255; - black.r=black.g=black.b=0; + white.r=white.g=white.b=255; + black.r=black.g=black.b=0; - tbl=img_rehash(NULL,arr->size); + tbl=img_rehash(NULL,arr->size); - s2.type=s.type=T_INT; - for (i=0; i<arr->size; i++) - { - array_index(&s,arr,i); - if (s.type!=T_ARRAY || s.u.array->size<3) - { - free(tbl); - error("Illegal type in colorlist, element %d, %s\n",i,from); - } - array_index(&s2,s.u.array,0); - if (s2.type!=T_INT) tbl->tbl[i].rgb.r=0; else tbl->tbl[i].rgb.r=s2.u.integer; - array_index(&s2,s.u.array,1); - if (s2.type!=T_INT) tbl->tbl[i].rgb.g=0; else tbl->tbl[i].rgb.g=s2.u.integer; - array_index(&s2,s.u.array,2); - if (s2.type!=T_INT) tbl->tbl[i].rgb.b=0; else tbl->tbl[i].rgb.b=s2.u.integer; - tbl->tbl[i].count=1; - } - free_svalue(&s); - free_svalue(&s2); - - ct = malloc(sizeof(struct colortable)+sizeof(rgb_group)*arr->size); - if (!ct) { free(tbl); error("Out of memory.\n"); } - MEMSET(ct,0,sizeof(struct colortable)+sizeof(rgb_group)*arr->size); - ct->numcol=arr->size; - - CHRONO("sort"); - sort_tbl(tbl, 0, arr->size, 0, 0, arr->size, -1, ct, black, white); + s2.type=s.type=T_INT; + for (i=0; i<arr->size; i++) + { + array_index(&s,arr,i); + if (s.type!=T_ARRAY || s.u.array->size<3) + { + free(tbl); + error("Illegal type in colorlist, element %d, %s\n",i,from); + } + array_index(&s2,s.u.array,0); + if (s2.type!=T_INT) tbl->tbl[i].rgb.r=0; else tbl->tbl[i].rgb.r=s2.u.integer; + array_index(&s2,s.u.array,1); + if (s2.type!=T_INT) tbl->tbl[i].rgb.g=0; else tbl->tbl[i].rgb.g=s2.u.integer; + array_index(&s2,s.u.array,2); + if (s2.type!=T_INT) tbl->tbl[i].rgb.b=0; else tbl->tbl[i].rgb.b=s2.u.integer; + tbl->tbl[i].count=1; + } + free_svalue(&s); + free_svalue(&s2); + + ct = colortable_allocate(arr->size); + + CHRONO("sort"); + next_free_rgb_node=ct->rgb_node+1; + sort_tbl(tbl, 0, arr->size, 0, 0, arr->size, -1, ct, black, white, + &next_free_rgb_node,ct->rgb_node); #ifdef QUANT_DEBUG - fprintf(stderr,"img_quant done, %d colors selected\n", arr->size); + fprintf(stderr,"img_quant done, %d colors selected\n", arr->size); #endif - CHRONO("done"); + CHRONO("done"); - free(tbl); + free(tbl); - for (i=0; i<QUANT_SELECT_CACHE; i++) - ct->cache[i].index=white; - j=colortable_rgb(ct,black); /* ^^ dont find it in the cache... */ - for (i=0; i<QUANT_SELECT_CACHE; i++) - ct->cache[i].index=black, - ct->cache[i].value=j; + for (i=0; i<QUANT_SELECT_CACHE; i++) + ct->cache[i].index=white; + j=colortable_rgb(ct,black); /* ^^ dont find it in the cache... */ + for (i=0; i<QUANT_SELECT_CACHE; i++) + ct->cache[i].index=black, + ct->cache[i].value=j; - CHRONO("really done"); - return ct; + CHRONO("really done"); + return ct; } -#define sq(x) ((x)*(x)) -#define DISTANCE(A,B) \ - (sq((A).r-(B).r)+sq((A).g-(B).g)+sq((A).b-(B).b)) - int colortable_rgb(struct colortable *ct,rgb_group rgb) { - struct map_entry *me,**eme,**beme,*feme; - int mindistance,best=0,i; + int i,best,di; if (ct->cache->index.r==rgb.r && ct->cache->index.g==rgb.g && ct->cache->index.b==rgb.b) return ct->cache->value; - feme=me=&(ct->map[QUANT_MAP_THISR(rgb.r)] - [QUANT_MAP_THISG(rgb.g)] - [QUANT_MAP_THISB(rgb.b)]); - -#ifdef QUANT_DEBUG_RGB - fprintf(stderr,"%d,%d,%d -> %lu %lu %lu: ",rgb.r,rgb.g,rgb.b, - QUANT_MAP_THISR(rgb.r), - QUANT_MAP_THISG(rgb.g), - QUANT_MAP_THISB(rgb.b)); - fprintf(stderr,"%lx %d,%d,%d %lu ",me,ct->clut[me->cl].r,ct->clut[me->cl].g,ct->clut[me->cl].b,me->cl); - if (!me->used) { fprintf(stderr,"unused "); } -#endif - if (!me->next) - { #ifdef QUANT_DEBUG_RGB - fprintf(stderr," -> %lu: %d,%d,%d\n",best, - ct->clut[best].r,ct->clut[best].g,ct->clut[best].b); +fprintf(stderr,"rgb: %d,%d,%d\n",rgb.r,rgb.g,rgb.b); #endif - return me->cl; - } + +#if QUANT_SELECT_CACHE>1 for (i=1; i<QUANT_SELECT_CACHE; i++) if (ct->cache[i].index.r==rgb.r && ct->cache[i].index.g==rgb.g && @@ -637,45 +689,81 @@ fprintf(stderr,"cache: %lu: %d,%d,%d\n",best,ct->clut[best].r,ct->clut[best].g,c #endif return best; } +#endif - mindistance=DISTANCE(rgb,ct->clut[me->cl]); - best=me->cl; - me=me->next; eme=&(me->next); beme=NULL; - while ( me && mindistance ) + /* find node */ + +#if 1 + + do { - int d; + rgb_group min={0,0,0},max={255,255,255}; + unsigned long *rn; + unsigned char split; + + rn=ct->rgb_node; + + for (;;) + { #ifdef QUANT_DEBUG_RGB -fprintf(stderr,"%lx %d,%d,%d ",me,ct->clut[me->cl].r,ct->clut[me->cl].g,ct->clut[me->cl].b); + fprintf(stderr,"-> %d: %c%d %d\n", + rn-ct->rgb_node, + (((*rn)>>30)==0)?'c': + (((*rn)>>30)==1)?'r': + (((*rn)>>30)==2)?'g':'b', + ((*rn)>>22) & 255, + ((*rn)&4194303)); #endif - d=DISTANCE(rgb,ct->clut[me->cl]); - if (d<mindistance) - { - mindistance=DISTANCE(rgb,ct->clut[me->cl]); - best=me->cl; - beme=eme; + + switch ((*rn)>>30) + { + case 0: /* end node */ break; + case 1: /* red */ + split=(unsigned char)( ((*rn)>>22) & 255 ); + rn=ct->rgb_node+((*rn)&4194303); + if (rgb.r<=split) max.r=split; + else rn++,min.r=split+1; + continue; + case 2: /* green */ + split=(unsigned char)( ((*rn)>>22) & 255 ); + rn=ct->rgb_node+((*rn)&4194303); + if (rgb.g<=split) max.g=split; + else rn++,min.g=split+1; + continue; + case 3: /* blue */ + split=(unsigned char)( ((*rn)>>22) & 255 ); + rn=ct->rgb_node+((*rn)&4194303); + if (rgb.b<=split) max.b=split; + else rn++,min.b=split+1; + continue; + } + break; } - eme=&(me->next); - me=me->next; - } - if (!mindistance && beme && *beme) /* exact match, place first */ - { - struct map_entry e; - e=*feme; - me=*beme; - *feme=*me; - *beme=me->next; - *me=e; - feme->next=me; - } - else /* place in cache */ - { - MEMMOVE(ct->cache+1,ct->cache, - (QUANT_SELECT_CACHE-1)*sizeof(struct rgb_cache)); - ct->cache[0].index=rgb; - ct->cache[0].value=best; - } + best=*rn; + } + while (0); + +#endif + +#if 0 + di=1000000L; + for (i=0; i<ct->numcol; i++) + if (DISTANCE(ct->clut[i],rgb)<di) + { + best=i; + di=DISTANCE(ct->clut[i],rgb); + } +#endif + + /* place in cache */ +#if QUANT_SELECT_CACHE>1 + MEMMOVE(ct->cache+1,ct->cache, + (QUANT_SELECT_CACHE-1)*sizeof(struct rgb_cache)); +#endif + ct->cache[0].index=rgb; + ct->cache[0].value=best; + #ifdef QUANT_DEBUG_RGB -fprintf(stderr,"%lx ",me); fprintf(stderr," -> %lu: %d,%d,%d\n",best, ct->clut[best].r,ct->clut[best].g,ct->clut[best].b); #endif @@ -685,20 +773,5 @@ fprintf(stderr," -> %lu: %d,%d,%d\n",best, void colortable_free(struct colortable *ct) { int r,g,b; - for (r=0; r<QUANT_MAP_REALR; r++) - { - for (g=0; g<QUANT_MAP_REALG; g++) - { - for (b=0; b<QUANT_MAP_REALB; b++) - { - struct map_entry *me; - while (me=ct->map[r][g][b].next) - { - ct->map[r][g][b].next=me->next; - free((char *)me); - } - } - } - } free((char *)ct); } -- GitLab