[4/5] png: Add support for 16 bpc png reading as floating point format

Submitted by Maarten Lankhorst on Dec. 3, 2018, 2:13 p.m.

Details

Message ID 20181203141343.12875-5-maarten.lankhorst@linux.intel.com
State New
Series "Implement floating point support in cairo."
Headers show

Commit Message

Maarten Lankhorst Dec. 3, 2018, 2:13 p.m.
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>
---
 src/cairo-png.c | 68 +++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 60 insertions(+), 8 deletions(-)

Patch hide | download patch | download mbox

diff --git a/src/cairo-png.c b/src/cairo-png.c
index 2e0520ae8fac..0037dd531b30 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);