[RT #99507] don't apply the icon mask to images with an alpha channel
authorTony Cook <tony@develop-help.com>
Sat, 8 Nov 2014 02:41:29 +0000 (13:41 +1100)
committerTony Cook <tony@develop-help.com>
Sat, 8 Nov 2014 02:41:29 +0000 (13:41 +1100)
but do it if the caller asks nicely

ICO/ICO.pm
ICO/ICO.xs
ICO/imicon.c
ICO/imicon.h
ICO/t/t10icon.t
lib/Imager/Files.pod

index 2bc8530..aeffd79 100644 (file)
@@ -4,7 +4,7 @@ use Imager;
 use vars qw($VERSION @ISA);
 
 BEGIN {
-  $VERSION = "0.03";
+  $VERSION = "0.04";
   
   require XSLoader;
   XSLoader::load('Imager::File::ICO', $VERSION);
@@ -18,7 +18,11 @@ Imager->register_reader
      my ($im, $io, %hsh) = @_;
      my $masked = 
        exists $hsh{ico_masked} ? $hsh{ico_masked} : 1;
-     $im->{IMG} = i_readico_single($io, $hsh{page} || 0, $masked);
+     my $alpha_masked =
+       exists $hsh{ico_alpha_masked} ? $hsh{ico_alpha_masked} : 0;
+
+     $im->{IMG} = i_readico_single($io, $hsh{page} || 0, $masked,
+                                  $alpha_masked);
 
      unless ($im->{IMG}) {
        $im->_set_error(Imager->_error_as_msg);
@@ -52,7 +56,10 @@ Imager->register_reader
      my ($im, $io, %hsh) = @_;
      my $masked = 
        exists $hsh{ico_masked} ? $hsh{ico_masked} : 1;
-     $im->{IMG} = i_readico_single($io, $hsh{page} || 0, $masked);
+     my $alpha_masked =
+       exists $hsh{ico_alpha_masked} ? $hsh{ico_alpha_masked} : 0;
+     $im->{IMG} = i_readico_single($io, $hsh{page} || 0, $masked,
+                                  $alpha_masked);
 
      unless ($im->{IMG}) {
        $im->_set_error(Imager->_error_as_msg);
index 333c6fb..3a15565 100644 (file)
@@ -14,21 +14,23 @@ MODULE = Imager::File::ICO  PACKAGE = Imager::File::ICO
 PROTOTYPES: DISABLE
 
 Imager::ImgRaw
-i_readico_single(ig, index, masked = 0)
+i_readico_single(ig, index, masked = 0, alpha_masked = 0)
        Imager::IO ig
        int index
        bool masked
+       bool alpha_masked
 
 void
-i_readico_multi(ig, masked = 0)
+i_readico_multi(ig, masked = 0, alpha_masked = 0)
        Imager::IO ig
        bool masked
+       bool alpha_masked
       PREINIT:
         i_img **imgs;
         int count;
         int i;
       PPCODE:
-        imgs = i_readico_multi(ig, &count, masked);
+        imgs = i_readico_multi(ig, &count, masked, alpha_masked);
         if (imgs) {
           EXTEND(SP, count);
           for (i = 0; i < count; ++i) {
index cb622cf..529610d 100644 (file)
@@ -13,7 +13,7 @@ ico_push_error(int error) {
 
 static
 i_img *
-read_one_icon(ico_reader_t *file, int index, int masked) {
+read_one_icon(ico_reader_t *file, int index, int masked, int alpha_masked) {
   ico_image_t *image;
   int error;
   i_img *result;
@@ -25,7 +25,7 @@ read_one_icon(ico_reader_t *file, int index, int masked) {
     return NULL;
   }
 
-  if (masked) {
+  if (masked && (image->bit_count != 32 || alpha_masked)) {
     /* check to make sure we should do the masking, if the mask has
        nothing set we don't mask */
     int pos;
@@ -195,7 +195,7 @@ read_one_icon(ico_reader_t *file, int index, int masked) {
 }
 
 i_img *
-i_readico_single(io_glue *ig, int index, int masked) {
+i_readico_single(io_glue *ig, int index, int masked, int alpha_masked) {
   ico_reader_t *file;
   i_img *result;
   int error;
@@ -211,14 +211,14 @@ i_readico_single(io_glue *ig, int index, int masked) {
 
   /* the index is range checked by msicon.c - don't duplicate it here */
 
-  result = read_one_icon(file, index, masked);
+  result = read_one_icon(file, index, masked, alpha_masked);
   ico_reader_close(file);
 
   return result;
 }
 
 i_img **
-i_readico_multi(io_glue *ig, int *count, int masked) {
+i_readico_multi(io_glue *ig, int *count, int masked, int alpha_masked) {
   ico_reader_t *file;
   int index;
   int error;
@@ -237,7 +237,7 @@ i_readico_multi(io_glue *ig, int *count, int masked) {
 
   *count = 0;
   for (index = 0; index < ico_image_count(file); ++index) {
-    i_img *im = read_one_icon(file, index, masked);
+    i_img *im = read_one_icon(file, index, masked, alpha_masked);
     if (!im)
       break;
 
index 7e26f4a..114d330 100644 (file)
@@ -4,9 +4,9 @@
 #include "imext.h"
 
 extern i_img *
-i_readico_single(io_glue *ig, int index, int masked);
+i_readico_single(io_glue *ig, int index, int masked, int alpha_masked);
 extern i_img **
-i_readico_multi(io_glue *ig, int *count, int masked);
+i_readico_multi(io_glue *ig, int *count, int masked, int alpha_masked);
 
 extern int
 i_writeico_wiol(i_io_glue_t *ig, i_img *im);
index 454a462..2c08c35 100644 (file)
@@ -1,7 +1,7 @@
 #!perl -w
 use strict;
-use Test::More tests => 106;
-use Imager::Test qw(is_image test_image);
+use Test::More tests => 111;
+use Imager::Test qw(is_image isnt_image test_image);
 
 BEGIN { use_ok('Imager::File::ICO'); }
 
@@ -415,3 +415,26 @@ EOS
   }
 }
 
+{ # RT #99507
+  # we now ignore the mask by default when reading a 32-bit image
+  my $im = Imager->new(xsize => 2, ysize => 2, channels => 4);
+  $im->setpixel(x => 0, y => 0, color => "#FF0000");
+  $im->setpixel(x => 1, y => 1, color => "#00FF00");
+  my $mask = <<EOS;
+01
+00
+11
+EOS
+  my $data;
+  ok($im->write(data => \$data,
+               type => "ico",
+               ico_mask => $mask), "write with dodgy mask");
+  my $im2 = Imager->new(data => \$data, filetype => "ico");
+  ok($im2, "read it back");
+  is_image($im2, $im, "should match original, despite bad mask");
+  my $im3 = Imager->new(data => \$data, filetype => "ico", ico_alpha_masked => 1);
+  ok($im3, "read it back with ico_alpha_masked => 1");
+  my $cmp = $im->copy;
+  $cmp->setpixel(x => 0, y => 0, color => [ 255, 0, 0, 0 ]);
+  isnt_image($im3, $cmp, "bad mask makes some pixels transparent");
+}
index 243fe75..7b9a0c8 100644 (file)
@@ -1613,9 +1613,10 @@ control reading of ICO/CUR files:
 
 =item *
 
-ico_masked - if true, the default, then the icon/cursors mask is
-applied as an alpha channel to the image.  This may result in a
-paletted image being returned as a direct color image.  Default: 1
+C<ico_masked> - if true, the default, then the icon/cursors mask is
+applied as an alpha channel to the image, unless that image already
+has an alpha channel.  This may result in a paletted image being
+returned as a direct color image.  Default: 1
 
   # retrieve the image as stored, without using the mask as an alpha
   # channel
@@ -1625,6 +1626,15 @@ paletted image being returned as a direct color image.  Default: 1
 This was introduced in Imager 0.60.  Previously reading ICO images
 acted as if C<ico_masked =E<gt> 0>.
 
+=item *
+
+C<ico_alpha_masked> - if true, then the icon/cursor mask is applied as
+an alpha channel to images that already have an alpha mask.  Note that
+this will only make pixels transparent, not opaque.  Default: 0.
+
+Note: If you get different results between C<ico_alpha_masked> being
+set to 0 and 1, your mask may broke when used with the Win32 API.
+
 =back
 
 C<cur_bits> is set when reading a cursor.