Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
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...
commit fe622da1a9411858f65f665bb33f4d065f01da97 1 parent 6353624
Tony Cook authored
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
27 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 {
View
16 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)
View
30 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<<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
Please sign in to comment.
Something went wrong with that request. Please try again.