summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaarten Lankhorst <maarten.lankhorst@linux.intel.com>2018-12-03 15:13:42 +0100
committerBryce Harrington <bryce@bryceharrington.org>2019-01-07 19:14:16 -0800
commitd061570a70c12ebf43e9aa914a9cbb87b616a979 (patch)
tree86a7664f75a5ac5c591ec8d7f3b0f1545c35c930
parent1df0a68460ed0c9e16089919002d8c58faccdab5 (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.c68
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);