diff options
author | Maarten Lankhorst <maarten.lankhorst@linux.intel.com> | 2018-12-03 15:13:42 +0100 |
---|---|---|
committer | Bryce Harrington <bryce@bryceharrington.org> | 2019-01-07 19:14:16 -0800 |
commit | d061570a70c12ebf43e9aa914a9cbb87b616a979 (patch) | |
tree | 86a7664f75a5ac5c591ec8d7f3b0f1545c35c930 | |
parent | 1df0a68460ed0c9e16089919002d8c58faccdab5 (diff) |
png: Add support for 16 bpc png reading as floating point format
Similar to writing png, don't squash 16 bpc to 8 bpc and create
a float surface to contain the image.
Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Reviewed-by: Bryce Harrington <bryce@bryceharrington.org>
-rw-r--r-- | src/cairo-png.c | 68 |
1 files changed, 60 insertions, 8 deletions
diff --git a/src/cairo-png.c b/src/cairo-png.c index 2e0520ae8..0037dd531 100644 --- a/src/cairo-png.c +++ b/src/cairo-png.c @@ -142,6 +142,33 @@ unpremultiply_float (float *f, uint16_t *d16, unsigned width) } } +static void +premultiply_float (float *f, const uint16_t *d16, unsigned int width) +{ + unsigned int i = width; + + /* Convert d16 in place back to float */ + while (i--) { + float a = d16[i * 4 + 3] / 65535.f; + + f[i * 4 + 3] = a; + f[i * 4 + 2] = (float)d16[i * 4 + 2] / 65535.f * a; + f[i * 4 + 1] = (float)d16[i * 4 + 1] / 65535.f * a; + f[i * 4] = (float)d16[i * 4] / 65535.f * a; + } +} + +static void convert_u16_to_float (float *f, const uint16_t *d16, unsigned int width) +{ + /* Convert d16 in place back to float */ + unsigned int i = width; + + while (i--) { + f[i * 3 + 2] = (float)d16[i * 4 + 2] / 65535.f; + f[i * 3 + 1] = (float)d16[i * 4 + 1] / 65535.f; + f[i * 3] = (float)d16[i * 4] / 65535.f; + } +} static void convert_float_to_u16 (float *f, uint16_t *d16, unsigned int width) @@ -700,9 +727,6 @@ read_png (struct png_read_closure_t *png_closure) if (png_get_valid (png, info, PNG_INFO_tRNS)) png_set_tRNS_to_alpha (png); - if (depth == 16) - png_set_strip_16 (png); - if (depth < 8) png_set_packing (png); @@ -723,7 +747,7 @@ read_png (struct png_read_closure_t *png_closure) png_get_IHDR (png, info, &png_width, &png_height, &depth, &color_type, &interlace, NULL, NULL); - if (depth != 8 || + if ((depth != 8 && depth != 16) || ! (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA)) { @@ -737,13 +761,21 @@ read_png (struct png_read_closure_t *png_closure) /* fall-through just in case ;-) */ case PNG_COLOR_TYPE_RGB_ALPHA: - format = CAIRO_FORMAT_ARGB32; - png_set_read_user_transform_fn (png, premultiply_data); + if (depth == 8) { + format = CAIRO_FORMAT_ARGB32; + png_set_read_user_transform_fn (png, premultiply_data); + } else { + format = CAIRO_FORMAT_RGBA128F; + } break; case PNG_COLOR_TYPE_RGB: - format = CAIRO_FORMAT_RGB24; - png_set_read_user_transform_fn (png, convert_bytes_to_data); + if (depth == 8) { + format = CAIRO_FORMAT_RGB24; + png_set_read_user_transform_fn (png, convert_bytes_to_data); + } else { + format = CAIRO_FORMAT_RGB96F; + } break; } @@ -776,6 +808,26 @@ read_png (struct png_read_closure_t *png_closure) goto BAIL; } + if (format == CAIRO_FORMAT_RGBA128F) { + i = png_height; + + while (i--) { + float *float_line = (float *)row_pointers[i]; + uint16_t *u16_line = (uint16_t *)row_pointers[i]; + + premultiply_float (float_line, u16_line, png_width); + } + } else if (format == CAIRO_FORMAT_RGB96F) { + i = png_height; + + while (i--) { + float *float_line = (float *)row_pointers[i]; + uint16_t *u16_line = (uint16_t *)row_pointers[i]; + + convert_u16_to_float (float_line, u16_line, png_width); + } + } + surface = cairo_image_surface_create_for_data (data, format, png_width, png_height, stride); |