WIP PNG re-work
authorTony Cook <tony@develop-help.com>
Sat, 12 Nov 2011 05:38:41 +0000 (16:38 +1100)
committerTony Cook <tony@develop-help.com>
Sun, 29 Apr 2012 03:40:55 +0000 (13:40 +1000)
Changes
MANIFEST
PNG/impng.c
PNG/t/10png.t
PNG/testimg/rgb8.png [new file with mode: 0644]
PNG/testimg/rgb8i.png [new file with mode: 0644]

diff --git a/Changes b/Changes
index 6889d76..d5c849d 100644 (file)
--- a/Changes
+++ b/Changes
@@ -2,6 +2,7 @@ Imager release history.  Older releases can be found in Changes.old
 
  - PNG rework
    - improve error reporting
+   - add png_interlace, png_bits tags
 
 Imager 0.90 - unreleased
 ===========
index 4d07d3e..0972e28 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -234,6 +234,8 @@ PNG/testimg/palette.png
 PNG/testimg/palette_out.png
 PNG/testimg/paltrans.png
 PNG/testimg/rgb16.png
+PNG/testimg/rgb8.png
+PNG/testimg/rgb8i.png
 pnm.c
 polygon.c
 ppport.h
index 55e9bef..aeb1359 100644 (file)
 static int CC2C[PNG_COLOR_MASK_PALETTE|PNG_COLOR_MASK_COLOR|PNG_COLOR_MASK_ALPHA];
 
 #define PNG_BYTES_TO_CHECK 4
+
+static i_img *
+read_direct8(png_structp png_ptr, png_infop info_ptr, int channels, i_img_dim width, i_img_dim height);
+
 unsigned
 i_png_lib_version(void) {
   return png_access_version_number();
@@ -313,43 +316,72 @@ i_readpng_wiol(io_glue *ig) {
     return NULL;
   }
 
+  im = read_direct8(png_ptr, info_ptr, channels, width, height);
+
+  if (im)
+    get_png_tags(im, png_ptr, info_ptr);
+
+  png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
+
+  if (im) {
+    if (rs.warnings) {
+      i_tags_set(&im->tags, "png_warnings", rs.warnings, -1);
+    }
+  }
+  cleanup_read_state(&rs);
+  
+  mm_log((1,"(%p) <- i_readpng_wiol\n", im));  
+  
+  return im;
+}
+
+static i_img *
+read_direct8(png_structp png_ptr, png_infop info_ptr, int channels,
+            i_img_dim width, i_img_dim height) {
+  i_img * volatile vim = NULL;
+  int color_type = png_get_color_type(png_ptr, info_ptr);
+  int bit_depth = png_get_bit_depth(png_ptr, info_ptr);
+  i_img_dim y;
+  int number_passes, pass;
+  i_img *im;
+
+  if (setjmp(png_jmpbuf(png_ptr))) {
+    if (vim) i_img_destroy(vim);
+
+    return NULL;
+  }
+
+  number_passes = png_set_interlace_handling(png_ptr);
+  mm_log((1,"number of passes=%d\n",number_passes));
+
   png_set_strip_16(png_ptr);
   png_set_packing(png_ptr);
-  if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand(png_ptr);
-  if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand(png_ptr);
 
+  if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
+    png_set_expand(png_ptr);
+    
   if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
     channels++;
     mm_log((1, "image has transparency, adding alpha: channels = %d\n", channels));
     png_set_expand(png_ptr);
   }
   
-  number_passes = png_set_interlace_handling(png_ptr);
-  mm_log((1,"number of passes=%d\n",number_passes));
   png_read_update_info(png_ptr, info_ptr);
   
-  im = i_img_8_new(width,height,channels);
+  im = vim = i_img_8_new(width,height,channels);
   if (!im) {
     png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
     return NULL;
   }
-
-  for (pass = 0; pass < number_passes; pass++)
-    for (y = 0; y < height; y++) { png_read_row(png_ptr,(png_bytep) &(im->idata[channels*width*y]), NULL); }
-  
-  png_read_end(png_ptr, info_ptr); 
   
-  get_png_tags(im, png_ptr, info_ptr);
-
-  png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
-
-  if (rs.warnings) {
-    i_tags_set(&im->tags, "png_warnings", rs.warnings, -1);
+  for (pass = 0; pass < number_passes; pass++) {
+    for (y = 0; y < height; y++) {
+      png_read_row(png_ptr,(png_bytep) &(im->idata[channels*width*y]), NULL);
+    }
   }
-  cleanup_read_state(&rs);
-  
-  mm_log((1,"(0x%08X) <- i_readpng_scalar\n", im));  
   
+  png_read_end(png_ptr, info_ptr); 
+
   return im;
 }
 
index c3a248c..b41606a 100644 (file)
@@ -2,7 +2,7 @@
 use strict;
 use Imager qw(:all);
 use Test::More;
-use Imager::Test qw(test_image_raw test_image);
+use Imager::Test qw(test_image_raw test_image is_image);
 
 my $debug_writes = 1;
 
@@ -13,7 +13,7 @@ init_log("testout/t102png.log",1);
 $Imager::formats{"png"}
   or plan skip_all => "No png support";
 
-plan tests => 73;
+plan tests => 92;
 
 diag("Library version " . Imager::File::PNG::i_png_lib_version());
 
@@ -231,6 +231,8 @@ SKIP:
   is($im->getchannels, 1, "check channel count");
   is($im->type, "direct", "check type");
   is($im->bits, 8, "check bits");
+  local $TODO = "Not yet implemented";
+  is($im->tags(name => "png_bits"), 8, "check png_bits tag");
 }
 
 { # test grayscale + alpha read as greyscale + alpha
@@ -240,6 +242,9 @@ SKIP:
   is($im->getchannels, 2, "check channel count");
   is($im->type, "direct", "check type");
   is($im->bits, 8, "check bits");
+  local $TODO = "Not yet implemented";
+  is($im->tags(name => "png_bits"), 8, "check png_bits tag");
+  is($im->tags(name => "png_interlace"), 0, "check png_bits tag");
 }
 
 { # test paletted + alpha read as paletted
@@ -249,6 +254,8 @@ SKIP:
   is($im->getchannels, 4, "check channel count");
   local $TODO = "Not yet implemented";
   is($im->type, "paletted", "check type");
+  is($im->tags(name => "png_bits"), 8, "check png_bits tag");
+  is($im->tags(name => "png_interlace"), 0, "check png_bits tag");
 }
 
 { # test paletted read as paletted
@@ -258,6 +265,8 @@ SKIP:
   is($im->getchannels, 3, "check channel count");
   local $TODO = "Not yet implemented";
   is($im->type, "paletted", "check type");
+  is($im->tags(name => "png_bits"), 8, "check png_bits tag");
+  is($im->tags(name => "png_interlace"), 0, "check png_bits tag");
 }
 
 { # test 16-bit rgb read as 16 bit
@@ -268,6 +277,8 @@ SKIP:
   is($im->type, "direct", "check type");
   local $TODO = "Not yet implemented";
   is($im->bits, 16, "check bits");
+  is($im->tags(name => "png_bits"), 16, "check png_bits tag");
+  is($im->tags(name => "png_interlace"), 0, "check png_bits tag");
 }
 
 { # test 1-bit grey read as mono
@@ -278,6 +289,25 @@ SKIP:
   local $TODO = "Not yet implemented";
   is($im->type, "paletted", "check type");
   ok($im->is_bilevel, "should be bilevel");
+  is($im->tags(name => "png_bits"), 1, "check png_bits tag");
+  is($im->tags(name => "png_interlace"), 0, "check png_bits tag");
+}
+
+SKIP:
+{ # test interlaced read as interlaced and matches original
+  my $im_i = Imager->new(file => "testimg/rgb8i.png", filetype => "png");
+  ok($im_i, "read interlaced")
+    or skip("Could not read rgb8i.png: " . Imager->errstr, 7);
+  is($im_i->getchannels, 3, "check channel count");
+  is($im_i->type, "direct", "check type");
+  is($im_i->tags(name => "png_bits"), 8, "check png_bits");
+  is($im_i->tags(name => "png_interlace"), "adam7", "check png_interlace");
+
+  my $im = Imager->new(file => "testimg/rgb8.png", filetype => "png");
+  ok($im, "read non-interlaced")
+    or skip("Could not read testimg/rgb8.png: " . Imager->errstr, 2);
+  is($im->tags(name => "png_interlace"), "0", "check png_interlace");
+  is_image($im_i, $im, "compare interlaced and non-interlaced");
 }
 
 sub limited_write {
diff --git a/PNG/testimg/rgb8.png b/PNG/testimg/rgb8.png
new file mode 100644 (file)
index 0000000..0eb3060
Binary files /dev/null and b/PNG/testimg/rgb8.png differ
diff --git a/PNG/testimg/rgb8i.png b/PNG/testimg/rgb8i.png
new file mode 100644 (file)
index 0000000..ecac1a9
Binary files /dev/null and b/PNG/testimg/rgb8i.png differ