diff options
author | Sergey Sharybin <sergey.vfx@gmail.com> | 2012-12-30 17:01:47 +0400 |
---|---|---|
committer | Sergey Sharybin <sergey.vfx@gmail.com> | 2012-12-30 17:01:47 +0400 |
commit | f62fc79da05b1b3568871adaff8b246eb6b30793 (patch) | |
tree | e69c8dbea350b3b8f4a37b0a1b064afa3daa4429 /source/blender/imbuf/intern/png.c | |
parent | fde101c50c3d7ad6bb43a578d7622cea084001a3 (diff) |
16 bit PNG write support
This commit adds a support of saving 16bit PNG files.
Alpha for such files would be premultiplied, would be corrected
with an upcoming alpha premul cleanup (it's not the only format
which will output 16bit image with premul alpha).
Diffstat (limited to 'source/blender/imbuf/intern/png.c')
-rw-r--r-- | source/blender/imbuf/intern/png.c | 108 |
1 files changed, 85 insertions, 23 deletions
diff --git a/source/blender/imbuf/intern/png.c b/source/blender/imbuf/intern/png.c index dcfebb95b87..c0737fadffa 100644 --- a/source/blender/imbuf/intern/png.c +++ b/source/blender/imbuf/intern/png.c @@ -109,10 +109,14 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags) unsigned char *pixels = NULL; unsigned char *from, *to; + unsigned short *pixels16 = NULL, *to16; + float *from_float; png_bytepp row_pointers = NULL; int i, bytesperpixel, color_type = PNG_COLOR_TYPE_GRAY; FILE *fp = NULL; + int is_16bit = (ibuf->ftype & PNG_16BIT) && ibuf->rect_float; + /* use the jpeg quality setting for compression */ int compression; compression = (int)(((float)(ibuf->ftype & 0xff) / 11.1111f)); @@ -150,8 +154,12 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags) /* copy image data */ - pixels = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned char), "pixels"); - if (pixels == NULL) { + if (is_16bit) + pixels16 = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned short), "png 16bit pixels"); + else + pixels = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned char), "png 8bit pixels"); + + if (pixels == NULL && pixels16 == NULL) { png_destroy_write_struct(&png_ptr, &info_ptr); printf("imb_savepng: Cannot allocate pixels array of %dx%d, %d bytes per pixel for file: '%s'\n", ibuf->x, ibuf->y, bytesperpixel, name); return 0; @@ -159,32 +167,63 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags) from = (unsigned char *) ibuf->rect; to = pixels; + from_float = ibuf->rect_float; + to16 = pixels16; switch (bytesperpixel) { case 4: color_type = PNG_COLOR_TYPE_RGBA; - 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; + if (is_16bit) { + for (i = ibuf->x * ibuf->y; i > 0; i--) { + to16[0] = FTOUSHORT(from_float[0]); + to16[1] = FTOUSHORT(from_float[1]); + to16[2] = FTOUSHORT(from_float[2]); + to16[3] = FTOUSHORT(from_float[3]); + to16 += 4; from_float += 4; + } + } + else { + 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: color_type = PNG_COLOR_TYPE_RGB; - for (i = ibuf->x * ibuf->y; i > 0; i--) { - to[0] = from[0]; - to[1] = from[1]; - to[2] = from[2]; - to += 3; from += 4; + if (is_16bit) { + for (i = ibuf->x * ibuf->y; i > 0; i--) { + to16[0] = FTOUSHORT(from_float[0]); + to16[1] = FTOUSHORT(from_float[1]); + to16[2] = FTOUSHORT(from_float[2]); + to16 += 3; from_float += 4; + } + } + else { + for (i = ibuf->x * ibuf->y; i > 0; i--) { + to[0] = from[0]; + to[1] = from[1]; + to[2] = from[2]; + to += 3; from += 4; + } } break; case 1: color_type = PNG_COLOR_TYPE_GRAY; - for (i = ibuf->x * ibuf->y; i > 0; i--) { - to[0] = from[0]; - to++; from += 4; + if (is_16bit) { + for (i = ibuf->x * ibuf->y; i > 0; i--) { + to16[0] = FTOUSHORT(from_float[0]); + to16++; from_float += 4; + } + } + else { + for (i = ibuf->x * ibuf->y; i > 0; i--) { + to[0] = from[0]; + to++; from += 4; + } } break; } @@ -203,7 +242,10 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags) fp = BLI_fopen(name, "wb"); if (!fp) { png_destroy_write_struct(&png_ptr, &info_ptr); - MEM_freeN(pixels); + if (pixels) + MEM_freeN(pixels); + if (pixels16) + MEM_freeN(pixels16); printf("imb_savepng: Cannot open file for writing: '%s'\n", name); return 0; } @@ -227,7 +269,7 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags) info_ptr, ibuf->x, ibuf->y, - 8, + is_16bit ? 16 : 8, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, @@ -268,12 +310,19 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags) /* write the file header information */ png_write_info(png_ptr, info_ptr); +#ifdef __LITTLE_ENDIAN__ + png_set_swap(png_ptr); +#endif + /* 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("imb_savepng: Cannot allocate row-pointers array for file '%s'\n", name); png_destroy_write_struct(&png_ptr, &info_ptr); - MEM_freeN(pixels); + if (pixels) + MEM_freeN(pixels); + if (pixels16) + MEM_freeN(pixels16); if (fp) { fclose(fp); } @@ -281,9 +330,17 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags) } /* 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)); + if (is_16bit) { + for (i = 0; i < ibuf->y; i++) { + row_pointers[ibuf->y - 1 - i] = (png_bytep) + ((unsigned short *)pixels16 + (i * ibuf->x) * bytesperpixel); + } + } + else { + 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)); + } } /* write out the entire image data in one call */ @@ -293,7 +350,10 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags) png_write_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_write_struct(&png_ptr, &info_ptr); @@ -394,6 +454,8 @@ ImBuf *imb_loadpng(unsigned char *mem, size_t size, int flags, char colorspace[I if (ibuf) { ibuf->ftype = PNG; + if (bit_depth == 16) + ibuf->ftype |= PNG_16BIT; if (png_get_valid(png_ptr, info_ptr, PNG_INFO_pHYs)) { int unit_type; |