optimize filled box drawing
authorTony Cook <tony@develop=help.com>
Sun, 5 Sep 2010 06:45:57 +0000 (06:45 +0000)
committerTony Cook <tony@develop=help.com>
Sun, 5 Sep 2010 06:45:57 +0000 (06:45 +0000)
Imager.pm
Imager.xs
bench/box.pl
draw.c
t/t01introvert.t

index a42a618..e8ec815 100644 (file)
--- a/Imager.pm
+++ b/Imager.pm
@@ -2651,14 +2651,27 @@ sub i_color_set {
 # Draws a box between the specified corner points.
 sub box {
   my $self=shift;
-  unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
-  my %opts=(xmin=>0,ymin=>0,xmax=>$self->getwidth()-1,ymax=>$self->getheight()-1,@_);
+  my $raw = $self->{IMG};
+
+  unless ($raw) {
+    $self->{ERRSTR}='empty input image';
+    return undef;
+  }
+
+  my %opts = @_;
 
+  my ($xmin, $ymin, $xmax, $ymax);
   if (exists $opts{'box'}) { 
-    $opts{'xmin'} = _min($opts{'box'}->[0],$opts{'box'}->[2]);
-    $opts{'xmax'} = _max($opts{'box'}->[0],$opts{'box'}->[2]);
-    $opts{'ymin'} = _min($opts{'box'}->[1],$opts{'box'}->[3]);
-    $opts{'ymax'} = _max($opts{'box'}->[1],$opts{'box'}->[3]);
+    $xmin = _min($opts{'box'}->[0],$opts{'box'}->[2]);
+    $xmax = _max($opts{'box'}->[0],$opts{'box'}->[2]);
+    $ymin = _min($opts{'box'}->[1],$opts{'box'}->[3]);
+    $ymax = _max($opts{'box'}->[1],$opts{'box'}->[3]);
+  }
+  else {
+    defined($xmin = $opts{xmin}) or $xmin = 0;
+    defined($xmax = $opts{xmax}) or $xmax = $self->getwidth()-1;
+    defined($ymin = $opts{ymin}) or $ymin = 0;
+    defined($ymax = $opts{ymax}) or $ymax = $self->getheight()-1;
   }
 
   if ($opts{filled}) { 
@@ -2679,8 +2692,7 @@ sub box {
       $color = i_color_new(255,255,255,255);
     }
 
-    i_box_filled($self->{IMG},$opts{xmin},$opts{ymin},$opts{xmax},
-                 $opts{ymax}, $color);
+    i_box_filled($raw, $xmin, $ymin,$xmax, $ymax, $color);
   }
   elsif ($opts{fill}) {
     unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
@@ -2691,8 +2703,7 @@ sub box {
         return undef;
       }
     }
-    i_box_cfill($self->{IMG},$opts{xmin},$opts{ymin},$opts{xmax},
-                $opts{ymax},$opts{fill}{fill});
+    i_box_cfill($raw, $xmin, $ymin, $xmax, $ymax, $opts{fill}{fill});
   }
   else {
     my $color = $opts{'color'};
@@ -2714,9 +2725,9 @@ sub box {
       $self->{ERRSTR} = $Imager::ERRSTR;
       return;
     }
-    i_box($self->{IMG},$opts{xmin},$opts{ymin},$opts{xmax},$opts{ymax},
-          $color);
+    i_box($raw, $xmin, $ymin, $xmax, $ymax, $color);
   }
+
   return $self;
 }
 
@@ -3520,16 +3531,26 @@ sub border {
 
 sub getwidth {
   my $self = shift;
-  if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
-  return (i_img_info($self->{IMG}))[0];
+
+  if (my $raw = $self->{IMG}) {
+    return i_img_get_width($raw);
+  }
+  else {
+    $self->{ERRSTR} = 'image is empty'; return undef;
+  }
 }
 
 # Get the height of an image
 
 sub getheight {
   my $self = shift;
-  if (!defined($self->{IMG})) { $self->{ERRSTR} = 'image is empty'; return undef; }
-  return (i_img_info($self->{IMG}))[1];
+
+  if (my $raw = $self->{IMG}) {
+    return i_img_get_height($raw);
+  }
+  else {
+    $self->{ERRSTR} = 'image is empty'; return undef;
+  }
 }
 
 # Get number of channels in an image
index 696eebf..31f0e3a 100644 (file)
--- a/Imager.xs
+++ b/Imager.xs
@@ -951,6 +951,9 @@ static im_pl_ext_funcs im_perl_funcs =
 /* trying to use more C style names, map them here */
 #define i_io_DESTROY(ig) io_glue_destroy(ig)
 
+#define i_img_get_width(im) ((im)->xsize)
+#define i_img_get_height(im) ((im)->ysize)
+
 MODULE = Imager                PACKAGE = Imager::Color PREFIX = ICL_
 
 Imager::Color
@@ -1384,6 +1387,15 @@ i_img_getdata(im)
                     sv_2mortal(newSVpv((char *)im->idata, im->bytes)) 
                     : &PL_sv_undef);
 
+IV
+i_img_get_width(im)
+    Imager::ImgRaw     im
+
+IV
+i_img_get_height(im)
+    Imager::ImgRaw     im
+
+
 void
 i_img_is_monochrome(im)
        Imager::ImgRaw im
index 611a9fc..19e5373 100644 (file)
@@ -156,3 +156,72 @@ palbox0010: 740.9 /s (0.001350 / iter)
 palbox0100: 473.2 /s (0.002113 / iter)
 palbox0500: 186.2 /s (0.005371 / iter)
 palbox1000: 109.1 /s (0.009167 / iter)
+
+re-work i_box_filled():
+
+box0010: 783.0 /s (0.001277 / iter)
+box0010c: 3.3 /s (0.300588 / iter)
+box0010d: 463.7 /s (0.002157 / iter)
+box0100: 548.2 /s (0.001824 / iter)
+box0500: 250.2 /s (0.003997 / iter)
+box1000: 155.1 /s (0.006448 / iter)
+fbox0010: 743.7 /s (0.001345 / iter)
+fbox0010c: 3.3 /s (0.302941 / iter)
+fbox0010d: 448.3 /s (0.002231 / iter)
+fbox0100: 147.8 /s (0.006765 / iter)
+fbox0500: 7.6 /s (0.132308 / iter)
+fbox1000: 1.9 /s (0.521000 / iter)
+fpalbox0010: 784.9 /s (0.001274 / iter)
+fpalbox0100: 424.7 /s (0.002355 / iter)
+fpalbox0500: 42.6 /s (0.023496 / iter)
+fpalbox1000: 11.4 /s (0.087966 / iter)
+palbox0010: 778.8 /s (0.001284 / iter)
+palbox0100: 541.5 /s (0.001847 / iter)
+palbox0500: 238.0 /s (0.004203 / iter)
+palbox1000: 141.1 /s (0.007088 / iter)
+
+optimize getwidth/getheight:
+
+box0010: 832.5 /s (0.001201 / iter)
+box0010c: 3.4 /s (0.297647 / iter)
+box0010d: 491.3 /s (0.002035 / iter)
+box0100: 594.7 /s (0.001682 / iter)
+box0500: 259.1 /s (0.003859 / iter)
+box1000: 158.5 /s (0.006310 / iter)
+fbox0010: 798.1 /s (0.001253 / iter)
+fbox0010c: 3.3 /s (0.300588 / iter)
+fbox0010d: 477.7 /s (0.002093 / iter)
+fbox0100: 148.5 /s (0.006735 / iter)
+fbox0500: 7.5 /s (0.134103 / iter)
+fbox1000: 1.9 /s (0.530000 / iter)
+fpalbox0010: 829.0 /s (0.001206 / iter)
+fpalbox0100: 444.1 /s (0.002252 / iter)
+fpalbox0500: 43.0 /s (0.023260 / iter)
+fpalbox1000: 11.5 /s (0.087333 / iter)
+palbox0010: 826.0 /s (0.001211 / iter)
+palbox0100: 553.2 /s (0.001808 / iter)
+palbox0500: 242.7 /s (0.004119 / iter)
+palbox1000: 144.4 /s (0.006923 / iter)
+
+pull stuff out of the hash fast:
+
+box0010: 1332.0 /s (0.000751 / iter)
+box0010c: 3.4 /s (0.295882 / iter)
+box0010d: 646.6 /s (0.001546 / iter)
+box0100: 805.3 /s (0.001242 / iter)
+box0500: 293.1 /s (0.003412 / iter)
+box1000: 161.7 /s (0.006183 / iter)
+fbox0010: 1215.2 /s (0.000823 / iter)
+fbox0010c: 3.4 /s (0.295294 / iter)
+fbox0010d: 600.9 /s (0.001664 / iter)
+fbox0100: 160.2 /s (0.006241 / iter)
+fbox0500: 7.6 /s (0.131250 / iter)
+fbox1000: 1.9 /s (0.519000 / iter)
+fpalbox0010: 1295.2 /s (0.000772 / iter)
+fpalbox0100: 547.2 /s (0.001828 / iter)
+fpalbox0500: 43.8 /s (0.022845 / iter)
+fpalbox1000: 11.5 /s (0.087333 / iter)
+palbox0010: 1314.1 /s (0.000761 / iter)
+palbox0100: 752.2 /s (0.001330 / iter)
+palbox0500: 269.4 /s (0.003712 / iter)
+palbox1000: 145.3 /s (0.006884 / iter)
diff --git a/draw.c b/draw.c
index 240d22c..93ae7ab 100644 (file)
--- a/draw.c
+++ b/draw.c
@@ -1076,9 +1076,50 @@ Fills the box from (x1,y1) to (x2,y2) inclusive with color.
 
 void
 i_box_filled(i_img *im,int x1,int y1,int x2,int y2, const i_color *val) {
-  int x,y;
+  i_img_dim x, y, width;
+  i_palidx index;
+
   mm_log((1,"i_box_filled(im* 0x%x,x1 %d,y1 %d,x2 %d,y2 %d,val 0x%x)\n",im,x1,y1,x2,y2,val));
-  for(x=x1;x<x2+1;x++) for (y=y1;y<y2+1;y++) i_ppix(im,x,y,val);
+
+  if (x1 > x2 || y1 > y2
+      || x2 < 0 || y2 < 0
+      || x1 >= im->xsize || y1 > im->ysize)
+    return;
+
+  if (x1 < 0)
+    x1 = 0;
+  if (x2 >= im->xsize)
+    x2 = im->xsize - 1;
+  if (y1 < 0)
+    y1 = 0;
+  if (y2 >= im->ysize)
+    y2 = im->ysize - 1;
+
+  width = x2 - x1 + 1;
+
+  if (im->type == i_palette_type
+      && i_findcolor(im, val, &index)) {
+    i_palidx *line = mymalloc(sizeof(i_palidx) * width);
+
+    for (x = 0; x < width; ++x)
+      line[x] = index;
+
+    for (y = y1; y <= y2; ++y)
+      i_ppal(im, x1, x2+1, y, line);
+
+    myfree(line);
+  }
+  else {
+    i_color *line = mymalloc(sizeof(i_color) * width);
+
+    for (x = 0; x < width; ++x)
+      line[x] = *val;
+
+    for (y = y1; y <= y2; ++y)
+      i_plin(im, x1, x2+1, y, line);
+
+    myfree(line);
+  }
 }
 
 /*
index 85d3792..c0f3baf 100644 (file)
@@ -3,7 +3,7 @@
 # to make sure we get expected values
 
 use strict;
-use Test::More tests => 220;
+use Test::More tests => 224;
 
 BEGIN { use_ok(Imager => qw(:handy :all)) }
 
@@ -28,6 +28,8 @@ ok(Imager::i_img_getmask($im_g) & 1, "1 channel image mask");
 ok(!Imager::i_img_virtual($im_g), "1 channel image not virtual");
 is(Imager::i_img_bits($im_g), 8, "1 channel image has 8 bits/sample");
 is(Imager::i_img_type($im_g), 0, "1 channel image is direct");
+is(Imager::i_img_get_width($im_g), 100, "100 pixels wide");
+is(Imager::i_img_get_height($im_g), 101, "101 pixels high");
 
 my @ginfo = Imager::i_img_info($im_g);
 is($ginfo[0], 100, "1 channel image width");
@@ -120,6 +122,8 @@ ok($impal2, "make paletted via OO");
 is($impal2->getchannels, 3, "check channels");
 is($impal2->bits, 8, "check bits");
 is($impal2->type, 'paletted', "check type");
+is($impal2->getwidth, 200, "check width");
+is($impal2->getheight, 201, "check height");
 
 {
   my $red_idx = $impal2->addcolors(colors=>[$red]);