From: Tony Cook Date: Fri, 24 Aug 2007 07:27:18 +0000 (+0000) Subject: Gabriel Vasseur's patch, corrected just enough for it to compile. X-Git-Tag: Imager-0.60~11 X-Git-Url: http://git.imager.perl.org/imager.git/commitdiff_plain/fe622da1a9411858f65f665bb33f4d065f01da97?ds=sidebyside Gabriel Vasseur's patch, corrected just enough for it to compile. This needs some cleanup: - integrate the extra tests supplied - test the method she didn't - foolproofing - documentation https://rt.cpan.org/Ticket/Display.html?id=28142 --- diff --git a/Imager.pm b/Imager.pm index 28a72bf9..065b29bd 100644 --- a/Imager.pm +++ b/Imager.pm @@ -3269,6 +3269,33 @@ sub getcolorcount { return ($rc==-1? undef : $rc); } +# Returns a reference to a hash. The keys are colour named (packed) and the +# values are the number of pixels in this colour. +sub getcolorusagehash { + my $self = shift; + my $channels= $self->getchannels; + # We don't want to look at the alpha channel, because some gifs using it + # doesn't define it for every colour (but only for some) + $channels -= 1 if $channels == 2 or $channels == 4; + my %colour_use; + my $height = $self->getheight; + for my $y (0 .. $height - 1) { + my $colours = $self->getsamples(y => $y, channels => [ 0 .. $channels - 1 ]); + while (length $colours) { + $colour_use{ substr($colours, 0, $channels, '') }++; + } + } + return \%colour_use; +} + +# This will return a ordered array of the colour usage. Kind of the sorted +# version of the values of the hash returned by getcolorusagehash. +# You might want to add safety checks and change the names, etc... +sub getcolorusage { + my $self=shift; + return get_anonymous_colour_usage ($self); +} + # draw string to an image sub string { diff --git a/Imager.xs b/Imager.xs index c44841c1..0ccba047 100644 --- a/Imager.xs +++ b/Imager.xs @@ -2972,6 +2972,22 @@ i_count_colors(im,maxc) Imager::ImgRaw im int maxc +void +get_anonymous_colour_usage(Imager::ImgRaw im) + PPCODE: + int i; + unsigned int ** col_usage = (unsigned int **) mymalloc(sizeof(unsigned int *)); + unsigned int * p; + int col_cnt = get_anonymous_color_histo(im, col_usage); + EXTEND(SP, col_cnt); + p = *col_usage; + for (i = 0; i < col_cnt; ) { + PUSHs(sv_2mortal(newSViv( p[i++]))); + } + myfree(p); + myfree(col_usage); + XSRETURN(col_cnt); + Imager::ImgRaw i_transform(im,opx,opy,parm) diff --git a/datatypes.c b/datatypes.c index 9c04b189..dfbf6a67 100644 --- a/datatypes.c +++ b/datatypes.c @@ -216,21 +216,22 @@ int octt_add(struct octt *ct,unsigned char r,unsigned char g,unsigned char b) { struct octt *c; int i,cm; - int ci,idx[8]; + int ci; int rc; rc=0; c=ct; /* printf("[r,g,b]=[%d,%d,%d]\n",r,g,b); */ - ct->cnt++; for(i=7;i>-1;i--) { cm=1<t[ci] == NULL) { c->t[ci]=octt_new(); rc=1; } + if (c->t[ci] == NULL) { + c->t[ci]=octt_new(); + rc=1; + } c=c->t[ci]; - c->cnt++; - idx[i]=ci; } + c->cnt++; /* New. The only thing really needed (I think) */ return rc; } @@ -267,3 +268,22 @@ octt_count(struct octt *ct,int *tot,int max,int *overflow) { if (!c) (*tot)++; if ( (*tot) > (*overflow) ) *overflow=0; } + +/* This whole function is new */ +/* walk through the tree and for each colour, store its seen count in the + space pointed by *col_usage_it_adr */ +void +octt_histo(struct octt *ct, unsigned int **col_usage_it_adr) { + int i,c; + c = 0; + for(i = 0; i < 8; i++) + if (ct->t[i] != NULL) { + octt_histo(ct->t[i], col_usage_it_adr); + c++; + } + if (!c) { + *(*col_usage_it_adr)++ = ct->cnt; + } +} + + diff --git a/image.c b/image.c index 4f21c161..dfef965b 100644 --- a/image.c +++ b/image.c @@ -1254,30 +1254,134 @@ to indicate that it was more than max colors =cut */ +/* This function has been changed and is now faster. It's using + * i_gsamp instead of i_gpix */ int i_count_colors(i_img *im,int maxc) { struct octt *ct; int x,y; - int xsize,ysize; - i_color val; int colorcnt; - - mm_log((1,"i_count_colors(im 0x%08X,maxc %d)\n")); - - xsize=im->xsize; - ysize=im->ysize; - ct=octt_new(); - - colorcnt=0; - for(y=0;y maxc) { octt_delete(ct); return -1; } + int channels[3]; + int *samp_chans; + i_sample_t * samp; + + int xsize = im->xsize; + int ysize = im->ysize; + if (im->channels >= 3) { + samp_chans = NULL; + } + else { + channels[0] = channels[1] = channels[2] = 0; + samp_chans = channels; } + int samp_cnt = 3 * xsize; + ct = octt_new(); + + samp = (i_sample_t *) mymalloc( xsize * 3 * sizeof(i_sample_t)); + + colorcnt = 0; + for(y = 0; y < ysize; ) { + i_gsamp(im, 0, xsize, y++, samp, samp_chans, 3); + for(x = 0; x < samp_cnt; ) { + colorcnt += octt_add(ct, samp[x], samp[x+1], samp[x+2]); + x += 3; + if (colorcnt > maxc) { + octt_delete(ct); + return -1; + } + } + } + myfree(samp); octt_delete(ct); return colorcnt; } +/* sorts the array ra[0..n-1] into increasing order using heapsort algorithm + * (adapted from the Numerical Recipes) + */ +/* Needed by get_anonymous_color_histo */ +void hpsort(unsigned int n, int *ra) { + unsigned int i, + ir, + j, + l, + rra; + + if (n < 2) return; + l = n >> 1; + ir = n - 1; + for(;;) { + if (l > 0) { + rra = ra[--l]; + } + else { + rra = ra[ir]; + ra[ir] = ra[0]; + if (--ir == 0) { + ra[0] = rra; + break; + } + } + i = l; + j = 2 * l + 1; + while (j <= ir) { + if (j < ir && ra[j] < ra[j+1]) j++; + if (rra < ra[j]) { + ra[i] = ra[j]; + i = j; + j++; j <<= 1; j--; + } + else break; + } + ra[i] = rra; + } +} + +/* This function constructs an ordered list which represents how much the + * different colors are used. So for instance (100, 100, 500) means that one + * color is used for 500 pixels, another for 100 pixels and another for 100 + * pixels. It's tuned for performance. You might not like the way I've hardcoded + * the maxc ;-) and you might want to change the name... */ +/* Uses octt_histo */ +int +get_anonymous_color_histo(i_img *im, unsigned int **col_usage) { + struct octt *ct; + int x,y,i; + int colorcnt; + int maxc = 10000000; + unsigned int *col_usage_it; + i_sample_t * samp; + + int xsize = im->xsize; + int ysize = im->ysize; + int samp_cnt = 3 * xsize; + ct = octt_new(); + + samp = (i_sample_t *) mymalloc( xsize * 3 * sizeof(i_sample_t)); + + colorcnt = 0; + for(y = 0; y < ysize; ) { + i_gsamp(im, 0, xsize, y++, samp, NULL, 3); + for(x = 0; x < samp_cnt; ) { + colorcnt += octt_add(ct, samp[x], samp[x+1], samp[x+2]); + x += 3; + if (colorcnt > maxc) { + octt_delete(ct); + return -1; + } + } + } + myfree(samp); + /* Now that we know the number of colours... */ + col_usage_it = *col_usage = (unsigned int *) mymalloc(colorcnt * 2 * sizeof(unsigned int)); + octt_histo(ct, &col_usage_it); + hpsort(colorcnt, *col_usage); + octt_delete(ct); + return colorcnt; +} + + + /* =back