From: Tony Cook <tony@develop-help.com> Date: Fri, 6 Apr 2012 13:18:45 +0000 (+1000) Subject: PNG re-work: read 16-bit PNG as 16-bit X-Git-Tag: v0.90~2^2~22 X-Git-Url: http://git.imager.perl.org/imager.git/commitdiff_plain/c631b2d57fceb0c61d566f7489d2c8e56f078425 PNG re-work: read 16-bit PNG as 16-bit --- diff --git a/PNG/impng.c b/PNG/impng.c index 2503b350..142baae8 100644 --- a/PNG/impng.c +++ b/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_direct16(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); @@ -295,6 +298,9 @@ i_readpng_wiol(io_glue *ig) { && !png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { im = read_bilevel(png_ptr, info_ptr, width, height); } + else if (bit_depth == 16) { + im = read_direct16(png_ptr, info_ptr, channels, width, height); + } else { im = read_direct8(png_ptr, info_ptr, channels, width, height); } @@ -375,6 +381,74 @@ read_direct8(png_structp png_ptr, png_infop info_ptr, int channels, return im; } +static i_img * +read_direct16(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); + i_img_dim x, y; + int number_passes, pass; + i_img *im; + unsigned char *line; + unsigned char * volatile vline = NULL; + unsigned *bits_line; + unsigned * volatile vbits_line = NULL; + size_t row_bytes; + + if (setjmp(png_jmpbuf(png_ptr))) { + if (vim) i_img_destroy(vim); + if (vline) myfree(vline); + if (vbits_line) myfree(vbits_line); + + return NULL; + } + + number_passes = png_set_interlace_handling(png_ptr); + mm_log((1,"number of passes=%d\n",number_passes)); + + 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); + } + + png_read_update_info(png_ptr, info_ptr); + + im = vim = i_img_16_new(width,height,channels); + if (!im) { + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); + return NULL; + } + + row_bytes = png_get_rowbytes(png_ptr, info_ptr); + line = vline = mymalloc(row_bytes); + memset(line, 0, row_bytes); + bits_line = vbits_line = mymalloc(sizeof(unsigned) * width * channels); + for (pass = 0; pass < number_passes; pass++) { + for (y = 0; y < height; y++) { + if (pass > 0) { + i_gsamp_bits(im, 0, width, y, bits_line, NULL, channels, 16); + for (x = 0; x < width * channels; ++x) { + line[x*2] = bits_line[x] >> 8; + line[x*2+1] = bits_line[x] & 0xff; + } + } + png_read_row(png_ptr,(png_bytep)line, NULL); + for (x = 0; x < width * channels; ++x) + bits_line[x] = (line[x*2] << 8) + line[x*2+1]; + i_psamp_bits(im, 0, width, y, bits_line, NULL, channels, 16); + } + } + myfree(line); + myfree(bits_line); + vline = NULL; + vbits_line = NULL; + + png_read_end(png_ptr, info_ptr); + + return im; +} + static i_img * read_bilevel(png_structp png_ptr, png_infop info_ptr, i_img_dim width, i_img_dim height) { diff --git a/PNG/t/10png.t b/PNG/t/10png.t index badc09ae..a23cde40 100644 --- a/PNG/t/10png.t +++ b/PNG/t/10png.t @@ -273,9 +273,7 @@ SKIP: 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"); - undef $TODO; is($im->tags(name => "png_bits"), 16, "check png_bits tag"); }