Permalink
Browse files

PNG re-work: read 1 bit grey images as the common internal bilevel fo…

…rmat

which is really paletted
  • Loading branch information...
1 parent 963d360 commit 79b4c8494a1faea766e550b81edd03b3c837f73f @tonycoz committed Apr 6, 2012
Showing with 86 additions and 5 deletions.
  1. +4 −0 Changes
  2. +81 −4 PNG/impng.c
  3. +1 −1 PNG/t/10png.t
View
@@ -4,11 +4,15 @@ Imager release history. Older releases can be found in Changes.old
- improve error reporting
- add png_interlace, png_bits tags
- read paletted images as paletted images, including transparency
+ - read 1 bit greyscale images as a type suitable for other file
+ handlers to write as bilevel
TODO:
- flush output
- documentation in C code
- documentation of new tags, behaviour
+ - FIXME for read_paletted: do we need to scale the palette colours
+ based on the alpha?
Imager 0.90 - unreleased
===========
View
@@ -14,6 +14,9 @@ read_direct8(png_structp png_ptr, png_infop info_ptr, int channels, i_img_dim wi
static i_img *
read_paletted(png_structp png_ptr, png_infop info_ptr, int channels, i_img_dim width, i_img_dim height);
+static i_img *
+read_bilevel(png_structp png_ptr, png_infop info_ptr, i_img_dim width, i_img_dim height);
+
unsigned
i_png_lib_version(void) {
return png_access_version_number();
@@ -203,7 +206,7 @@ i_writepng_wiol(i_img *im, io_glue *ig) {
}
static void
-get_png_tags(i_img *im, png_structp png_ptr, png_infop info_ptr);
+get_png_tags(i_img *im, png_structp png_ptr, png_infop info_ptr, int bit_depth);
typedef struct {
char *warnings;
@@ -287,12 +290,17 @@ i_readpng_wiol(io_glue *ig) {
if (color_type == PNG_COLOR_TYPE_PALETTE) {
im = read_paletted(png_ptr, info_ptr, channels, width, height);
}
+ else if (color_type == PNG_COLOR_TYPE_GRAY
+ && bit_depth == 1
+ && !png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
+ im = read_bilevel(png_ptr, info_ptr, width, height);
+ }
else {
im = read_direct8(png_ptr, info_ptr, channels, width, height);
}
if (im)
- get_png_tags(im, png_ptr, info_ptr);
+ get_png_tags(im, png_ptr, info_ptr, bit_depth);
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
@@ -368,6 +376,73 @@ read_direct8(png_structp png_ptr, png_infop info_ptr, int channels,
}
static i_img *
+read_bilevel(png_structp png_ptr, png_infop info_ptr,
+ i_img_dim width, i_img_dim height) {
+ i_img * volatile vim = NULL;
+ i_img_dim x, y;
+ int number_passes, pass;
+ i_img *im;
+ unsigned char *line;
+ unsigned char * volatile vline = NULL;
+ i_color palette[2];
+
+ 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_packing(png_ptr);
+
+ png_set_expand(png_ptr);
+
+ png_read_update_info(png_ptr, info_ptr);
+
+ im = vim = i_img_pal_new(width, height, 1, 256);
+ if (!im) {
+ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
+ return NULL;
+ }
+
+ palette[0].channel[0] = palette[0].channel[1] = palette[0].channel[2] =
+ palette[0].channel[3] = 0;
+ palette[1].channel[0] = palette[1].channel[1] = palette[1].channel[2] =
+ palette[1].channel[3] = 255;
+ i_addcolors(im, palette, 2);
+
+ line = vline = mymalloc(width);
+ memset(line, 0, width);
+ for (pass = 0; pass < number_passes; pass++) {
+ for (y = 0; y < height; y++) {
+ if (pass > 0) {
+ i_gpal(im, 0, width, y, line);
+ /* expand indexes back to 0/255 */
+ for (x = 0; x < width; ++x)
+ line[x] = line[x] ? 255 : 0;
+ }
+ png_read_row(png_ptr,(png_bytep)line, NULL);
+
+ /* back to palette indexes */
+ for (x = 0; x < width; ++x)
+ line[x] = line[x] ? 1 : 0;
+ i_ppal(im, 0, width, y, line);
+ }
+ }
+ myfree(line);
+ vline = NULL;
+
+ png_read_end(png_ptr, info_ptr);
+
+ return im;
+}
+
+/* FIXME: do we need to unscale palette color values from the
+ supplied alphas? */
+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;
@@ -452,7 +527,7 @@ read_paletted(png_structp png_ptr, png_infop info_ptr, int channels,
}
static void
-get_png_tags(i_img *im, png_structp png_ptr, png_infop info_ptr) {
+get_png_tags(i_img *im, png_structp png_ptr, png_infop info_ptr, int bit_depth) {
png_uint_32 xres, yres;
int unit_type;
@@ -482,7 +557,9 @@ get_png_tags(i_img *im, png_structp png_ptr, png_infop info_ptr) {
break;
}
- i_tags_setn(&im->tags, "png_bits", png_get_bit_depth(png_ptr, info_ptr));
+ /* the various readers can call png_set_expand(), libpng will make
+ it's internal record of bit_depth at least 8 in that case */
+ i_tags_setn(&im->tags, "png_bits", bit_depth);
}
static void
View
@@ -275,6 +275,7 @@ SKIP:
is($im->tags(name => "png_interlace"), 0, "check png_interlace tag");
local $TODO = "Not yet implemented";
is($im->bits, 16, "check bits");
+ undef $TODO;
is($im->tags(name => "png_bits"), 16, "check png_bits tag");
}
@@ -284,7 +285,6 @@ SKIP:
"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");

0 comments on commit 79b4c84

Please sign in to comment.