add offset and width parameters to setsamples() for new psamp/psampf
authorTony Cook <tony@develop-help.com>
Tue, 14 Feb 2012 11:52:56 +0000 (22:52 +1100)
committerTony Cook <tony@develop-help.com>
Tue, 14 Feb 2012 11:52:56 +0000 (22:52 +1100)
Imager.pm
Imager.xs
t/t01introvert.t

index fa8578d..4b10bc0 100644 (file)
--- a/Imager.pm
+++ b/Imager.pm
@@ -3403,11 +3403,11 @@ sub setsamples {
   my $count;
   if ($type eq '8bit') {
     $count = i_psamp($self->{IMG}, $opts{x}, $opts{y}, $opts{channels},
-                    $data);
+                    $data, $opts{offset}, $width);
   }
   elsif ($type eq 'float') {
     $count = i_psampf($self->{IMG}, $opts{x}, $opts{y}, $opts{channels},
-                     $opts{data});
+                     $data, $opts{offset}, $width);
   }
   elsif ($type =~ /^([0-9]+)bit$/) {
     my $bits = $1;
@@ -3418,7 +3418,7 @@ sub setsamples {
     }
 
     $count = i_psamp_bits($self->{IMG}, $opts{x}, $opts{y}, $bits,
-                         $opts{channels}, $opts{data}, $opts{offset}, 
+                         $opts{channels}, $data, $opts{offset}, 
                          $width);
   }
   else {
index db1182e..c869f55 100644 (file)
--- a/Imager.xs
+++ b/Imager.xs
@@ -3300,8 +3300,8 @@ i_psamp_bits(im, l, y, bits, channels, data_av, data_offset = 0, pixel_count = -
        int bits
        i_channel_list channels
        AV *data_av
-        int data_offset
-        int pixel_count
+        i_img_dim data_offset
+        i_img_dim pixel_count
       PREINIT:
        STRLEN data_count;
        size_t data_used;
@@ -3312,7 +3312,7 @@ i_psamp_bits(im, l, y, bits, channels, data_av, data_offset = 0, pixel_count = -
 
        data_count = av_len(data_av) + 1;
        if (data_offset < 0) {
-         croak("data_offset must by non-negative");
+         croak("data_offset must be non-negative");
        }
        if (data_offset > data_count) {
          croak("data_offset greater than number of samples supplied");
@@ -3336,39 +3336,69 @@ i_psamp_bits(im, l, y, bits, channels, data_av, data_offset = 0, pixel_count = -
        RETVAL
 
 undef_neg_int
-i_psamp(im, x, y, channels, data)
+i_psamp(im, x, y, channels, data, offset = 0, width = -1)
        Imager::ImgRaw im
        i_img_dim x
        i_img_dim y
        i_channel_list channels
         i_sample_list data
+       i_img_dim offset
+       i_img_dim width
     PREINIT:
        i_img_dim r;
     CODE:
-       if (data.count % channels.count) {
-         croak("channel count and data sample counts don't match");
-       }
-       r = x + data.count / channels.count;
        i_clear_error();
+       if (offset < 0) {
+         i_push_error(0, "offset must be non-negative");
+         XSRETURN_UNDEF;
+       }
+       if (offset > 0) {
+         if (offset > data.count) {
+           i_push_error(0, "offset greater than number of samples supplied");
+           XSRETURN_UNDEF;
+         }
+         data.samples += offset;
+         data.count -= offset;
+       }
+       if (width == -1 ||
+           width * channels.count > data.count) {
+         width = data.count / channels.count;
+        }
+       r = x + width;
        RETVAL = i_psamp(im, x, r, y, data.samples, channels.channels, channels.count);
     OUTPUT:
        RETVAL
 
 undef_neg_int
-i_psampf(im, x, y, channels, data)
+i_psampf(im, x, y, channels, data, offset = 0, width = -1)
        Imager::ImgRaw im
        i_img_dim x
        i_img_dim y
        i_channel_list channels
         i_fsample_list data
+       i_img_dim offset
+       i_img_dim width
     PREINIT:
        i_img_dim r;
     CODE:
-       if (data.count % channels.count) {
-         croak("channel count and data sample counts don't match");
-       }
-       r = x + data.count / channels.count;
        i_clear_error();
+       if (offset < 0) {
+         i_push_error(0, "offset must be non-negative");
+         XSRETURN_UNDEF;
+       }
+       if (offset > 0) {
+         if (offset > data.count) {
+           i_push_error(0, "offset greater than number of samples supplied");
+           XSRETURN_UNDEF;
+         }
+         data.samples += offset;
+         data.count -= offset;
+       }
+       if (width == -1 ||
+           width * channels.count > data.count) {
+         width = data.count / channels.count;
+        }
+       r = x + width;
        RETVAL = i_psampf(im, x, r, y, data.samples, channels.channels, channels.count);
     OUTPUT:
        RETVAL
index e8d8bc3..2ba3d0d 100644 (file)
@@ -3,7 +3,7 @@
 # to make sure we get expected values
 
 use strict;
-use Test::More tests => 329;
+use Test::More tests => 345;
 
 BEGIN { use_ok(Imager => qw(:handy :all)) }
 
@@ -421,7 +421,7 @@ cmp_ok(Imager->errstr, '=~', qr/channels must be between 1 and 4/,
 my $psamp_outside_error = "Image position outside of image";
 { # psamp
   print "# psamp\n";
-  my $imraw = Imager::ImgRaw::new(10, 10, 3);
+  my $imraw = Imager::ImgRaw::new(10, 20, 3);
   {
     is(Imager::i_psamp($imraw, 0, 2, undef, [ 255, 128, 64 ]), 3,
        "i_psamp def channels, 3 samples");
@@ -451,6 +451,16 @@ my $psamp_outside_error = "Image position outside of image";
     is(Imager::i_psamp($imraw, 8, 8, [ 0, 1, 2 ],
                       [ 255, 128, 32, 64, 32, 16, 32, 16, 8 ]),
        6, "i_psamp channels [0, 1, 2], 9 samples, but room for 6");
+    is(Imager::i_psamp($imraw, 4, 6, undef, [ 0 .. 18 ], 1), 18,
+       "psamp with offset");
+    is_deeply([ Imager::i_gsamp($imraw, 0, 10, 6, undef) ],
+             [ (0) x 12, 1 .. 18 ],
+             "check result");
+    is(Imager::i_psamp($imraw, 4, 11, undef, [ 0 .. 18 ], 1, 3), 9,
+       "psamp with offset and width");
+    is_deeply([ Imager::i_gsamp($imraw, 0, 10, 11, undef) ],
+             [ (0) x 12, 1 .. 9, (0) x 9 ],
+             "check result");
   }
   { # errors we catch
     is(Imager::i_psamp($imraw, 6, 8, [ 0, 1, 3 ], [ 255, 128, 32 ]),
@@ -465,7 +475,7 @@ my $psamp_outside_error = "Image position outside of image";
        "negative y");
     is(_get_error(), $psamp_outside_error,
        "check error message");
-    is(Imager::i_psamp($imraw, 0, 10, undef, [ 0, 0, 0 ]), undef,
+    is(Imager::i_psamp($imraw, 0, 20, undef, [ 0, 0, 0 ]), undef,
        "y overflow");
     is(_get_error(), $psamp_outside_error,
        "check error message");
@@ -497,17 +507,22 @@ my $psamp_outside_error = "Image position outside of image";
         "check message");
 
     # not the typemap
-    ok(!eval { Imager::i_psamp($imraw, 9, 9, undef, [ 1 ]); 1 },
-       "sample count mod channel count non-zero");
-    like($@, qr/channel count and data sample counts don't match/,
-        "check message");
+    is(Imager::i_psamp($imraw, 0, 8, undef, [ (0) x 3 ], -1), undef,
+       "negative offset");
+    is(_get_error(), "offset must be non-negative",
+       "check message");
+
+    is(Imager::i_psamp($imraw, 0, 8, undef, [ (0) x 3 ], 4), undef,
+       "too high offset");
+    is(_get_error(), "offset greater than number of samples supplied",
+       "check message");
   }
   print "# end psamp tests\n";
 }
 
 { # psampf
   print "# psampf\n";
-  my $imraw = Imager::ImgRaw::new(10, 10, 3);
+  my $imraw = Imager::ImgRaw::new(10, 20, 3);
   {
     is(Imager::i_psampf($imraw, 0, 2, undef, [ 1, 0.5, 0.25 ]), 3,
        "i_psampf def channels, 3 samples");
@@ -537,6 +552,16 @@ my $psamp_outside_error = "Image position outside of image";
     is(Imager::i_psampf($imraw, 8, 8, [ 0, 1, 2 ],
                        [ 1.0, 0.5, 0.125, 0.25, 0.125, 0.0625, 0.125, 0, 1 ]),
        6, "i_psampf channels [0, 1, 2], 9 samples, but room for 6");
+    is(Imager::i_psampf($imraw, 4, 6, undef, [ map $_/254.9, 0 .. 18 ], 1), 18,
+       "psampf with offset");
+    is_deeply([ Imager::i_gsamp($imraw, 0, 10, 6, undef) ],
+             [ (0) x 12, 1 .. 18 ],
+             "check result");
+    is(Imager::i_psampf($imraw, 4, 11, undef, [ map $_/254.9, 0 .. 18 ], 1, 3), 9,
+       "psampf with offset and width");
+    is_deeply([ Imager::i_gsamp($imraw, 0, 10, 11, undef) ],
+             [ (0) x 12, 1 .. 9, (0) x 9 ],
+             "check result");
   }
   { # errors we catch
     is(Imager::i_psampf($imraw, 6, 8, [ 0, 1, 3 ], [ 1, 0.5, 0.125 ]),
@@ -551,7 +576,7 @@ my $psamp_outside_error = "Image position outside of image";
        "negative y");
     is(_get_error(), $psamp_outside_error,
        "check error message");
-    is(Imager::i_psampf($imraw, 0, 10, undef, [ 0, 0, 0 ]), undef,
+    is(Imager::i_psampf($imraw, 0, 20, undef, [ 0, 0, 0 ]), undef,
        "y overflow");
     is(_get_error(), $psamp_outside_error,
        "check error message");
@@ -583,10 +608,15 @@ my $psamp_outside_error = "Image position outside of image";
         "check message");
 
     # not the typemap
-    ok(!eval { Imager::i_psampf($imraw, 9, 9, undef, [ 1 ]); 1 },
-       "sample count mod channel count non-zero");
-    like($@, qr/channel count and data sample counts don't match/,
-        "check message");
+    is(Imager::i_psampf($imraw, 0, 8, undef, [ (0) x 3 ], -1), undef,
+       "negative offset");
+    is(_get_error(), "offset must be non-negative",
+       "check message");
+
+    is(Imager::i_psampf($imraw, 0, 8, undef, [ (0) x 3 ], 4), undef,
+       "too high offset");
+    is(_get_error(), "offset greater than number of samples supplied",
+       "check message");
   }
   print "# end psampf tests\n";
 }
@@ -776,6 +806,19 @@ my $psamp_outside_error = "Image position outside of image";
   is_deeply([ $im->getsamples(y => 5, x => 0) ],
            [ (0) x 9, 1 .. 6, (0) x 15 ], "check they were stored");
 
+  is($im->setsamples(y => 7, x => 3, data => [ 0 .. 18 ], offset => 1), 18,
+     "setsamples offset");
+  is_deeply([ $im->getsamples(y => 7) ],
+           [ (0) x 9, 1 .. 18, (0) x 3 ],
+           "check result");
+
+  is($im->setsamples(y => 8, x => 3, data => [ map $_ / 254.9, 0 .. 18 ],
+                    offset => 1, type => 'float'),
+     18, "setsamples offset (float)");
+  is_deeply([ $im->getsamples(y => 8) ],
+           [ (0) x 9, 1 .. 18, (0) x 3 ],
+           "check result");
+
   is_deeply([ $im->setsamples(y => 6, x => 10, data => [ (0) x 3 ]) ],
            [], "check out of range result (8bit)");
   is($im->errstr, $psamp_outside_error, "check error message");