re-work sample down-conversion to rounding
authorTony Cook <tony@develop-help.com>
Sat, 14 Apr 2012 04:06:07 +0000 (14:06 +1000)
committerTony Cook <tony@develop-help.com>
Sat, 14 Apr 2012 04:06:07 +0000 (14:06 +1000)
Changes
imageri.h
t/t01introvert.t
t/t020masked.t
t/t022double.t
t/t023palette.t

diff --git a/Changes b/Changes
index efaeee4..057f7c9 100644 (file)
--- a/Changes
+++ b/Changes
@@ -9,6 +9,14 @@ Bug fixes:
    parameter but the prototype didn't allow for the extra parameter.
    Corrected the prototype.
 
+ - when downconverting samples (eg. from floating point to 8 bit)
+   Imager now rounds the sample value rather than attempting to
+   allocate input values over output values equally.  The old
+   behaviour had the probably surprising effect of converting a
+   floating point 2.1/255.0 into an 8-bit 3 rather than the expected
+   2.
+   This may result in slightly different 8 or 16-bit output images.
+
 Imager 0.89 - 18 Mar 2012
 ===========
 
index 9b07315..347e2ab 100644 (file)
--- a/imageri.h
+++ b/imageri.h
@@ -34,14 +34,14 @@ extern int i_setcolors_forward(i_img *im, int index, const i_color *colors,
 extern i_img_dim i_gsamp_bits_fb(i_img *im, i_img_dim x, i_img_dim r, i_img_dim y, unsigned *samp, 
                           const int *chans, int chan_count, int bits);
 
-#define SampleFTo16(num) ((int)((num) * 65535.0 + 0.01))
+#define SampleFTo16(num) ((int)((num) * 65535.0 + 0.5))
 /* we add that little bit to avoid rounding issues */
 #define Sample16ToF(num) ((num) / 65535.0)
 
-#define SampleFTo8(num) ((int)((num) * 255.0 + 0.01))
+#define SampleFTo8(num) ((int)((num) * 255.0 + 0.5))
 #define Sample8ToF(num) ((num) / 255.0)
 
-#define Sample16To8(num) ((num) / 257)
+#define Sample16To8(num) (((num)+128) / 257)
 #define Sample8To16(num) ((num) * 257)
 
 extern void i_get_combine(int combine, i_fill_combine_f *, i_fill_combinef_f *);
index 02f5c63..542791c 100644 (file)
@@ -526,28 +526,28 @@ my $psamp_outside_error = "Image position outside of image";
   {
     is(Imager::i_psampf($imraw, 0, 2, undef, [ 1, 0.5, 0.25 ]), 3,
        "i_psampf def channels, 3 samples");
-    is_color3(Imager::i_get_pixel($imraw, 0, 2), 255, 127, 63,
+    is_color3(Imager::i_get_pixel($imraw, 0, 2), 255, 128, 64,
              "check color written");
     Imager::i_img_setmask($imraw, 5);
     is(Imager::i_psampf($imraw, 1, 3, undef, [ 0.25, 0.5, 0.75 ]), 3,
        "i_psampf def channels, 3 samples, masked");
-    is_color3(Imager::i_get_pixel($imraw, 1, 3), 63, 0, 191,
+    is_color3(Imager::i_get_pixel($imraw, 1, 3), 64, 0, 191,
              "check color written");
     is(Imager::i_psampf($imraw, 1, 7, [ 0, 1, 2 ], [ 0.25, 0.5, 0.75 ]), 3,
        "i_psampf channels listed, 3 samples, masked");
-    is_color3(Imager::i_get_pixel($imraw, 1, 7), 63, 0, 191,
+    is_color3(Imager::i_get_pixel($imraw, 1, 7), 64, 0, 191,
              "check color written");
     Imager::i_img_setmask($imraw, ~0);
     is(Imager::i_psampf($imraw, 2, 4, [ 0, 1 ], [ 1, 0.5, 0.25, 0.125 ]), 4,
        "i_psampf channels [0, 1], 4 samples");
-    is_color3(Imager::i_get_pixel($imraw, 2, 4), 255, 127, 0,
+    is_color3(Imager::i_get_pixel($imraw, 2, 4), 255, 128, 0,
              "check first color written");
-    is_color3(Imager::i_get_pixel($imraw, 3, 4), 63, 31, 0,
+    is_color3(Imager::i_get_pixel($imraw, 3, 4), 64, 32, 0,
              "check second color written");
     is(Imager::i_psampf($imraw, 0, 5, [ 0, 1, 2 ], [ (0.5, 0.25, 0.125) x 10 ]), 30,
        "write a full row");
     is_deeply([ Imager::i_gsamp($imraw, 0, 10, 5, [ 0, 1, 2 ]) ],
-             [ (127, 63, 31) x 10 ],
+             [ (128, 64, 32) x 10 ],
              "check full row");
     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 ]),
index 7a3d7d8..a520054 100644 (file)
@@ -609,28 +609,28 @@ for my $masked (0, 1) { # psampf
   {
     is(Imager::i_psampf($imraw, 0, 2, undef, [ 1, 0.5, 0.25 ]), 3,
        "i_psampf def channels, 3 samples");
-    is_color3(Imager::i_get_pixel($imraw, 0, 2), 255, 127, 63,
+    is_color3(Imager::i_get_pixel($imraw, 0, 2), 255, 128, 64,
              "check color written");
     Imager::i_img_setmask($imraw, 5);
     is(Imager::i_psampf($imraw, 1, 3, undef, [ 0.25, 0.5, 0.75 ]), 3,
        "i_psampf def channels, 3 samples, masked");
-    is_color3(Imager::i_get_pixel($imraw, 1, 3), 63, 0, 191,
+    is_color3(Imager::i_get_pixel($imraw, 1, 3), 64, 0, 191,
              "check color written");
     is(Imager::i_psampf($imraw, 1, 7, [ 0, 1, 2 ], [ 0.25, 0.5, 0.75 ]), 3,
        "i_psampf channels listed, 3 samples, masked");
-    is_color3(Imager::i_get_pixel($imraw, 1, 7), 63, 0, 191,
+    is_color3(Imager::i_get_pixel($imraw, 1, 7), 64, 0, 191,
              "check color written");
     Imager::i_img_setmask($imraw, ~0);
     is(Imager::i_psampf($imraw, 2, 4, [ 0, 1 ], [ 1, 0.5, 0.25, 0.125 ]), 4,
        "i_psampf channels [0, 1], 4 samples");
-    is_color3(Imager::i_get_pixel($imraw, 2, 4), 255, 127, 0,
+    is_color3(Imager::i_get_pixel($imraw, 2, 4), 255, 128, 0,
              "check first color written");
-    is_color3(Imager::i_get_pixel($imraw, 3, 4), 63, 31, 0,
+    is_color3(Imager::i_get_pixel($imraw, 3, 4), 64, 32, 0,
              "check second color written");
     is(Imager::i_psampf($imraw, 0, 5, [ 0, 1, 2 ], [ (0.5, 0.25, 0.125) x 10 ]), 30,
        "write a full row");
     is_deeply([ Imager::i_gsamp($imraw, 0, 10, 5, [ 0, 1, 2 ]) ],
-             [ (127, 63, 31) x 10 ],
+             [ (128, 64, 32) x 10 ],
              "check full row");
     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 ]),
@@ -680,9 +680,9 @@ for my $masked (0, 1) { # psampf
      "psampf() to masked image");
   is_deeply([ Imager::i_gsamp($base, 0, 20, 6, undef) ],
            [ ( 0, 0, 0 ) x 3, # left of mask
-             ( 0, 127, 255 ) x 4, # masked area
+             ( 0, 128, 255 ) x 4, # masked area
              ( 0, 0, 0 ) x 3, # unmasked area
-             ( 0, 127, 255 ) x 3, # masked area
+             ( 0, 128, 255 ) x 3, # masked area
              ( 0, 0, 0 ) x 7 ], # right of mask
            "check values written");
 }
index e7d80e6..0580771 100644 (file)
@@ -234,28 +234,28 @@ my $psamp_outside_error = "Image position outside of image";
   {
     is(Imager::i_psampf($imraw, 0, 2, undef, [ 1, 0.5, 0.25 ]), 3,
        "i_psampf def channels, 3 samples");
-    is_color3(Imager::i_get_pixel($imraw, 0, 2), 255, 127, 63,
+    is_color3(Imager::i_get_pixel($imraw, 0, 2), 255, 128, 64,
              "check color written");
     Imager::i_img_setmask($imraw, 5);
     is(Imager::i_psampf($imraw, 1, 3, undef, [ 0.25, 0.5, 0.75 ]), 3,
        "i_psampf def channels, 3 samples, masked");
-    is_color3(Imager::i_get_pixel($imraw, 1, 3), 63, 0, 191,
+    is_color3(Imager::i_get_pixel($imraw, 1, 3), 64, 0, 191,
              "check color written");
     is(Imager::i_psampf($imraw, 1, 7, [ 0, 1, 2 ], [ 0.25, 0.5, 0.75 ]), 3,
        "i_psampf channels listed, 3 samples, masked");
-    is_color3(Imager::i_get_pixel($imraw, 1, 7), 63, 0, 191,
+    is_color3(Imager::i_get_pixel($imraw, 1, 7), 64, 0, 191,
              "check color written");
     Imager::i_img_setmask($imraw, ~0);
     is(Imager::i_psampf($imraw, 2, 4, [ 0, 1 ], [ 1, 0.5, 0.25, 0.125 ]), 4,
        "i_psampf channels [0, 1], 4 samples");
-    is_color3(Imager::i_get_pixel($imraw, 2, 4), 255, 127, 0,
+    is_color3(Imager::i_get_pixel($imraw, 2, 4), 255, 128, 0,
              "check first color written");
-    is_color3(Imager::i_get_pixel($imraw, 3, 4), 63, 31, 0,
+    is_color3(Imager::i_get_pixel($imraw, 3, 4), 64, 32, 0,
              "check second color written");
     is(Imager::i_psampf($imraw, 0, 5, [ 0, 1, 2 ], [ (0.5, 0.25, 0.125) x 10 ]), 30,
        "write a full row");
     is_deeply([ Imager::i_gsamp($imraw, 0, 10, 5, [ 0, 1, 2 ]) ],
-             [ (127, 63, 31) x 10 ],
+             [ (128, 64, 32) x 10 ],
              "check full row");
     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 ]),
index a3c2ecf..0a96b8f 100644 (file)
@@ -511,37 +511,37 @@ my $psamp_outside_error = "Image position outside of image";
   my $imraw = Imager::i_img_pal_new(10, 10, 3, 255);
   my @colors =
     (
-     NC(0, 0, 0), NC(255, 127, 63), NC(64, 128, 192),
-     NC(63, 0, 191), NC(255, 127, 0), NC(63, 31, 0),
-     NC(127, 63, 31), NC(255, 127, 31), NC(63, 31, 15),
+     NC(0, 0, 0), NC(255, 128, 64), NC(64, 128, 192),
+     NC(64, 0, 191), NC(255, 128, 0), NC(64, 32, 0),
+     NC(128, 64, 32), NC(255, 128, 32), NC(64, 32, 16),
     );
   is(Imager::i_addcolors($imraw, @colors), "0 but true",
      "add colors needed for testing");
   {
     is(Imager::i_psampf($imraw, 0, 2, undef, [ 1, 0.5, 0.25 ]), 3,
        "i_psampf def channels, 3 samples");
-    is_color3(Imager::i_get_pixel($imraw, 0, 2), 255, 127, 63,
+    is_color3(Imager::i_get_pixel($imraw, 0, 2), 255, 128, 64,
              "check color written");
     Imager::i_img_setmask($imraw, 5);
     is(Imager::i_psampf($imraw, 1, 3, undef, [ 0.25, 0.5, 0.75 ]), 3,
        "i_psampf def channels, 3 samples, masked");
-    is_color3(Imager::i_get_pixel($imraw, 1, 3), 63, 0, 191,
+    is_color3(Imager::i_get_pixel($imraw, 1, 3), 64, 0, 191,
              "check color written");
     is(Imager::i_psampf($imraw, 1, 7, [ 0, 1, 2 ], [ 0.25, 0.5, 0.75 ]), 3,
        "i_psampf channels listed, 3 samples, masked");
-    is_color3(Imager::i_get_pixel($imraw, 1, 7), 63, 0, 191,
+    is_color3(Imager::i_get_pixel($imraw, 1, 7), 64, 0, 191,
              "check color written");
     Imager::i_img_setmask($imraw, ~0);
     is(Imager::i_psampf($imraw, 2, 4, [ 0, 1 ], [ 1, 0.5, 0.25, 0.125 ]), 4,
        "i_psampf channels [0, 1], 4 samples");
-    is_color3(Imager::i_get_pixel($imraw, 2, 4), 255, 127, 0,
+    is_color3(Imager::i_get_pixel($imraw, 2, 4), 255, 128, 0,
              "check first color written");
-    is_color3(Imager::i_get_pixel($imraw, 3, 4), 63, 31, 0,
+    is_color3(Imager::i_get_pixel($imraw, 3, 4), 64, 32, 0,
              "check second color written");
     is(Imager::i_psampf($imraw, 0, 5, [ 0, 1, 2 ], [ (0.5, 0.25, 0.125) x 10 ]), 30,
        "write a full row");
     is_deeply([ Imager::i_gsamp($imraw, 0, 10, 5, [ 0, 1, 2 ]) ],
-             [ (127, 63, 31) x 10 ],
+             [ (128, 64, 32) x 10 ],
              "check full row");
     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 ]),