Permalink
Browse files

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
  • Loading branch information...
1 parent 6353624 commit fe622da1a9411858f65f665bb33f4d065f01da97 Tony Cook committed Aug 24, 2007
Showing with 186 additions and 19 deletions.
  1. +27 −0 Imager.pm
  2. +16 −0 Imager.xs
  3. +25 −5 datatypes.c
  4. +118 −14 image.c
View
@@ -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 {
View
@@ -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)
View
@@ -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<<i;
ci=((!!(r&cm))<<2)+((!!(g&cm))<<1)+!!(b&cm);
/* printf("idx[%d]=%d\n",i,ci); */
- if (c->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;
+ }
+}
+
+
View
132 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<ysize;y++) for(x=0;x<xsize;x++) {
- i_gpix(im,x,y,&val);
- colorcnt+=octt_add(ct,val.rgb.r,val.rgb.g,val.rgb.b);
- if (colorcnt > 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

0 comments on commit fe622da

Please sign in to comment.