- images with an translucent alpha channel were not scaled correctly
authorTony Cook <tony@develop=help.com>
Thu, 16 Dec 2010 12:49:35 +0000 (12:49 +0000)
committerTony Cook <tony@develop=help.com>
Thu, 16 Dec 2010 12:49:35 +0000 (12:49 +0000)
   by the default (qtype=normal) scaling method.
   https://rt.cpan.org/Public/Bug/Display.html?id=63922

Changes
image.c
t/t40scale.t

diff --git a/Changes b/Changes
index 8282cbf..8856148 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,6 +1,15 @@
 Imager release history.  Older releases can be found in Changes.old
 
-Imager 0.79 - unreleased
+Imager 0.80 - unreleased
+===========
+
+Bug fixes:
+
+ - images with an translucent alpha channel were not scaled correctly
+   by the default (qtype=normal) scaling method.
+   https://rt.cpan.org/Public/Bug/Display.html?id=63922
+
+Imager 0.79 - 10 Dec 2010
 ===========
 
  - add Imager::Test to the POD coverage tests and document the missing
diff --git a/image.c b/image.c
index 28721a2..bf25b7d 100644 (file)
--- a/image.c
+++ b/image.c
@@ -747,11 +747,12 @@ i_scaleaxis(i_img *im, float Value, int Axis) {
   short psave;
   i_color val,val1,val2;
   i_img *new_img;
+  int has_alpha = i_img_has_alpha(im);
+  int color_chans = i_img_color_channels(im);
 
   i_clear_error();
   mm_log((1,"i_scaleaxis(im %p,Value %.2f,Axis %d)\n",im,Value,Axis));
 
-
   if (Axis == XAXIS) {
     hsize = (int)(0.5 + im->xsize * Value);
     if (hsize < 1) {
@@ -823,15 +824,46 @@ i_scaleaxis(i_img *im, float Value, int Axis) {
          
          i_gpix(im, Mx, i, &val1);
          i_gpix(im, mx, i, &val2);
-         
-         for (k=0; k<im->channels; k++) {
-           PictureValue[k] += l1[l]        * val1.channel[k];
-           PictureValue[k] += l0[lMax-l-1] * val2.channel[k];
+
+         if (has_alpha) {
+           i_sample_t alpha1 = val1.channel[color_chans];
+           i_sample_t alpha2 = val2.channel[color_chans];
+           for (k=0; k < color_chans; k++) {
+             PictureValue[k] += l1[l]        * val1.channel[k] * alpha1 / 255;
+             PictureValue[k] += l0[lMax-l-1] * val2.channel[k] * alpha2 / 255;
+           }
+           PictureValue[color_chans] += l1[l] * val1.channel[color_chans];
+           PictureValue[color_chans] += l0[lMax-l-1] * val2.channel[color_chans];
+         }
+         else {
+           for (k=0; k<im->channels; k++) {
+             PictureValue[k] += l1[l]        * val1.channel[k];
+             PictureValue[k] += l0[lMax-l-1] * val2.channel[k];
+           }
+         }
+       }
+
+       if (has_alpha) {
+         float fa = PictureValue[color_chans] / LanczosWidthFactor;
+         int alpha = minmax(0, 255, fa+0.5);
+         if (alpha) {
+           for (k = 0; k < color_chans; ++k) {
+             psave = (short)(0.5+(PictureValue[k] / LanczosWidthFactor * 255 / fa));
+             val.channel[k]=minmax(0,255,psave);
+           }
+           val.channel[color_chans] = alpha;
+         }
+         else {
+           /* zero alpha, so the pixel has no color */
+           for (k = 0; k < im->channels; ++k)
+             val.channel[k] = 0;
          }
        }
-       for(k=0;k<im->channels;k++) {
-         psave = (short)(0.5+(PictureValue[k] / LanczosWidthFactor));
-         val.channel[k]=minmax(0,255,psave);
+       else {
+         for(k=0;k<im->channels;k++) {
+           psave = (short)(0.5+(PictureValue[k] / LanczosWidthFactor));
+           val.channel[k]=minmax(0,255,psave);
+         }
        }
        i_ppix(new_img, j, i, &val);
       }
@@ -848,14 +880,43 @@ i_scaleaxis(i_img *im, float Value, int Axis) {
 
          i_gpix(im, i, Mx, &val1);
          i_gpix(im, i, mx, &val2);
-         for (k=0; k<im->channels; k++) {
-           PictureValue[k] += l1[l]        * val1.channel[k];
-           PictureValue[k] += l0[lMax-l-1] * val2.channel[k]; 
+         if (has_alpha) {
+           i_sample_t alpha1 = val1.channel[color_chans];
+           i_sample_t alpha2 = val2.channel[color_chans];
+           for (k=0; k < color_chans; k++) {
+             PictureValue[k] += l1[l]        * val1.channel[k] * alpha1 / 255;
+             PictureValue[k] += l0[lMax-l-1] * val2.channel[k] * alpha2 / 255;
+           }
+           PictureValue[color_chans] += l1[l] * val1.channel[color_chans];
+           PictureValue[color_chans] += l0[lMax-l-1] * val2.channel[color_chans];
+         }
+         else {
+           for (k=0; k<im->channels; k++) {
+             PictureValue[k] += l1[l]        * val1.channel[k];
+             PictureValue[k] += l0[lMax-l-1] * val2.channel[k];
+           }
          }
        }
-       for (k=0; k<im->channels; k++) {
-         psave = (short)(0.5+(PictureValue[k] / LanczosWidthFactor));
-         val.channel[k] = minmax(0, 255, psave);
+       if (has_alpha) {
+         float fa = PictureValue[color_chans] / LanczosWidthFactor;
+         int alpha = minmax(0, 255, fa+0.5);
+         if (alpha) {
+           for (k = 0; k < color_chans; ++k) {
+             psave = (short)(0.5+(PictureValue[k] / LanczosWidthFactor * 255 / fa));
+             val.channel[k]=minmax(0,255,psave);
+           }
+           val.channel[color_chans] = alpha;
+         }
+         else {
+           for (k = 0; k < im->channels; ++k)
+             val.channel[k] = 0;
+         }
+       }
+       else {
+         for(k=0;k<im->channels;k++) {
+           psave = (short)(0.5+(PictureValue[k] / LanczosWidthFactor));
+           val.channel[k]=minmax(0,255,psave);
+         }
        }
        i_ppix(new_img, i, j, &val);
       }
index b2ee906..f1d32a9 100644 (file)
@@ -1,9 +1,9 @@
 #!perl -w
 use strict;
-use Test::More tests => 230;
+use Test::More tests => 232;
 
 BEGIN { use_ok(Imager=>':all') }
-use Imager::Test qw(is_image is_color4);
+use Imager::Test qw(is_image is_color4 is_image_similar);
 
 Imager::init('log'=>'testout/t40scale.log');
 my $img=Imager->new();
@@ -180,7 +180,7 @@ SKIP:
              pixels => 144);
 }
 
-{ # check proper alpha handling
+{ # check proper alpha handling for mixing
   my $im = Imager->new(xsize => 40, ysize => 40, channels => 4);
   $im->box(filled => 1, color => 'C0C0C0');
   my $rot = $im->rotate(degrees => -4)
@@ -191,7 +191,24 @@ SKIP:
   $out->box(filled => 1, color => 'C0C0C0');
   my $cmp = $out->copy;
   $out->rubthrough(src => $sc);
-  is_image($out, $cmp, "check we get the right image after scaling");
+  is_image($out, $cmp, "check we get the right image after scaling (mixing)");
+
+  # we now set alpha=0 pixels to zero on scaling
+  is_color4($sc->getpixel('x' => 39, 'y' => 39), 0, 0, 0, 0,
+           "check we set alpha=0 pixels to zero on scaling");
+}
+
+{ # check proper alpha handling for default scaling
+  my $im = Imager->new(xsize => 40, ysize => 40, channels => 4);
+  $im->box(filled => 1, color => 'C0C0C0');
+  my $rot = $im->rotate(degrees => -4)
+    or die;
+  my $sc = $rot->scale(qtype => "normal", xpixels => 40);
+  my $out = Imager->new(xsize => $sc->getwidth, ysize => $sc->getheight);
+  $out->box(filled => 1, color => 'C0C0C0');
+  my $cmp = $out->copy;
+  $out->rubthrough(src => $sc);
+  is_image_similar($out, $cmp, 100, "check we get the right image after scaling (normal)");
 
   # we now set alpha=0 pixels to zero on scaling
   is_color4($sc->getpixel('x' => 39, 'y' => 39), 0, 0, 0, 0,