Skip to content
Browse files

PNG re-work: implement paletted read

  • Loading branch information...
1 parent 022439e commit 963d3602728cb3f265af53c8c88664c034be7266 @tonycoz committed Apr 6, 2012
Showing with 108 additions and 13 deletions.
  1. +6 −0 Changes
  2. +95 −3 PNG/impng.c
  3. +7 −10 PNG/t/10png.t
View
6 Changes
@@ -3,6 +3,12 @@ Imager release history. Older releases can be found in Changes.old
- PNG rework
- improve error reporting
- add png_interlace, png_bits tags
+ - read paletted images as paletted images, including transparency
+
+ TODO:
+ - flush output
+ - documentation in C code
+ - documentation of new tags, behaviour
Imager 0.90 - unreleased
===========
View
98 PNG/impng.c
@@ -11,6 +11,9 @@ static int CC2C[PNG_COLOR_MASK_PALETTE|PNG_COLOR_MASK_COLOR|PNG_COLOR_MASK_ALPHA
static i_img *
read_direct8(png_structp png_ptr, png_infop info_ptr, int channels, i_img_dim width, i_img_dim height);
+static i_img *
+read_paletted(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();
@@ -46,8 +49,8 @@ error_handler(png_structp png_ptr, png_const_charp msg) {
/*
-For writing a warning might have information about an error, so send
-it to the error stack.
+ For writing a warning might have information about an error, so send
+ it to the error stack.
*/
static void
@@ -281,7 +284,12 @@ i_readpng_wiol(io_glue *ig) {
return NULL;
}
- im = read_direct8(png_ptr, info_ptr, channels, width, height);
+ if (color_type == PNG_COLOR_TYPE_PALETTE) {
+ im = read_paletted(png_ptr, info_ptr, channels, width, height);
+ }
+ else {
+ im = read_direct8(png_ptr, info_ptr, channels, width, height);
+ }
if (im)
get_png_tags(im, png_ptr, info_ptr);
@@ -359,6 +367,90 @@ read_direct8(png_structp png_ptr, png_infop info_ptr, int channels,
return im;
}
+static i_img *
+read_paletted(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;
+ unsigned char *line;
+ unsigned char * volatile vline = NULL;
+ int num_palette, i;
+ png_colorp png_palette;
+ png_bytep png_pal_trans;
+ png_color_16p png_color_trans;
+ int num_pal_trans;
+
+ if (setjmp(png_jmpbuf(png_ptr))) {
+ if (vim) i_img_destroy(vim);
+ if (vline) myfree(vline);
+
+ 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_GRAY && bit_depth < 8)
+ png_set_expand(png_ptr);
+
+ if (!png_get_PLTE(png_ptr, info_ptr, &png_palette, &num_palette)) {
+ i_push_error(0, "Paletted image with no PLTE chunk");
+ return NULL;
+ }
+
+ if (png_get_tRNS(png_ptr, info_ptr, &png_pal_trans, &num_pal_trans,
+ &png_color_trans)) {
+ channels++;
+ }
+ else {
+ num_pal_trans = 0;
+ }
+
+ png_read_update_info(png_ptr, info_ptr);
+
+ im = vim = i_img_pal_new(width, height, channels, 256);
+ if (!im) {
+ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
+ return NULL;
+ }
+
+ for (i = 0; i < num_palette; ++i) {
+ i_color c;
+
+ c.rgba.r = png_palette[i].red;
+ c.rgba.g = png_palette[i].green;
+ c.rgba.b = png_palette[i].blue;
+ if (i < num_pal_trans)
+ c.rgba.a = png_pal_trans[i];
+ else
+ c.rgba.a = 255;
+ i_addcolors(im, &c, 1);
+ }
+
+ line = vline = mymalloc(width);
+ for (pass = 0; pass < number_passes; pass++) {
+ for (y = 0; y < height; y++) {
+ if (pass > 0)
+ i_gpal(im, 0, width, y, line);
+ png_read_row(png_ptr,(png_bytep)line, NULL);
+ i_ppal(im, 0, width, y, line);
+ }
+ }
+ myfree(line);
+ vline = NULL;
+
+ png_read_end(png_ptr, info_ptr);
+
+ return im;
+}
+
static void
get_png_tags(i_img *im, png_structp png_ptr, png_infop info_ptr) {
png_uint_32 xres, yres;
View
17 PNG/t/10png.t
@@ -13,7 +13,7 @@ init_log("testout/t102png.log",1);
$Imager::formats{"png"}
or plan skip_all => "No png support";
-plan tests => 92;
+plan tests => 93;
diag("Library version " . Imager::File::PNG::i_png_lib_version());
@@ -231,8 +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");
+ is($im->tags(name => "png_interlace"), 0, "check png_interlace tag");
}
{ # test grayscale + alpha read as greyscale + alpha
@@ -242,31 +242,28 @@ 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");
+ is($im->tags(name => "png_interlace"), 0, "check png_interlace tag");
}
{ # test paletted + alpha read as paletted
my $im = Imager->new;
ok($im->read(file => "testimg/paltrans.png", type => "png"),
"read paletted with alpha");
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");
+ is($im->tags(name => "png_interlace"), 0, "check png_interlace tag");
}
{ # test paletted read as paletted
my $im = Imager->new;
ok($im->read(file => "testimg/pal.png", type => "png"),
"read paletted");
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");
+ is($im->tags(name => "png_interlace"), 0, "check png_interlace tag");
}
{ # test 16-bit rgb read as 16 bit
@@ -275,22 +272,22 @@ SKIP:
"read 16-bit rgb");
is($im->getchannels, 3, "check channel count");
is($im->type, "direct", "check type");
+ is($im->tags(name => "png_interlace"), 0, "check png_interlace tag");
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
my $im = Imager->new;
ok($im->read(file => "testimg/bilevel.png", type => "png"),
"read bilevel png");
is($im->getchannels, 1, "check channel count");
+ is($im->tags(name => "png_interlace"), 0, "check png_interlace tag");
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:

0 comments on commit 963d360

Please sign in to comment.
Something went wrong with that request. Please try again.