[rt #71564] fix i_render_color() to work in normal mode
authorTony Cook <tony@develop-help.com>
Sat, 10 Dec 2011 03:05:21 +0000 (14:05 +1100)
committerTony Cook <tony@develop-help.com>
Tue, 3 Jan 2012 04:55:54 +0000 (15:55 +1100)
Previously it ignored the color alpha channel when drawing on a 1 or 3
channel image.

render.im
t/t35ttfont.t
t/t82inline.t

index 4f9bbd3..947dcb2 100644 (file)
--- a/render.im
+++ b/render.im
@@ -485,6 +485,7 @@ IM_SUFFIX(render_color_13)(i_render *r, i_img_dim x, i_img_dim y,
   IM_COLOR *linep = r->IM_SUFFIX(line);
   int ch, channels = im->channels;
   i_img_dim fetch_offset;
+  int color_alpha = color->channel[im->channels];
 #undef STORE_COLOR
 #ifdef IM_EIGHT_BIT
 #define STORE_COLOR (*color)
@@ -498,17 +499,19 @@ IM_SUFFIX(render_color_13)(i_render *r, i_img_dim x, i_img_dim y,
 #endif
  
   fetch_offset = 0;
-  while (fetch_offset < width && *src == 0xFF) {
-    *linep++ = STORE_COLOR;
-    ++src;
-    ++fetch_offset;
+  if (color_alpha == 0xFF) {
+    while (fetch_offset < width && *src == 0xFF) {
+      *linep++ = STORE_COLOR;
+      ++src;
+      ++fetch_offset;
+    }
   }
   IM_GLIN(im, x+fetch_offset, x+width, y, linep);
   while (fetch_offset < width) {
 #ifdef IM_EIGHT_BIT
-    IM_WORK_T alpha = *src++;
+    IM_WORK_T alpha = *src++ * color_alpha / 255;
 #else
-    IM_WORK_T alpha = *src++ / 255.0;
+    IM_WORK_T alpha = *src++ * color_alpha / (255.0 * 255.0);
 #endif
     if (alpha == IM_SAMPLE_MAX)
       *linep = STORE_COLOR;
@@ -533,6 +536,7 @@ IM_SUFFIX(render_color_alpha)(i_render *r, i_img_dim x, i_img_dim y,
   int ch;
   int alpha_channel = r->im->channels - 1;
   i_img_dim fetch_offset;
+  int color_alpha = color->channel[alpha_channel];
 #undef STORE_COLOR
 #ifdef IM_EIGHT_BIT
 #define STORE_COLOR (*color)
@@ -546,17 +550,19 @@ IM_SUFFIX(render_color_alpha)(i_render *r, i_img_dim x, i_img_dim y,
 #endif
 
   fetch_offset = 0;
-  while (fetch_offset < width && *src == 0xFF) {
-    *linep++ = STORE_COLOR;
-    ++src;
-    ++fetch_offset;
+  if (color->channel[alpha_channel] == 0xFF) {
+    while (fetch_offset < width && *src == 0xFF) {
+      *linep++ = STORE_COLOR;
+      ++src;
+      ++fetch_offset;
+    }
   }
   IM_GLIN(r->im, x+fetch_offset, x+width, y, linep);
   while (fetch_offset < width) {
 #ifdef IM_EIGHT_BIT
-    IM_WORK_T src_alpha = *src++;
+    IM_WORK_T src_alpha = *src++ * color_alpha / 255;
 #else
-    IM_WORK_T src_alpha = *src++ / 255.0;
+    IM_WORK_T src_alpha = *src++ * color_alpha / (255.0 * 255.0);
 #endif
     if (src_alpha == IM_SAMPLE_MAX)
       *linep = STORE_COLOR;
index 42234fa..27c6a42 100644 (file)
@@ -1,11 +1,11 @@
 #!perl -w
 use strict;
-use Test::More tests => 92;
+use Test::More tests => 97;
 
 $|=1;
 
 BEGIN { use_ok(Imager => ':all') }
-use Imager::Test qw(diff_text_with_nul is_color3);
+use Imager::Test qw(diff_text_with_nul is_color3 is_image);
 
 -d "testout" or mkdir "testout";
 
@@ -13,7 +13,7 @@ init_log("testout/t35ttfont.log",2);
 
 SKIP:
 {
-  skip("freetype 1.x unavailable or disabled", 91
+  skip("freetype 1.x unavailable or disabled", 96
     unless $Imager::formats{"tt"};
   print "# has tt\n";
   
@@ -304,5 +304,31 @@ SKIP:
     is_color3($colors[1], 255, 0, 0, "and red");
   }
 
+ SKIP:
+  { # RT 71564
+    my $noalpha = Imager::Color->new(255, 255, 255, 0);
+    my $font = Imager::Font->new(file=>'fontfiles/ImUgly.ttf', type=>'tt',
+                                color => $noalpha);
+    ok($font, "loaded fontfiles/ImUgly.ttf")
+      or skip("Could not load test font: ".Imager->errstr, 4);
+    {
+      my $im = Imager->new(xsize => 40, ysize => 20);
+      my $copy = $im->copy;
+      ok($im->string(string => "AB", size => 20, aa => 1,
+                    x => 0, y => 15, font => $font),
+        "draw with transparent color, aa");
+      is_image($im, $copy, "should draw nothing");
+    }
+    {
+      my $im = Imager->new(xsize => 40, ysize => 20);
+      my $copy = $im->copy;
+      ok($im->string(string => "AB", size => 20, aa => 0,
+                    x => 0, y => 15, font => $font),
+        "draw with transparent color, non-aa");
+      local $TODO = "RT 73359 - non-AA text isn't normal mode rendered";
+      is_image($im, $copy, "should draw nothing");
+    }
+  }
+
   ok(1, "end of code");
 }
index 15f625d..653e4a8 100644 (file)
@@ -3,6 +3,7 @@
 # this tests both the Inline interface and the API
 use strict;
 use Test::More;
+use Imager::Test qw(is_color3 is_color4);
 eval "require Inline::C;";
 plan skip_all => "Inline required for testing API" if $@;
 
@@ -18,7 +19,7 @@ plan skip_all => "perl 5.005_04, 5.005_05 too buggy"
 
 -d "testout" or mkdir "testout";
 
-plan tests => 16;
+plan tests => 82;
 require Inline;
 Inline->import(with => 'Imager');
 Inline->import("FORCE"); # force rebuild
@@ -363,6 +364,36 @@ io_peekc_test(SV *in) {
   return result;
 }
 
+
+
+int
+test_render_color(Imager work_8) {
+  i_render *r8;
+  i_color c;
+  unsigned char render_coverage[3];
+
+  render_coverage[0] = 0;
+  render_coverage[1] = 128;
+  render_coverage[2] = 255;
+
+  r8 = i_render_new(work_8, 10);
+  c.channel[0] = 128;
+  c.channel[1] = 255;
+  c.channel[2] = 0;
+  c.channel[3] = 255;
+  i_render_color(r8, 0, 0, sizeof(render_coverage), render_coverage, &c);
+
+  c.channel[3] = 128;
+  i_render_color(r8, 0, 1, sizeof(render_coverage), render_coverage, &c);
+
+  c.channel[3] = 0;
+  i_render_color(r8, 0, 2, sizeof(render_coverage), render_coverage, &c);
+
+  i_render_delete(r8);
+
+  return 1;
+}
+
 EOS
 
 my $im = Imager->new(xsize=>50, ysize=>50);
@@ -427,3 +458,89 @@ is(io_gets_test("test"), "tes", "check i_io_gets()");
 is(io_getc_test("ABC"), ord "A", "check i_io_getc(_imp)?");
 
 is(io_getc_test("XYZ"), ord "X", "check i_io_peekc(_imp)?");
+
+for my $bits (8, 16) {
+  print "# bits: $bits\n";
+
+  # the floating point processing is a little more accurate
+  my $bump = $bits == 16 ? 1 : 0;
+  {
+    my $im = Imager->new(xsize => 10, ysize => 10, channels => 3, bits => $bits);
+    ok($im->box(filled => 1, color => '#808080'), "fill work image with gray");
+    ok(test_render_color($im),
+       "call render_color on 3 channel image");
+    is_color3($im->getpixel(x => 0, y => 0), 128, 128, 128,
+             "check zero coverage, alpha 255 color, bits $bits");
+    is_color3($im->getpixel(x => 1, y => 0), 128, 191+$bump, 63+$bump,
+             "check 128 coverage, alpha 255 color, bits $bits");
+    is_color3($im->getpixel(x => 2, y => 0), 128, 255, 0,
+             "check 255 coverage, alpha 255 color, bits $bits");
+
+    is_color3($im->getpixel(x => 0, y => 1), 128, 128, 128,
+             "check zero coverage, alpha 128 color, bits $bits");
+    is_color3($im->getpixel(x => 1, y => 1), 128, 159+$bump, 95+$bump,
+             "check 128 coverage, alpha 128 color, bits $bits");
+    is_color3($im->getpixel(x => 2, y => 1), 128, 191+$bump, 63+$bump,
+             "check 255 coverage, alpha 128 color, bits $bits");
+
+    is_color3($im->getpixel(x => 0, y => 2), 128, 128, 128,
+             "check zero coverage, alpha 0 color, bits $bits");
+    is_color3($im->getpixel(x => 1, y => 2), 128, 128, 128,
+             "check 128 coverage, alpha 0 color, bits $bits");
+    is_color3($im->getpixel(x => 2, y => 2), 128, 128, 128,
+             "check 255 coverage, alpha 0 color, bits $bits");
+  }
+  {
+    my $im = Imager->new(xsize => 10, ysize => 10, channels => 4, bits => $bits);
+    ok($im->box(filled => 1, color => '#808080'), "fill work image with opaque gray");
+    ok(test_render_color($im),
+       "call render_color on 4 channel image");
+    is_color4($im->getpixel(x => 0, y => 0), 128, 128, 128, 255,
+             "check zero coverage, alpha 255 color, bits $bits");
+    is_color4($im->getpixel(x => 1, y => 0), 128, 191+$bump, 63+$bump, 255,
+             "check 128 coverage, alpha 255 color, bits $bits");
+    is_color4($im->getpixel(x => 2, y => 0), 128, 255, 0, 255,
+             "check 255 coverage, alpha 255 color, bits $bits");
+
+    is_color4($im->getpixel(x => 0, y => 1), 128, 128, 128, 255,
+             "check zero coverage, alpha 128 color, bits $bits");
+    is_color4($im->getpixel(x => 1, y => 1), 128, 159+$bump, 95+$bump, 255,
+             "check 128 coverage, alpha 128 color, bits $bits");
+    is_color4($im->getpixel(x => 2, y => 1), 128, 191+$bump, 63+$bump, 255,
+             "check 255 coverage, alpha 128 color, bits $bits");
+
+    is_color4($im->getpixel(x => 0, y => 2), 128, 128, 128, 255,
+             "check zero coverage, alpha 0 color, bits $bits");
+    is_color4($im->getpixel(x => 1, y => 2), 128, 128, 128, 255,
+             "check 128 coverage, alpha 0 color, bits $bits");
+    is_color4($im->getpixel(x => 2, y => 2), 128, 128, 128, 255,
+             "check 255 coverage, alpha 0 color, bits $bits");
+  }
+
+  {
+    my $im = Imager->new(xsize => 10, ysize => 10, channels => 4, bits => $bits);
+    ok($im->box(filled => 1, color => Imager::Color->new(128, 128, 128, 64)), "fill work image with translucent gray");
+    ok(test_render_color($im),
+       "call render_color on 4 channel image");
+    is_color4($im->getpixel(x => 0, y => 0), 128, 128, 128, 64,
+             "check zero coverage, alpha 255 color, bits $bits");
+    is_color4($im->getpixel(x => 1, y => 0), 128, 230, 25+$bump, 159+$bump,
+             "check 128 coverage, alpha 255 color, bits $bits");
+    is_color4($im->getpixel(x => 2, y => 0), 128, 255, 0, 255,
+             "check 255 coverage, alpha 255 color, bits $bits");
+
+    is_color4($im->getpixel(x => 0, y => 1), 128, 128, 128, 64,
+             "check zero coverage, alpha 128 color, bits $bits");
+    is_color4($im->getpixel(x => 1, y => 1), 129-$bump, 202-$bump, 55, 111+$bump,
+             "check 128 coverage, alpha 128 color, bits $bits");
+    is_color4($im->getpixel(x => 2, y => 1), 128, 230, 25+$bump, 159+$bump,
+             "check 255 coverage, alpha 128 color, bits $bits");
+
+    is_color4($im->getpixel(x => 0, y => 2), 128, 128, 128, 64,
+             "check zero coverage, alpha 0 color, bits $bits");
+    is_color4($im->getpixel(x => 1, y => 2), 128, 128, 128, 64,
+             "check 128 coverage, alpha 0 color, bits $bits");
+    is_color4($im->getpixel(x => 2, y => 2), 128, 128, 128, 64,
+             "check 255 coverage, alpha 0 color, bits $bits");
+  }
+}