From: Tony Cook Date: Sat, 14 Apr 2012 04:06:07 +0000 (+1000) Subject: re-work sample down-conversion to rounding X-Git-Tag: v0.90~20 X-Git-Url: http://git.imager.perl.org/imager.git/commitdiff_plain/29b3867850824e719aa9c080faa1fa78f5cc881f re-work sample down-conversion to rounding --- diff --git a/Changes b/Changes index efaeee47..057f7c92 100644 --- 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 =========== diff --git a/imageri.h b/imageri.h index 9b07315b..347e2abd 100644 --- 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 *); diff --git a/t/t01introvert.t b/t/t01introvert.t index 02f5c638..542791c5 100644 --- a/t/t01introvert.t +++ b/t/t01introvert.t @@ -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 ]), diff --git a/t/t020masked.t b/t/t020masked.t index 7a3d7d84..a5200546 100644 --- a/t/t020masked.t +++ b/t/t020masked.t @@ -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"); } diff --git a/t/t022double.t b/t/t022double.t index e7d80e6d..05807715 100644 --- a/t/t022double.t +++ b/t/t022double.t @@ -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 ]), diff --git a/t/t023palette.t b/t/t023palette.t index a3c2ecfb..0a96b8f7 100644 --- a/t/t023palette.t +++ b/t/t023palette.t @@ -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 ]),