From cb78ba16bfd45d174acba1ac22f27e3c47e4061c Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 9 May 2012 15:20:08 +0000 Subject: patch [#31355] 16-bit pngs are only read with 8-bit precision from David M (erwin94) --- source/blender/imbuf/intern/png.c | 204 ++++++++++++++++++++++++++------------ 1 file changed, 141 insertions(+), 63 deletions(-) (limited to 'source/blender/imbuf/intern/png.c') diff --git a/source/blender/imbuf/intern/png.c b/source/blender/imbuf/intern/png.c index 0a19bf1280b..d39ab6f036e 100644 --- a/source/blender/imbuf/intern/png.c +++ b/source/blender/imbuf/intern/png.c @@ -27,13 +27,14 @@ /** \file blender/imbuf/intern/png.c * \ingroup imbuf + * + * \todo Save floats as 16 bits per pixel, currently readonly. */ - - #include "png.h" #include "BLI_blenlib.h" +#include "BLI_math.h" #include "MEM_guardedalloc.h" #include "imbuf.h" @@ -306,12 +307,16 @@ struct ImBuf *imb_loadpng(unsigned char *mem, size_t size, int flags) png_structp png_ptr; png_infop info_ptr; unsigned char *pixels = NULL; + unsigned short *pixels16 = NULL; png_bytepp row_pointers = NULL; png_uint_32 width, height; int bit_depth, color_type; PNGReadStruct ps; unsigned char *from, *to; + unsigned short *from16; + float *to_float; + float tmp[4]; int i, bytesperpixel; if (imb_is_a_png(mem) == 0) return(NULL); @@ -340,6 +345,7 @@ struct ImBuf *imb_loadpng(unsigned char *mem, size_t size, int flags) if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); if (pixels) MEM_freeN(pixels); + if (pixels16) MEM_freeN(pixels16); if (row_pointers) MEM_freeN(row_pointers); if (ibuf) IMB_freeImBuf(ibuf); return NULL; @@ -351,11 +357,6 @@ struct ImBuf *imb_loadpng(unsigned char *mem, size_t size, int flags) png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); - if (bit_depth == 16) { - png_set_strip_16(png_ptr); - bit_depth = 8; - } - bytesperpixel = png_get_channels(png_ptr, info_ptr); switch (color_type) { @@ -387,7 +388,10 @@ struct ImBuf *imb_loadpng(unsigned char *mem, size_t size, int flags) if (ibuf) { ibuf->ftype = PNG; - ibuf->profile = IB_PROFILE_SRGB; + if (bit_depth == 16) + ibuf->profile = IB_PROFILE_LINEAR_RGB; + else + ibuf->profile = IB_PROFILE_SRGB; if (png_get_valid (png_ptr, info_ptr, PNG_INFO_pHYs)) { int unit_type; @@ -405,67 +409,138 @@ struct ImBuf *imb_loadpng(unsigned char *mem, size_t size, int flags) } if (ibuf && ((flags & IB_test) == 0)) { - imb_addrectImBuf(ibuf); + if (bit_depth == 16) { + imb_addrectfloatImBuf(ibuf); + png_set_swap(png_ptr); + + pixels16 = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(png_uint_16), "pixels"); + if (pixels16 == NULL) { + printf("Cannot allocate pixels array\n"); + longjmp(png_jmpbuf(png_ptr), 1); + } - pixels = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned char), "pixels"); - if (pixels == NULL) { - printf("Cannot allocate pixels array\n"); - longjmp(png_jmpbuf(png_ptr), 1); - } + // allocate memory for an array of row-pointers + row_pointers = (png_bytepp) MEM_mallocN(ibuf->y * sizeof(png_uint_16p), "row_pointers"); + if (row_pointers == NULL) { + printf("Cannot allocate row-pointers array\n"); + longjmp(png_jmpbuf(png_ptr), 1); + } - // allocate memory for an array of row-pointers - row_pointers = (png_bytepp) MEM_mallocN(ibuf->y * sizeof(png_bytep), "row_pointers"); - if (row_pointers == NULL) { - printf("Cannot allocate row-pointers array\n"); - longjmp(png_jmpbuf(png_ptr), 1); - } + // set the individual row-pointers to point at the correct offsets + for (i = 0; i < ibuf->y; i++) { + row_pointers[ibuf->y - 1 - i] = (png_bytep) + ((png_uint_16 *)pixels16 + (i * ibuf->x) * bytesperpixel); + } - // set the individual row-pointers to point at the correct offsets - for (i = 0; i < ibuf->y; i++) { - row_pointers[ibuf->y-1-i] = (png_bytep) - ((unsigned char *)pixels + (i * ibuf->x) * bytesperpixel * sizeof(unsigned char)); + png_read_image(png_ptr, row_pointers); + + // copy image data + + to_float = ibuf->rect_float; + from16 = pixels16; + + switch (bytesperpixel) { + case 4: + for (i = ibuf->x * ibuf->y; i > 0; i--) { + tmp[0] = from16[0] / 65535.0; + tmp[1] = from16[1] / 65535.0; + tmp[2] = from16[2] / 65535.0; + tmp[3] = from16[3] / 65535.0; + srgb_to_linearrgb_v4(to_float, tmp); + to_float += 4; from16 += 4; + } + break; + case 3: + for (i = ibuf->x * ibuf->y; i > 0; i--) { + tmp[0] = from16[0] / 65535.0; + tmp[1] = from16[1] / 65535.0; + tmp[2] = from16[2] / 65535.0; + tmp[3] = 1.0; + srgb_to_linearrgb_v4(to_float, tmp); + to_float += 4; from16 += 3; + } + break; + case 2: + for (i = ibuf->x * ibuf->y; i > 0; i--) { + tmp[0] = tmp[1] = tmp[2] = from16[0] / 65535.0; + tmp[3] = from16[1] / 65535.0; + srgb_to_linearrgb_v4(to_float, tmp); + to_float += 4; from16 += 2; + } + break; + case 1: + for (i = ibuf->x * ibuf->y; i > 0; i--) { + tmp[0] = tmp[1] = tmp[2] = from16[0] / 65535.0; + tmp[3] = 1.0; + srgb_to_linearrgb_v4(to_float, tmp); + to_float += 4; from16++; + } + break; + } } + else { + imb_addrectImBuf(ibuf); - png_read_image(png_ptr, row_pointers); - - // copy image data - - to = (unsigned char *) ibuf->rect; - from = pixels; - - switch (bytesperpixel) { - case 4: - for (i = ibuf->x * ibuf->y; i > 0; i--) { - to[0] = from[0]; - to[1] = from[1]; - to[2] = from[2]; - to[3] = from[3]; - to += 4; from += 4; + pixels = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned char), "pixels"); + if (pixels == NULL) { + printf("Cannot allocate pixels array\n"); + longjmp(png_jmpbuf(png_ptr), 1); } - break; - case 3: - for (i = ibuf->x * ibuf->y; i > 0; i--) { - to[0] = from[0]; - to[1] = from[1]; - to[2] = from[2]; - to[3] = 0xff; - to += 4; from += 3; + + // allocate memory for an array of row-pointers + row_pointers = (png_bytepp) MEM_mallocN(ibuf->y * sizeof(png_bytep), "row_pointers"); + if (row_pointers == NULL) { + printf("Cannot allocate row-pointers array\n"); + longjmp(png_jmpbuf(png_ptr), 1); } - break; - case 2: - for (i = ibuf->x * ibuf->y; i > 0; i--) { - to[0] = to[1] = to[2] = from[0]; - to[3] = from[1]; - to += 4; from += 2; + + // set the individual row-pointers to point at the correct offsets + for (i = 0; i < ibuf->y; i++) { + row_pointers[ibuf->y-1-i] = (png_bytep) + ((unsigned char *)pixels + (i * ibuf->x) * bytesperpixel * sizeof(unsigned char)); } - break; - case 1: - for (i = ibuf->x * ibuf->y; i > 0; i--) { - to[0] = to[1] = to[2] = from[0]; - to[3] = 0xff; - to += 4; from++; + + png_read_image(png_ptr, row_pointers); + + // copy image data + + to = (unsigned char *) ibuf->rect; + from = pixels; + + switch (bytesperpixel) { + case 4: + for (i = ibuf->x * ibuf->y; i > 0; i--) { + to[0] = from[0]; + to[1] = from[1]; + to[2] = from[2]; + to[3] = from[3]; + to += 4; from += 4; + } + break; + case 3: + for (i = ibuf->x * ibuf->y; i > 0; i--) { + to[0] = from[0]; + to[1] = from[1]; + to[2] = from[2]; + to[3] = 0xff; + to += 4; from += 3; + } + break; + case 2: + for (i = ibuf->x * ibuf->y; i > 0; i--) { + to[0] = to[1] = to[2] = from[0]; + to[3] = from[1]; + to += 4; from += 2; + } + break; + case 1: + for (i = ibuf->x * ibuf->y; i > 0; i--) { + to[0] = to[1] = to[2] = from[0]; + to[3] = 0xff; + to += 4; from++; + } + break; } - break; } if (flags & IB_metadata) { @@ -473,15 +548,18 @@ struct ImBuf *imb_loadpng(unsigned char *mem, size_t size, int flags) int count = png_get_text(png_ptr, info_ptr, &text_chunks, NULL); for (i = 0; i < count; i++) { IMB_metadata_add_field(ibuf, text_chunks[i].key, text_chunks[i].text); - ibuf->flags |= IB_metadata; - } + ibuf->flags |= IB_metadata; + } } png_read_end(png_ptr, info_ptr); } // clean up - MEM_freeN(pixels); + if(pixels) + MEM_freeN(pixels); + if(pixels16) + MEM_freeN(pixels16); MEM_freeN(row_pointers); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); -- cgit v1.2.3