Discussion:
[cairo] [PATCH v2 4/5] png: Add support for 16 bpc png reading as floating point format
Maarten Lankhorst
2018-08-06 14:59:30 UTC
Permalink
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 <***@linux.intel.com>
---
src/cairo-png.c | 68 +++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 60 insertions(+), 8 deletions(-)

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);
--
2.18.0
--
cairo mailing list
***@cairographics.org
https://lists.cairographics.org/mailman/lis
Maarten Lankhorst
2018-08-06 14:59:28 UTC
Permalink
IGT wants to add support for planes with a bit depth >10, which
requires a higher precision format than we have currently.

I'm using RGBA as format, because of its existence in OpenGL.
With the new formats we can directly convert our bytes to half float,
or multiply a colro vector with a matrix to go to the Y'CbCr colorspace.

Signed-off-by: Maarten Lankhorst <***@linux.intel.com>
---
perf/micro/fill-clip.c | 2 ++
perf/micro/pixel.c | 2 ++
src/cairo-debug.c | 6 +++++
src/cairo-image-compositor.c | 4 ++++
src/cairo-image-source.c | 27 ++++++++++++++++++++++
src/cairo-image-surface.c | 16 +++++++++++++
src/cairo-png.c | 2 ++
src/cairo-script-surface.c | 20 ++++++++++++++++
src/cairo-xlib-display.c | 12 ++++++++++
src/cairo.h | 6 ++++-
src/cairoint.h | 2 +-
test/any2ppm.c | 2 ++
test/map-to-image.c | 2 ++
test/png.c | 2 ++
util/cairo-script/cairo-script-operators.c | 12 ++++++++++
util/cairo-trace/trace.c | 10 ++++++++
16 files changed, 125 insertions(+), 2 deletions(-)

diff --git a/perf/micro/fill-clip.c b/perf/micro/fill-clip.c
index 2d014aca832c..f9802705f4d0 100644
--- a/perf/micro/fill-clip.c
+++ b/perf/micro/fill-clip.c
@@ -92,6 +92,8 @@ direct (cairo_t *cr, int width, int height, int loops)
case CAIRO_FORMAT_RGB24:
case CAIRO_FORMAT_RGB30:
case CAIRO_FORMAT_ARGB32: bpp = 32; break;
+ case CAIRO_FORMAT_RGB96F: bpp = 96; break;
+ case CAIRO_FORMAT_RGBA128F: bpp = 128; break;
}

cairo_perf_timer_start ();
diff --git a/perf/micro/pixel.c b/perf/micro/pixel.c
index b600b5170d86..85a42e4427bc 100644
--- a/perf/micro/pixel.c
+++ b/perf/micro/pixel.c
@@ -51,6 +51,8 @@ pixel_direct (cairo_t *cr, int width, int height, int loops)
case CAIRO_FORMAT_RGB24:
case CAIRO_FORMAT_RGB30:
case CAIRO_FORMAT_ARGB32: bpp = 32; break;
+ case CAIRO_FORMAT_RGB96F: bpp = 96; break;
+ case CAIRO_FORMAT_RGBA128F: bpp = 128; break;
}

cairo_perf_timer_start ();
diff --git a/src/cairo-debug.c b/src/cairo-debug.c
index 6005060d4a0c..760f092e3a8b 100644
--- a/src/cairo-debug.c
+++ b/src/cairo-debug.c
@@ -131,6 +131,12 @@ _cairo_debug_check_image_surface_is_defined (const cairo_surface_t *surface)
case CAIRO_FORMAT_ARGB32:
width = image->width*4;
break;
+ case CAIRO_FORMAT_RGB96F:
+ width = image->width*12;
+ break;
+ case CAIRO_FORMAT_RGBA128F:
+ width = image->width*16;
+ break;
case CAIRO_FORMAT_INVALID:
default:
/* XXX compute width from pixman bpp */
diff --git a/src/cairo-image-compositor.c b/src/cairo-image-compositor.c
index bbf4cf2281da..434f67e59b74 100644
--- a/src/cairo-image-compositor.c
+++ b/src/cairo-image-compositor.c
@@ -2845,6 +2845,8 @@ inplace_renderer_init (cairo_image_span_renderer_t *r,
case CAIRO_FORMAT_A1:
case CAIRO_FORMAT_RGB16_565:
case CAIRO_FORMAT_RGB30:
+ case CAIRO_FORMAT_RGB96F:
+ case CAIRO_FORMAT_RGBA128F:
case CAIRO_FORMAT_INVALID:
default: break;
}
@@ -2860,6 +2862,8 @@ inplace_renderer_init (cairo_image_span_renderer_t *r,
case CAIRO_FORMAT_A1:
case CAIRO_FORMAT_RGB16_565:
case CAIRO_FORMAT_RGB30:
+ case CAIRO_FORMAT_RGB96F:
+ case CAIRO_FORMAT_RGBA128F:
case CAIRO_FORMAT_INVALID:
default: break;
}
diff --git a/src/cairo-image-source.c b/src/cairo-image-source.c
index 0b50afcad327..c56845ab2d91 100644
--- a/src/cairo-image-source.c
+++ b/src/cairo-image-source.c
@@ -455,6 +455,7 @@ static pixman_image_t *
_pixel_to_solid (cairo_image_surface_t *image, int x, int y)
{
uint32_t pixel;
+ float *rgba;
pixman_color_t color;

TRACE ((stderr, "%s\n", __FUNCTION__));
@@ -523,6 +524,32 @@ _pixel_to_solid (cairo_image_surface_t *image, int x, int y)
color.green = (pixel >> 8 & 0xff) | (pixel & 0xff00);
color.blue = (pixel & 0xff) | (pixel << 8 & 0xff00);
return pixman_image_create_solid_fill (&color);
+
+ case CAIRO_FORMAT_RGB96F:
+ case CAIRO_FORMAT_RGBA128F:
+ if (image->format == CAIRO_FORMAT_RGBA128F)
+ {
+ rgba = (float *)&image->data[y * image->stride + 16 * x];
+ color.alpha = 65535.f * rgba[3];
+
+ if (color.alpha == 0)
+ return _pixman_transparent_image ();
+ }
+ else
+ {
+ rgba = (float *)&image->data[y * image->stride + 12 * x];
+ color.alpha = 0xffff;
+ }
+
+ if (color.alpha == 0xffff && rgba[0] == 0.f && rgba[1] == 0.f && rgba[2] == 0.f)
+ return _pixman_black_image ();
+ if (color.alpha == 0xffff && rgba[0] == 1.f && rgba[1] == 1.f && rgba[2] == 1.f)
+ return _pixman_white_image ();
+
+ color.red = rgba[0] * 65535.f;
+ color.green = rgba[1] * 65535.f;
+ color.blue = rgba[2] * 65535.f;
+ return pixman_image_create_solid_fill (&color);
}
}

diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index 2ee1cad42cf7..0e17f3a1619c 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -93,6 +93,10 @@ cairo_format_t
_cairo_format_from_pixman_format (pixman_format_code_t pixman_format)
{
switch (pixman_format) {
+ case PIXMAN_rgba_float:
+ return CAIRO_FORMAT_RGBA128F;
+ case PIXMAN_rgb_float:
+ return CAIRO_FORMAT_RGB96F;
case PIXMAN_a8r8g8b8:
return CAIRO_FORMAT_ARGB32;
case PIXMAN_x2r10g10b10:
@@ -322,6 +326,12 @@ _cairo_format_to_pixman_format_code (cairo_format_t format)
case CAIRO_FORMAT_RGB16_565:
ret = PIXMAN_r5g6b5;
break;
+ case CAIRO_FORMAT_RGB96F:
+ ret = PIXMAN_rgb_float;
+ break;
+ case CAIRO_FORMAT_RGBA128F:
+ ret = PIXMAN_rgba_float;
+ break;
case CAIRO_FORMAT_ARGB32:
case CAIRO_FORMAT_INVALID:
default:
@@ -693,8 +703,10 @@ _cairo_format_from_content (cairo_content_t content)
_cairo_content_from_format (cairo_format_t format)
{
switch (format) {
+ case CAIRO_FORMAT_RGBA128F:
case CAIRO_FORMAT_ARGB32:
return CAIRO_CONTENT_COLOR_ALPHA;
+ case CAIRO_FORMAT_RGB96F:
case CAIRO_FORMAT_RGB30:
return CAIRO_CONTENT_COLOR;
case CAIRO_FORMAT_RGB24:
@@ -716,6 +728,10 @@ _cairo_content_from_format (cairo_format_t format)
_cairo_format_bits_per_pixel (cairo_format_t format)
{
switch (format) {
+ case CAIRO_FORMAT_RGBA128F:
+ return 128;
+ case CAIRO_FORMAT_RGB96F:
+ return 96;
case CAIRO_FORMAT_ARGB32:
case CAIRO_FORMAT_RGB30:
case CAIRO_FORMAT_RGB24:
diff --git a/src/cairo-png.c b/src/cairo-png.c
index ab0b9d0c51ea..b9fc9160a8ab 100644
--- a/src/cairo-png.c
+++ b/src/cairo-png.c
@@ -265,6 +265,8 @@ write_png (cairo_surface_t *surface,
break;
case CAIRO_FORMAT_INVALID:
case CAIRO_FORMAT_RGB16_565:
+ case CAIRO_FORMAT_RGB96F:
+ case CAIRO_FORMAT_RGBA128F:
default:
status = _cairo_error (CAIRO_STATUS_INVALID_FORMAT);
goto BAIL4;
diff --git a/src/cairo-script-surface.c b/src/cairo-script-surface.c
index 7db7dc5b0dfb..0e6bc5e893e1 100644
--- a/src/cairo-script-surface.c
+++ b/src/cairo-script-surface.c
@@ -871,6 +871,8 @@ static const char *
_format_to_string (cairo_format_t format)
{
switch (format) {
+ case CAIRO_FORMAT_RGBA128F: return "RGBA128F";
+ case CAIRO_FORMAT_RGB96F: return "RGB96F";
case CAIRO_FORMAT_ARGB32: return "ARGB32";
case CAIRO_FORMAT_RGB30: return "RGB30";
case CAIRO_FORMAT_RGB24: return "RGB24";
@@ -1315,6 +1317,18 @@ _write_image_surface (cairo_output_stream_t *output,
data += stride;
}
break;
+ case CAIRO_FORMAT_RGB96F:
+ for (row = image->height; row--; ) {
+ _cairo_output_stream_write (output, data, 12*width);
+ data += stride;
+ }
+ break;
+ case CAIRO_FORMAT_RGBA128F:
+ for (row = image->height; row--; ) {
+ _cairo_output_stream_write (output, data, 16*width);
+ data += stride;
+ }
+ break;
case CAIRO_FORMAT_INVALID:
default:
ASSERT_NOT_REACHED;
@@ -1421,6 +1435,12 @@ _emit_image_surface (cairo_script_surface_t *surface,
case CAIRO_FORMAT_ARGB32:
len = clone->width * 4;
break;
+ case CAIRO_FORMAT_RGB96F:
+ len = clone->width * 12;
+ break;
+ case CAIRO_FORMAT_RGBA128F:
+ len = clone->width * 16;
+ break;
case CAIRO_FORMAT_INVALID:
default:
ASSERT_NOT_REACHED;
diff --git a/src/cairo-xlib-display.c b/src/cairo-xlib-display.c
index add42299b4cd..108897e92a2e 100644
--- a/src/cairo-xlib-display.c
+++ b/src/cairo-xlib-display.c
@@ -383,6 +383,10 @@ _cairo_xlib_display_get_xrender_format_for_pixman(cairo_xlib_display_t *display,
XRenderPictFormat tmpl;
int mask;

+ /* No equivalent in X11 yet. */
+ if (format == PIXMAN_rgba_float || format == PIXMAN_rgb_float)
+ return NULL;
+
#define MASK(x) ((1<<(x))-1)

tmpl.depth = PIXMAN_FORMAT_DEPTH(format);
@@ -510,6 +514,14 @@ _cairo_xlib_display_get_xrender_format (cairo_xlib_display_t *display,
xrender_format = _cairo_xlib_display_get_xrender_format_for_pixman(display,
PIXMAN_x2r10g10b10);
break;
+ case CAIRO_FORMAT_RGBA128F:
+ xrender_format = _cairo_xlib_display_get_xrender_format_for_pixman(display,
+ PIXMAN_rgba_float);
+ break;
+ case CAIRO_FORMAT_RGB96F:
+ xrender_format = _cairo_xlib_display_get_xrender_format_for_pixman(display,
+ PIXMAN_rgb_float);
+ break;
case CAIRO_FORMAT_INVALID:
default:
ASSERT_NOT_REACHED;
diff --git a/src/cairo.h b/src/cairo.h
index b2386af5d920..29be5ef7e57e 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -405,6 +405,8 @@ typedef enum _cairo_content {
* with red in the upper 5 bits, then green in the middle
* 6 bits, and blue in the lower 5 bits. (Since 1.2)
* @CAIRO_FORMAT_RGB30: like RGB24 but with 10bpc. (Since 1.12)
+ * @CAIRO_FORMAT_RGB96F: 3 floats, R, G, B. (Since 1.16)
+ * @CAIRO_FORMAT_RGBA128F: 4 floats, R, G, B, A. (Since 1.16)
*
* #cairo_format_t is used to identify the memory format of
* image data.
@@ -420,7 +422,9 @@ typedef enum _cairo_format {
CAIRO_FORMAT_A8 = 2,
CAIRO_FORMAT_A1 = 3,
CAIRO_FORMAT_RGB16_565 = 4,
- CAIRO_FORMAT_RGB30 = 5
+ CAIRO_FORMAT_RGB30 = 5,
+ CAIRO_FORMAT_RGB96F = 6,
+ CAIRO_FORMAT_RGBA128F = 7
} cairo_format_t;


diff --git a/src/cairoint.h b/src/cairoint.h
index cfae18cf93bd..331ab5357ac4 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1536,7 +1536,7 @@ _cairo_surface_release_device_reference (cairo_surface_t *surface);
* in cairo-xlib-surface.c--again see -Wswitch-enum).
*/
#define CAIRO_FORMAT_VALID(format) ((format) >= CAIRO_FORMAT_ARGB32 && \
- (format) <= CAIRO_FORMAT_RGB30)
+ (format) <= CAIRO_FORMAT_RGBA128F)

/* pixman-required stride alignment in bytes. */
#define CAIRO_STRIDE_ALIGNMENT (sizeof (uint32_t))
diff --git a/test/any2ppm.c b/test/any2ppm.c
index a92412d084f1..7eb582c04d22 100644
--- a/test/any2ppm.c
+++ b/test/any2ppm.c
@@ -201,6 +201,8 @@ write_ppm (cairo_surface_t *surface, int fd)
case CAIRO_FORMAT_A1:
case CAIRO_FORMAT_RGB16_565:
case CAIRO_FORMAT_RGB30:
+ case CAIRO_FORMAT_RGB96F:
+ case CAIRO_FORMAT_RGBA128F:
case CAIRO_FORMAT_INVALID:
default:
return "unhandled image format";
diff --git a/test/map-to-image.c b/test/map-to-image.c
index 0262245a88e1..2b1799f71107 100644
--- a/test/map-to-image.c
+++ b/test/map-to-image.c
@@ -45,6 +45,8 @@ set_pixel_black(uint8_t *data, int stride,
case CAIRO_FORMAT_RGB16_565:
*(uint16_t *)(data + y * stride + 2*x) = black_pixel;
break;
+ case CAIRO_FORMAT_RGBA128F:
+ case CAIRO_FORMAT_RGB96F:
case CAIRO_FORMAT_RGB30:
case CAIRO_FORMAT_A8:
case CAIRO_FORMAT_A1:
diff --git a/test/png.c b/test/png.c
index cd11fd0d1825..a199d4867d3f 100644
--- a/test/png.c
+++ b/test/png.c
@@ -60,6 +60,8 @@ format_to_string (cairo_format_t format)
case CAIRO_FORMAT_RGB24: return "rgb24";
case CAIRO_FORMAT_RGB30: return "rgb30";
case CAIRO_FORMAT_ARGB32: return "argb32";
+ case CAIRO_FORMAT_RGB96F: return "rgb96f";
+ case CAIRO_FORMAT_RGBA128F: return "rgba128f";
case CAIRO_FORMAT_INVALID:
default: return "???";
}
diff --git a/util/cairo-script/cairo-script-operators.c b/util/cairo-script/cairo-script-operators.c
index e493311e74a0..7cdb5afb66a2 100644
--- a/util/cairo-script/cairo-script-operators.c
+++ b/util/cairo-script/cairo-script-operators.c
@@ -2967,6 +2967,12 @@ _image_read_raw (csi_t *ctx,
case CAIRO_FORMAT_ARGB32:
instride = rowlen = 4 * width;
break;
+ case CAIRO_FORMAT_RGB96F:
+ instride = rowlen = 12 * width;
+ break;
+ case CAIRO_FORMAT_RGBA128F:
+ instride = rowlen = 16 * width;
+ break;
}
len = rowlen * height;

@@ -3066,6 +3072,8 @@ err_decompress:
#endif
}
break;
+ case CAIRO_FORMAT_RGB96F:
+ case CAIRO_FORMAT_RGBA128F:
case CAIRO_FORMAT_RGB30:
case CAIRO_FORMAT_INVALID:
case CAIRO_FORMAT_ARGB32:
@@ -3155,6 +3163,8 @@ err_decompress:
#endif
}
break;
+ case CAIRO_FORMAT_RGBA128F:
+ case CAIRO_FORMAT_RGB96F:
case CAIRO_FORMAT_RGB30:
case CAIRO_FORMAT_INVALID:
case CAIRO_FORMAT_ARGB32:
@@ -3191,6 +3201,8 @@ err_decompress:
case CAIRO_FORMAT_A8:
break;

+ case CAIRO_FORMAT_RGBA128F:
+ case CAIRO_FORMAT_RGB96F:
case CAIRO_FORMAT_RGB30:
case CAIRO_FORMAT_RGB24:
case CAIRO_FORMAT_INVALID:
diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c
index 7a43b0f2c341..0f271d8a2671 100644
--- a/util/cairo-trace/trace.c
+++ b/util/cairo-trace/trace.c
@@ -1510,6 +1510,8 @@ _format_to_string (cairo_format_t format)
#define f(name) case CAIRO_FORMAT_ ## name: return #name
switch (format) {
f(INVALID);
+ f(RGBA128F);
+ f(RGB96F);
f(ARGB32);
f(RGB30);
f(RGB24);
@@ -1527,8 +1529,10 @@ _format_to_content_string (cairo_format_t format)
switch (format) {
case CAIRO_FORMAT_INVALID:
return "INVALID";
+ case CAIRO_FORMAT_RGBA128F:
case CAIRO_FORMAT_ARGB32:
return "COLOR_ALPHA";
+ case CAIRO_FORMAT_RGB96F:
case CAIRO_FORMAT_RGB30:
case CAIRO_FORMAT_RGB24:
case CAIRO_FORMAT_RGB16_565:
@@ -1673,6 +1677,8 @@ _emit_image (cairo_surface_t *image,
case CAIRO_FORMAT_RGB30:
case CAIRO_FORMAT_INVALID:
case CAIRO_FORMAT_ARGB32: len = 4*width; break;
+ case CAIRO_FORMAT_RGB96F: len = 12*width; break;
+ case CAIRO_FORMAT_RGBA128F: len = 16*width; break;
}

_trace_printf (" /source ");
@@ -1696,6 +1702,8 @@ _emit_image (cairo_surface_t *image,
case CAIRO_FORMAT_RGB16_565:
case CAIRO_FORMAT_RGB30:
case CAIRO_FORMAT_ARGB32:
+ case CAIRO_FORMAT_RGB96F:
+ case CAIRO_FORMAT_RGBA128F:
for (row = height; row--; ) {
_write_data (&stream, data, len);
data += stride;
@@ -1754,6 +1762,8 @@ _emit_image (cairo_surface_t *image,
data += stride;
}
break;
+ case CAIRO_FORMAT_RGB96F:
+ case CAIRO_FORMAT_RGBA128F:
case CAIRO_FORMAT_RGB30:
case CAIRO_FORMAT_ARGB32:
for (row = height; row--; ) {
--
2.18.0
--
cairo mailing list
***@cairographics.org
htt
Xenofon Papadopoulos
2018-08-14 21:07:22 UTC
Permalink
unsubscribe

On Mon, Aug 6, 2018 at 7:59 AM, Maarten Lankhorst <
Post by Maarten Lankhorst
IGT wants to add support for planes with a bit depth >10, which
requires a higher precision format than we have currently.
I'm using RGBA as format, because of its existence in OpenGL.
With the new formats we can directly convert our bytes to half float,
or multiply a colro vector with a matrix to go to the Y'CbCr colorspace.
---
perf/micro/fill-clip.c | 2 ++
perf/micro/pixel.c | 2 ++
src/cairo-debug.c | 6 +++++
src/cairo-image-compositor.c | 4 ++++
src/cairo-image-source.c | 27 ++++++++++++++++++++++
src/cairo-image-surface.c | 16 +++++++++++++
src/cairo-png.c | 2 ++
src/cairo-script-surface.c | 20 ++++++++++++++++
src/cairo-xlib-display.c | 12 ++++++++++
src/cairo.h | 6 ++++-
src/cairoint.h | 2 +-
test/any2ppm.c | 2 ++
test/map-to-image.c | 2 ++
test/png.c | 2 ++
util/cairo-script/cairo-script-operators.c | 12 ++++++++++
util/cairo-trace/trace.c | 10 ++++++++
16 files changed, 125 insertions(+), 2 deletions(-)
diff --git a/perf/micro/fill-clip.c b/perf/micro/fill-clip.c
index 2d014aca832c..f9802705f4d0 100644
--- a/perf/micro/fill-clip.c
+++ b/perf/micro/fill-clip.c
@@ -92,6 +92,8 @@ direct (cairo_t *cr, int width, int height, int loops)
case CAIRO_FORMAT_ARGB32: bpp = 32; break;
+ case CAIRO_FORMAT_RGB96F: bpp = 96; break;
+ case CAIRO_FORMAT_RGBA128F: bpp = 128; break;
}
cairo_perf_timer_start ();
diff --git a/perf/micro/pixel.c b/perf/micro/pixel.c
index b600b5170d86..85a42e4427bc 100644
--- a/perf/micro/pixel.c
+++ b/perf/micro/pixel.c
@@ -51,6 +51,8 @@ pixel_direct (cairo_t *cr, int width, int height, int loops)
case CAIRO_FORMAT_ARGB32: bpp = 32; break;
+ case CAIRO_FORMAT_RGB96F: bpp = 96; break;
+ case CAIRO_FORMAT_RGBA128F: bpp = 128; break;
}
cairo_perf_timer_start ();
diff --git a/src/cairo-debug.c b/src/cairo-debug.c
index 6005060d4a0c..760f092e3a8b 100644
--- a/src/cairo-debug.c
+++ b/src/cairo-debug.c
@@ -131,6 +131,12 @@ _cairo_debug_check_image_surface_is_defined (const
cairo_surface_t *surface)
width = image->width*4;
break;
+ width = image->width*12;
+ break;
+ width = image->width*16;
+ break;
/* XXX compute width from pixman bpp */
diff --git a/src/cairo-image-compositor.c b/src/cairo-image-compositor.c
index bbf4cf2281da..434f67e59b74 100644
--- a/src/cairo-image-compositor.c
+++ b/src/cairo-image-compositor.c
@@ -2845,6 +2845,8 @@ inplace_renderer_init (cairo_image_span_renderer_t
*r,
default: break;
}
@@ -2860,6 +2862,8 @@ inplace_renderer_init (cairo_image_span_renderer_t
*r,
default: break;
}
diff --git a/src/cairo-image-source.c b/src/cairo-image-source.c
index 0b50afcad327..c56845ab2d91 100644
--- a/src/cairo-image-source.c
+++ b/src/cairo-image-source.c
@@ -455,6 +455,7 @@ static pixman_image_t *
_pixel_to_solid (cairo_image_surface_t *image, int x, int y)
{
uint32_t pixel;
+ float *rgba;
pixman_color_t color;
TRACE ((stderr, "%s\n", __FUNCTION__));
@@ -523,6 +524,32 @@ _pixel_to_solid (cairo_image_surface_t *image, int x, int y)
color.green = (pixel >> 8 & 0xff) | (pixel & 0xff00);
color.blue = (pixel & 0xff) | (pixel << 8 & 0xff00);
return pixman_image_create_solid_fill (&color);
+
+ if (image->format == CAIRO_FORMAT_RGBA128F)
+ {
+ rgba = (float *)&image->data[y * image->stride + 16 * x];
+ color.alpha = 65535.f * rgba[3];
+
+ if (color.alpha == 0)
+ return _pixman_transparent_image ();
+ }
+ else
+ {
+ rgba = (float *)&image->data[y * image->stride + 12 * x];
+ color.alpha = 0xffff;
+ }
+
+ if (color.alpha == 0xffff && rgba[0] == 0.f && rgba[1] == 0.f &&
rgba[2] == 0.f)
+ return _pixman_black_image ();
+ if (color.alpha == 0xffff && rgba[0] == 1.f && rgba[1] == 1.f &&
rgba[2] == 1.f)
+ return _pixman_white_image ();
+
+ color.red = rgba[0] * 65535.f;
+ color.green = rgba[1] * 65535.f;
+ color.blue = rgba[2] * 65535.f;
+ return pixman_image_create_solid_fill (&color);
}
}
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index 2ee1cad42cf7..0e17f3a1619c 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -93,6 +93,10 @@ cairo_format_t
_cairo_format_from_pixman_format (pixman_format_code_t pixman_format)
{
switch (pixman_format) {
+ return CAIRO_FORMAT_RGBA128F;
+ return CAIRO_FORMAT_RGB96F;
return CAIRO_FORMAT_ARGB32;
@@ -322,6 +326,12 @@ _cairo_format_to_pixman_format_code (cairo_format_t format)
ret = PIXMAN_r5g6b5;
break;
+ ret = PIXMAN_rgb_float;
+ break;
+ ret = PIXMAN_rgba_float;
+ break;
@@ -693,8 +703,10 @@ _cairo_format_from_content (cairo_content_t content)
_cairo_content_from_format (cairo_format_t format)
{
switch (format) {
return CAIRO_CONTENT_COLOR_ALPHA;
return CAIRO_CONTENT_COLOR;
@@ -716,6 +728,10 @@ _cairo_content_from_format (cairo_format_t format)
_cairo_format_bits_per_pixel (cairo_format_t format)
{
switch (format) {
+ return 128;
+ return 96;
diff --git a/src/cairo-png.c b/src/cairo-png.c
index ab0b9d0c51ea..b9fc9160a8ab 100644
--- a/src/cairo-png.c
+++ b/src/cairo-png.c
@@ -265,6 +265,8 @@ write_png (cairo_surface_t *surface,
break;
status = _cairo_error (CAIRO_STATUS_INVALID_FORMAT);
goto BAIL4;
diff --git a/src/cairo-script-surface.c b/src/cairo-script-surface.c
index 7db7dc5b0dfb..0e6bc5e893e1 100644
--- a/src/cairo-script-surface.c
+++ b/src/cairo-script-surface.c
@@ -871,6 +871,8 @@ static const char *
_format_to_string (cairo_format_t format)
{
switch (format) {
+ case CAIRO_FORMAT_RGBA128F: return "RGBA128F";
+ case CAIRO_FORMAT_RGB96F: return "RGB96F";
case CAIRO_FORMAT_ARGB32: return "ARGB32";
case CAIRO_FORMAT_RGB30: return "RGB30";
case CAIRO_FORMAT_RGB24: return "RGB24";
@@ -1315,6 +1317,18 @@ _write_image_surface (cairo_output_stream_t *output,
data += stride;
}
break;
+ for (row = image->height; row--; ) {
+ _cairo_output_stream_write (output, data, 12*width);
+ data += stride;
+ }
+ break;
+ for (row = image->height; row--; ) {
+ _cairo_output_stream_write (output, data, 16*width);
+ data += stride;
+ }
+ break;
ASSERT_NOT_REACHED;
@@ -1421,6 +1435,12 @@ _emit_image_surface (cairo_script_surface_t *surface,
len = clone->width * 4;
break;
+ len = clone->width * 12;
+ break;
+ len = clone->width * 16;
+ break;
ASSERT_NOT_REACHED;
diff --git a/src/cairo-xlib-display.c b/src/cairo-xlib-display.c
index add42299b4cd..108897e92a2e 100644
--- a/src/cairo-xlib-display.c
+++ b/src/cairo-xlib-display.c
@@ -383,6 +383,10 @@ _cairo_xlib_display_get_xrender_format_for_pixman(cairo_xlib_display_t
*display,
XRenderPictFormat tmpl;
int mask;
+ /* No equivalent in X11 yet. */
+ if (format == PIXMAN_rgba_float || format == PIXMAN_rgb_float)
+ return NULL;
+
#define MASK(x) ((1<<(x))-1)
tmpl.depth = PIXMAN_FORMAT_DEPTH(format);
@@ -510,6 +514,14 @@ _cairo_xlib_display_get_xrender_format
(cairo_xlib_display_t *display,
xrender_format = _cairo_xlib_display_get_
xrender_format_for_pixman(display,
PIXMAN_x2r10g10b10);
break;
+ xrender_format = _cairo_xlib_display_get_
xrender_format_for_pixman(display,
+
PIXMAN_rgba_float);
+ break;
+ xrender_format = _cairo_xlib_display_get_
xrender_format_for_pixman(display,
+
PIXMAN_rgb_float);
+ break;
ASSERT_NOT_REACHED;
diff --git a/src/cairo.h b/src/cairo.h
index b2386af5d920..29be5ef7e57e 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -405,6 +405,8 @@ typedef enum _cairo_content {
* with red in the upper 5 bits, then green in the middle
* 6 bits, and blue in the lower 5 bits. (Since 1.2)
*
* #cairo_format_t is used to identify the memory format of
* image data.
@@ -420,7 +422,9 @@ typedef enum _cairo_format {
CAIRO_FORMAT_A8 = 2,
CAIRO_FORMAT_A1 = 3,
CAIRO_FORMAT_RGB16_565 = 4,
- CAIRO_FORMAT_RGB30 = 5
+ CAIRO_FORMAT_RGB30 = 5,
+ CAIRO_FORMAT_RGB96F = 6,
+ CAIRO_FORMAT_RGBA128F = 7
} cairo_format_t;
diff --git a/src/cairoint.h b/src/cairoint.h
index cfae18cf93bd..331ab5357ac4 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1536,7 +1536,7 @@ _cairo_surface_release_device_reference
(cairo_surface_t *surface);
* in cairo-xlib-surface.c--again see -Wswitch-enum).
*/
#define CAIRO_FORMAT_VALID(format) ((format) >= CAIRO_FORMAT_ARGB32 &&
\
- (format) <= CAIRO_FORMAT_RGB30)
+ (format) <= CAIRO_FORMAT_RGBA128F)
/* pixman-required stride alignment in bytes. */
#define CAIRO_STRIDE_ALIGNMENT (sizeof (uint32_t))
diff --git a/test/any2ppm.c b/test/any2ppm.c
index a92412d084f1..7eb582c04d22 100644
--- a/test/any2ppm.c
+++ b/test/any2ppm.c
@@ -201,6 +201,8 @@ write_ppm (cairo_surface_t *surface, int fd)
return "unhandled image format";
diff --git a/test/map-to-image.c b/test/map-to-image.c
index 0262245a88e1..2b1799f71107 100644
--- a/test/map-to-image.c
+++ b/test/map-to-image.c
@@ -45,6 +45,8 @@ set_pixel_black(uint8_t *data, int stride,
*(uint16_t *)(data + y * stride + 2*x) = black_pixel;
break;
diff --git a/test/png.c b/test/png.c
index cd11fd0d1825..a199d4867d3f 100644
--- a/test/png.c
+++ b/test/png.c
@@ -60,6 +60,8 @@ format_to_string (cairo_format_t format)
case CAIRO_FORMAT_RGB24: return "rgb24";
case CAIRO_FORMAT_RGB30: return "rgb30";
case CAIRO_FORMAT_ARGB32: return "argb32";
+ case CAIRO_FORMAT_RGB96F: return "rgb96f";
+ case CAIRO_FORMAT_RGBA128F: return "rgba128f";
default: return "???";
}
diff --git a/util/cairo-script/cairo-script-operators.c
b/util/cairo-script/cairo-script-operators.c
index e493311e74a0..7cdb5afb66a2 100644
--- a/util/cairo-script/cairo-script-operators.c
+++ b/util/cairo-script/cairo-script-operators.c
@@ -2967,6 +2967,12 @@ _image_read_raw (csi_t *ctx,
instride = rowlen = 4 * width;
break;
+ instride = rowlen = 12 * width;
+ break;
+ instride = rowlen = 16 * width;
+ break;
}
len = rowlen * height;
#endif
}
break;
#endif
}
break;
break;
diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c
index 7a43b0f2c341..0f271d8a2671 100644
--- a/util/cairo-trace/trace.c
+++ b/util/cairo-trace/trace.c
@@ -1510,6 +1510,8 @@ _format_to_string (cairo_format_t format)
#define f(name) case CAIRO_FORMAT_ ## name: return #name
switch (format) {
f(INVALID);
+ f(RGBA128F);
+ f(RGB96F);
f(ARGB32);
f(RGB30);
f(RGB24);
@@ -1527,8 +1529,10 @@ _format_to_content_string (cairo_format_t format)
switch (format) {
return "INVALID";
return "COLOR_ALPHA";
@@ -1673,6 +1677,8 @@ _emit_image (cairo_surface_t *image,
case CAIRO_FORMAT_ARGB32: len = 4*width; break;
+ case CAIRO_FORMAT_RGB96F: len = 12*width; break;
+ case CAIRO_FORMAT_RGBA128F: len = 16*width; break;
}
_trace_printf (" /source ");
@@ -1696,6 +1702,8 @@ _emit_image (cairo_surface_t *image,
for (row = height; row--; ) {
_write_data (&stream, data, len);
data += stride;
@@ -1754,6 +1762,8 @@ _emit_image (cairo_surface_t *image,
data += stride;
}
break;
for (row = height; row--; ) {
--
2.18.0
--
cairo mailing list
https://lists.cairographics.org/mailman/listinfo/cairo
Maarten Lankhorst
2018-08-06 14:59:29 UTC
Permalink
_cairo_image_surface_coerce will round down the image to a lower
bpp when using one of the floating point formats, so don't coerce those.
This makes the code actually work for those formats.

Because a float takes more storage than u16, we have to convert float
to u16 before calling png_write_image, because png_write
doesn't give us back the original row data, but an in-place copy.

With these changes we can dump floating point files with the highest
possible accuracy, with floats clamped between 0 and 1.

Signed-off-by: Maarten Lankhorst <***@linux.intel.com>
---
src/cairo-png.c | 108 +++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 97 insertions(+), 11 deletions(-)

diff --git a/src/cairo-png.c b/src/cairo-png.c
index b9fc9160a8ab..2e0520ae8fac 100644
--- a/src/cairo-png.c
+++ b/src/cairo-png.c
@@ -105,6 +105,57 @@ unpremultiply_data (png_structp png, png_row_infop row_info, png_bytep data)
}
}

+static uint16_t f_to_u16(float val)
+{
+ if (val < 0)
+ return 0;
+ else if (val > 1)
+ return 65535;
+ else
+ return (uint16_t)(val * 65535.f);
+}
+
+static void
+unpremultiply_float (float *f, uint16_t *d16, unsigned width)
+{
+ unsigned int i;
+
+ for (i = 0; i < width; i++) {
+ float r, g, b, a;
+
+ r = *f++;
+ g = *f++;
+ b = *f++;
+ a = *f++;
+
+ if (a > 0) {
+ *d16++ = f_to_u16(r / a);
+ *d16++ = f_to_u16(g / a);
+ *d16++ = f_to_u16(b / a);
+ *d16++ = f_to_u16(a);
+ } else {
+ *d16++ = 0;
+ *d16++ = 0;
+ *d16++ = 0;
+ *d16++ = 0;
+ }
+ }
+}
+
+
+static void
+convert_float_to_u16 (float *f, uint16_t *d16, unsigned int width)
+{
+ unsigned int i;
+
+ for (i = 0; i < width; i++) {
+ *d16++ = f_to_u16(*f++);
+ *d16++ = f_to_u16(*f++);
+ *d16++ = f_to_u16(*f++);
+ *d16++ = 0;
+ }
+}
+
/* Converts native endian xRGB => RGBx bytes */
static void
convert_data_to_bytes (png_structp png, png_row_infop row_info, png_bytep data)
@@ -182,6 +233,7 @@ write_png (cairo_surface_t *surface,
png_color_16 white;
int png_color_type;
int bpc;
+ unsigned char *volatile u16_copy = NULL;

status = _cairo_surface_acquire_source_image (surface,
&image,
@@ -198,11 +250,22 @@ write_png (cairo_surface_t *surface,
goto BAIL1;
}

- /* Handle the various fallback formats (e.g. low bit-depth XServers)
- * by coercing them to a simpler format using pixman.
- */
- clone = _cairo_image_surface_coerce (image);
- status = clone->base.status;
+ /* Don't coerce to a lower resolution format */
+ if (image->format == CAIRO_FORMAT_RGB96F ||
+ image->format == CAIRO_FORMAT_RGBA128F) {
+ u16_copy = _cairo_malloc_ab (image->width * 8, image->height);
+ if (!u16_copy) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto BAIL1;
+ }
+ clone = (cairo_image_surface_t *)cairo_surface_reference (&image->base);
+ } else {
+ /* Handle the various fallback formats (e.g. low bit-depth XServers)
+ * by coercing them to a simpler format using pixman.
+ */
+ clone = _cairo_image_surface_coerce (image);
+ status = clone->base.status;
+ }
if (unlikely (status))
goto BAIL1;

@@ -212,8 +275,22 @@ write_png (cairo_surface_t *surface,
goto BAIL2;
}

- for (i = 0; i < clone->height; i++)
- rows[i] = (png_byte *) clone->data + i * clone->stride;
+ if (!u16_copy) {
+ for (i = 0; i < clone->height; i++)
+ rows[i] = (png_byte *)clone->data + i * clone->stride;
+ } else {
+ for (i = 0; i < clone->height; i++) {
+ float *float_line = (float *)&clone->data[i * clone->stride];
+ uint16_t *u16_line = (uint16_t *)&u16_copy[i * clone->width * 8];
+
+ if (image->format == CAIRO_FORMAT_RGBA128F)
+ unpremultiply_float (float_line, u16_line, clone->width);
+ else
+ convert_float_to_u16 (float_line, u16_line, clone->width);
+
+ rows[i] = (png_byte *)u16_line;
+ }
+ }

png = png_create_write_struct (PNG_LIBPNG_VER_STRING, &status,
png_simple_error_callback,
@@ -263,10 +340,16 @@ write_png (cairo_surface_t *surface,
png_set_packswap (png);
#endif
break;
- case CAIRO_FORMAT_INVALID:
- case CAIRO_FORMAT_RGB16_565:
case CAIRO_FORMAT_RGB96F:
+ bpc = 16;
+ png_color_type = PNG_COLOR_TYPE_RGB;
+ break;
case CAIRO_FORMAT_RGBA128F:
+ bpc = 16;
+ png_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
+ break;
+ case CAIRO_FORMAT_INVALID:
+ case CAIRO_FORMAT_RGB16_565:
default:
status = _cairo_error (CAIRO_STATUS_INVALID_FORMAT);
goto BAIL4;
@@ -298,9 +381,11 @@ write_png (cairo_surface_t *surface,
png_write_info (png, info);

if (png_color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
- png_set_write_user_transform_fn (png, unpremultiply_data);
+ if (clone->format != CAIRO_FORMAT_RGBA128F)
+ png_set_write_user_transform_fn (png, unpremultiply_data);
} else if (png_color_type == PNG_COLOR_TYPE_RGB) {
- png_set_write_user_transform_fn (png, convert_data_to_bytes);
+ if (clone->format != CAIRO_FORMAT_RGB96F)
+ png_set_write_user_transform_fn (png, convert_data_to_bytes);
png_set_filler (png, 0, PNG_FILLER_AFTER);
}

@@ -313,6 +398,7 @@ BAIL3:
free (rows);
BAIL2:
cairo_surface_destroy (&clone->base);
+ free (u16_copy);
BAIL1:
_cairo_surface_release_source_image (surface, image, image_extra);
--
2.18.0
--
cairo mailing list
***@cairographics.org
h
Bill Spitzak
2018-08-06 19:05:19 UTC
Permalink
Recommend the unpremultiply be written like this:

if (a > 0 && a < 1) {
... r/a ...
} else {
.... r, g, b, (a>0)?1:0;
}

The purpose is to avoid the division for a > 1.0, which will happen when
various filtering operations are done but will produce the wrong color. The
above code also leaves the color alone on transparent and treats NaN in the
alpha as 0.0, both of which I have also found useful.

It would really be nice if cairo provided an option to treat png as
premultiplied, but it is the toy interface. Just be warned that a huge
number of them are premultipled (the spec is ignored a lot!).

On Mon, Aug 6, 2018 at 7:59 AM, Maarten Lankhorst <
Post by Maarten Lankhorst
_cairo_image_surface_coerce will round down the image to a lower
bpp when using one of the floating point formats, so don't coerce those.
This makes the code actually work for those formats.
Because a float takes more storage than u16, we have to convert float
to u16 before calling png_write_image, because png_write
doesn't give us back the original row data, but an in-place copy.
With these changes we can dump floating point files with the highest
possible accuracy, with floats clamped between 0 and 1.
---
src/cairo-png.c | 108 +++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 97 insertions(+), 11 deletions(-)
diff --git a/src/cairo-png.c b/src/cairo-png.c
index b9fc9160a8ab..2e0520ae8fac 100644
--- a/src/cairo-png.c
+++ b/src/cairo-png.c
@@ -105,6 +105,57 @@ unpremultiply_data (png_structp png, png_row_infop
row_info, png_bytep data)
}
}
+static uint16_t f_to_u16(float val)
+{
+ if (val < 0)
+ return 0;
+ else if (val > 1)
+ return 65535;
+ else
+ return (uint16_t)(val * 65535.f);
+}
+
+static void
+unpremultiply_float (float *f, uint16_t *d16, unsigned width)
+{
+ unsigned int i;
+
+ for (i = 0; i < width; i++) {
+ float r, g, b, a;
+
+ r = *f++;
+ g = *f++;
+ b = *f++;
+ a = *f++;
+
+ if (a > 0) {
+ *d16++ = f_to_u16(r / a);
+ *d16++ = f_to_u16(g / a);
+ *d16++ = f_to_u16(b / a);
+ *d16++ = f_to_u16(a);
+ } else {
+ *d16++ = 0;
+ *d16++ = 0;
+ *d16++ = 0;
+ *d16++ = 0;
+ }
+ }
+}
+
+
+static void
+convert_float_to_u16 (float *f, uint16_t *d16, unsigned int width)
+{
+ unsigned int i;
+
+ for (i = 0; i < width; i++) {
+ *d16++ = f_to_u16(*f++);
+ *d16++ = f_to_u16(*f++);
+ *d16++ = f_to_u16(*f++);
+ *d16++ = 0;
+ }
+}
+
/* Converts native endian xRGB => RGBx bytes */
static void
convert_data_to_bytes (png_structp png, png_row_infop row_info, png_bytep data)
@@ -182,6 +233,7 @@ write_png (cairo_surface_t *surface,
png_color_16 white;
int png_color_type;
int bpc;
+ unsigned char *volatile u16_copy = NULL;
status = _cairo_surface_acquire_source_image (surface,
&image,
@@ -198,11 +250,22 @@ write_png (cairo_surface_t *surface,
goto BAIL1;
}
- /* Handle the various fallback formats (e.g. low bit-depth XServers)
- * by coercing them to a simpler format using pixman.
- */
- clone = _cairo_image_surface_coerce (image);
- status = clone->base.status;
+ /* Don't coerce to a lower resolution format */
+ if (image->format == CAIRO_FORMAT_RGB96F ||
+ image->format == CAIRO_FORMAT_RGBA128F) {
+ u16_copy = _cairo_malloc_ab (image->width * 8, image->height);
+ if (!u16_copy) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto BAIL1;
+ }
+ clone = (cairo_image_surface_t *)cairo_surface_reference
(&image->base);
+ } else {
+ /* Handle the various fallback formats (e.g. low bit-depth
XServers)
+ * by coercing them to a simpler format using pixman.
+ */
+ clone = _cairo_image_surface_coerce (image);
+ status = clone->base.status;
+ }
if (unlikely (status))
goto BAIL1;
@@ -212,8 +275,22 @@ write_png (cairo_surface_t *surface,
goto BAIL2;
}
- for (i = 0; i < clone->height; i++)
- rows[i] = (png_byte *) clone->data + i * clone->stride;
+ if (!u16_copy) {
+ for (i = 0; i < clone->height; i++)
+ rows[i] = (png_byte *)clone->data + i * clone->stride;
+ } else {
+ for (i = 0; i < clone->height; i++) {
+ float *float_line = (float *)&clone->data[i * clone->stride];
+ uint16_t *u16_line = (uint16_t *)&u16_copy[i * clone->width *
8];
+
+ if (image->format == CAIRO_FORMAT_RGBA128F)
+ unpremultiply_float (float_line, u16_line, clone->width);
+ else
+ convert_float_to_u16 (float_line, u16_line, clone->width);
+
+ rows[i] = (png_byte *)u16_line;
+ }
+ }
png = png_create_write_struct (PNG_LIBPNG_VER_STRING, &status,
png_simple_error_callback,
@@ -263,10 +340,16 @@ write_png (cairo_surface_t *surface,
png_set_packswap (png);
#endif
break;
+ bpc = 16;
+ png_color_type = PNG_COLOR_TYPE_RGB;
+ break;
+ bpc = 16;
+ png_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
+ break;
status = _cairo_error (CAIRO_STATUS_INVALID_FORMAT);
goto BAIL4;
@@ -298,9 +381,11 @@ write_png (cairo_surface_t *surface,
png_write_info (png, info);
if (png_color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
- png_set_write_user_transform_fn (png, unpremultiply_data);
+ if (clone->format != CAIRO_FORMAT_RGBA128F)
+ png_set_write_user_transform_fn (png, unpremultiply_data);
} else if (png_color_type == PNG_COLOR_TYPE_RGB) {
- png_set_write_user_transform_fn (png, convert_data_to_bytes);
+ if (clone->format != CAIRO_FORMAT_RGB96F)
+ png_set_write_user_transform_fn (png, convert_data_to_bytes);
png_set_filler (png, 0, PNG_FILLER_AFTER);
}
free (rows);
cairo_surface_destroy (&clone->base);
+ free (u16_copy);
_cairo_surface_release_source_image (surface, image, image_extra);
--
2.18.0
--
cairo mailing list
https://lists.cairographics.org/mailman/listinfo/cairo
Maarten Lankhorst
2018-08-07 09:04:26 UTC
Permalink
Hey,
   if (a > 0 && a < 1) {
      ... r/a ...
   } else {
      .... r, g, b, (a>0)?1:0;
   }
The purpose is to avoid the division for a > 1.0, which will happen when various filtering operations are done but will produce the wrong color. The above code also leaves the color alone on transparent and treats NaN in the alpha as 0.0, both of which I have also found useful.
It would really be nice if cairo provided an option to treat png as premultiplied, but it is the toy interface. Just be warned that a huge number of them are premultipled (the spec is ignored a lot!).
Yeah I guess premultiplied could be a problem, but I think as long as we stick to the spec and are able to read
files we wrote in the same way, we should be fine. Anything else would really be outside the scope of the png support.  :)
Did you find anything else while looking at the patch series?

~Maarten
_cairo_image_surface_coerce will round down the image to a lower
bpp when using one of the floating point formats, so don't coerce those.
This makes the code actually work for those formats.
Because a float takes more storage than u16, we have to convert float
to u16 before calling png_write_image, because png_write
doesn't give us back the original row data, but an in-place copy.
With these changes we can dump floating point files with the highest
possible accuracy, with floats clamped between 0 and 1.
---
 src/cairo-png.c | 108 +++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 97 insertions(+), 11 deletions(-)
diff --git a/src/cairo-png.c b/src/cairo-png.c
index b9fc9160a8ab..2e0520ae8fac 100644
--- a/src/cairo-png.c
+++ b/src/cairo-png.c
@@ -105,6 +105,57 @@ unpremultiply_data (png_structp png, png_row_infop row_info, png_bytep data)
     }
 }
+static uint16_t f_to_u16(float val)
+{
+    if (val < 0)
+       return 0;
+    else if (val > 1)
+       return 65535;
+    else
+       return (uint16_t)(val * 65535.f);
+}
+
+static void
+unpremultiply_float (float *f, uint16_t *d16, unsigned width)
+{
+    unsigned int i;
+
+    for (i = 0; i < width; i++) {
+       float r, g, b, a;
+
+       r = *f++;
+       g = *f++;
+       b = *f++;
+       a = *f++;
+
+       if (a > 0) {
+           *d16++ = f_to_u16(r / a);
+           *d16++ = f_to_u16(g / a);
+           *d16++ = f_to_u16(b / a);
+           *d16++ = f_to_u16(a);
+       } else {
+           *d16++ = 0;
+           *d16++ = 0;
+           *d16++ = 0;
+           *d16++ = 0;
+       }
+    }
+}
+
+
+static void
+convert_float_to_u16 (float *f, uint16_t *d16, unsigned int width)
+{
+    unsigned int i;
+
+    for (i = 0; i < width; i++) {
+       *d16++ = f_to_u16(*f++);
+       *d16++ = f_to_u16(*f++);
+       *d16++ = f_to_u16(*f++);
+       *d16++ = 0;
+    }
+}
+
 /* Converts native endian xRGB => RGBx bytes */
 static void
 convert_data_to_bytes (png_structp png, png_row_infop row_info, png_bytep data)
@@ -182,6 +233,7 @@ write_png (cairo_surface_t  *surface,
     png_color_16 white;
     int png_color_type;
     int bpc;
+    unsigned char *volatile u16_copy = NULL;
     status = _cairo_surface_acquire_source_image (surface,
                                                  &image,
@@ -198,11 +250,22 @@ write_png (cairo_surface_t        *surface,
        goto BAIL1;
     }
-    /* Handle the various fallback formats (e.g. low bit-depth XServers)
-     * by coercing them to a simpler format using pixman.
-     */
-    clone = _cairo_image_surface_coerce (image);
-    status = clone->base.status;
+    /* Don't coerce to a lower resolution format */
+    if (image->format == CAIRO_FORMAT_RGB96F ||
+        image->format == CAIRO_FORMAT_RGBA128F) {
+       u16_copy = _cairo_malloc_ab (image->width * 8, image->height);
+       if (!u16_copy) {
+           status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+           goto BAIL1;
+       }
+       clone = (cairo_image_surface_t *)cairo_surface_reference (&image->base);
+    } else {
+         /* Handle the various fallback formats (e.g. low bit-depth XServers)
+         * by coercing them to a simpler format using pixman.
+         */
+         clone = _cairo_image_surface_coerce (image);
+         status = clone->base.status;
+    }
     if (unlikely (status))
         goto BAIL1;
@@ -212,8 +275,22 @@ write_png (cairo_surface_t *surface,
        goto BAIL2;
     }
-    for (i = 0; i < clone->height; i++)
-       rows[i] = (png_byte *) clone->data + i * clone->stride;
+    if (!u16_copy) {
+       for (i = 0; i < clone->height; i++)
+           rows[i] = (png_byte *)clone->data + i * clone->stride;
+    } else {
+       for (i = 0; i < clone->height; i++) {
+           float *float_line = (float *)&clone->data[i * clone->stride];
+           uint16_t *u16_line = (uint16_t *)&u16_copy[i * clone->width * 8];
+
+           if (image->format == CAIRO_FORMAT_RGBA128F)
+               unpremultiply_float (float_line, u16_line, clone->width);
+           else
+               convert_float_to_u16 (float_line, u16_line, clone->width);
+
+           rows[i] = (png_byte *)u16_line;
+       }
+    }
     png = png_create_write_struct (PNG_LIBPNG_VER_STRING, &status,
                                   png_simple_error_callback,
@@ -263,10 +340,16 @@ write_png (cairo_surface_t        *surface,
        png_set_packswap (png);
 #endif
        break;
+       bpc = 16;
+       png_color_type = PNG_COLOR_TYPE_RGB;
+       break;
+       bpc = 16;
+       png_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
+       break;
        status = _cairo_error (CAIRO_STATUS_INVALID_FORMAT);
        goto BAIL4;
@@ -298,9 +381,11 @@ write_png (cairo_surface_t *surface,
     png_write_info (png, info);
     if (png_color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
-       png_set_write_user_transform_fn (png, unpremultiply_data);
+       if (clone->format != CAIRO_FORMAT_RGBA128F)
+           png_set_write_user_transform_fn (png, unpremultiply_data);
     } else if (png_color_type == PNG_COLOR_TYPE_RGB) {
-       png_set_write_user_transform_fn (png, convert_data_to_bytes);
+       if (clone->format != CAIRO_FORMAT_RGB96F)
+           png_set_write_user_transform_fn (png, convert_data_to_bytes);
        png_set_filler (png, 0, PNG_FILLER_AFTER);
     }
     free (rows);
     cairo_surface_destroy (&clone->base);
+    free (u16_copy);
     _cairo_surface_release_source_image (surface, image, image_extra);
 
--
2.18.0
--
cairo mailing list
https://lists.cairographics.org/mailman/listinfo/cairo <https://lists.cairographics.org/mailman/listinfo/cairo>
--
cairo mailing list
***@cairographics.org
https://lists.cair
Bill Spitzak
2018-08-07 14:56:57 UTC
Permalink
Yes I think we need to leave premultiplied as it is, since the png api is
supposed to be a toy api and there should not be a reason to complicate it.
It would be nice to write some kind of ImageMagic link to Cairo, maybe
something exists already, that would convert many image formats to source
surfaces. This probably should cache images so they can be read multiple
times, and is thus outside the scope of Cairo itself. If so I have found it
best to assume premultipled no matter what the file format says. The reason
is that it is much easier to see accidental lack of multiplication (which
produces bright edges that are very bad the more transparent a pixel is in
a comp) than double multiplication (which produces dark edges that are
somewhat subtle and worst at 50% transparency), so it means bugs are more
noticable and thus fixed.

It was an unfortunate decision by png to say it is not premultiplied, or to
not put an indicator in the header.

Your patches look good though I did not really look at how it is doing the
floating point buffers. Support for half data would be nice but requires a
header from ILM. I fully agree that it is pointless to support image
formats with 16 or more bits as floating point is superior in every single
case.

Not related, but support for floating point transform matrix would be a
good idea too. Cairo also needs to start supporting float in all it's
coordinates, in particular before clipping is done.


On Tue, Aug 7, 2018 at 2:04 AM, Maarten Lankhorst <
Post by Bill Spitzak
Hey,
Post by Bill Spitzak
if (a > 0 && a < 1) {
... r/a ...
} else {
.... r, g, b, (a>0)?1:0;
}
The purpose is to avoid the division for a > 1.0, which will happen when
various filtering operations are done but will produce the wrong color. The
above code also leaves the color alone on transparent and treats NaN in the
alpha as 0.0, both of which I have also found useful.
Post by Bill Spitzak
It would really be nice if cairo provided an option to treat png as
premultiplied, but it is the toy interface. Just be warned that a huge
number of them are premultipled (the spec is ignored a lot!).
Yeah I guess premultiplied could be a problem, but I think as long as we
stick to the spec and are able to read
files we wrote in the same way, we should be fine. Anything else would
really be outside the scope of the png support. :)
Did you find anything else while looking at the patch series?
~Maarten
Post by Bill Spitzak
On Mon, Aug 6, 2018 at 7:59 AM, Maarten Lankhorst <
_cairo_image_surface_coerce will round down the image to a lower
bpp when using one of the floating point formats, so don't coerce
those.
Post by Bill Spitzak
This makes the code actually work for those formats.
Because a float takes more storage than u16, we have to convert float
to u16 before calling png_write_image, because png_write
doesn't give us back the original row data, but an in-place copy.
With these changes we can dump floating point files with the highest
possible accuracy, with floats clamped between 0 and 1.
---
src/cairo-png.c | 108 ++++++++++++++++++++++++++++++
+++++++++++++-----
Post by Bill Spitzak
1 file changed, 97 insertions(+), 11 deletions(-)
diff --git a/src/cairo-png.c b/src/cairo-png.c
index b9fc9160a8ab..2e0520ae8fac 100644
--- a/src/cairo-png.c
+++ b/src/cairo-png.c
@@ -105,6 +105,57 @@ unpremultiply_data (png_structp png,
png_row_infop row_info, png_bytep data)
Post by Bill Spitzak
}
}
+static uint16_t f_to_u16(float val)
+{
+ if (val < 0)
+ return 0;
+ else if (val > 1)
+ return 65535;
+ else
+ return (uint16_t)(val * 65535.f);
+}
+
+static void
+unpremultiply_float (float *f, uint16_t *d16, unsigned width)
+{
+ unsigned int i;
+
+ for (i = 0; i < width; i++) {
+ float r, g, b, a;
+
+ r = *f++;
+ g = *f++;
+ b = *f++;
+ a = *f++;
+
+ if (a > 0) {
+ *d16++ = f_to_u16(r / a);
+ *d16++ = f_to_u16(g / a);
+ *d16++ = f_to_u16(b / a);
+ *d16++ = f_to_u16(a);
+ } else {
+ *d16++ = 0;
+ *d16++ = 0;
+ *d16++ = 0;
+ *d16++ = 0;
+ }
+ }
+}
+
+
+static void
+convert_float_to_u16 (float *f, uint16_t *d16, unsigned int width)
+{
+ unsigned int i;
+
+ for (i = 0; i < width; i++) {
+ *d16++ = f_to_u16(*f++);
+ *d16++ = f_to_u16(*f++);
+ *d16++ = f_to_u16(*f++);
+ *d16++ = 0;
+ }
+}
+
/* Converts native endian xRGB => RGBx bytes */
static void
convert_data_to_bytes (png_structp png, png_row_infop row_info,
png_bytep data)
Post by Bill Spitzak
@@ -182,6 +233,7 @@ write_png (cairo_surface_t *surface,
png_color_16 white;
int png_color_type;
int bpc;
+ unsigned char *volatile u16_copy = NULL;
status = _cairo_surface_acquire_source_image (surface,
&image,
@@ -198,11 +250,22 @@ write_png (cairo_surface_t *surface,
goto BAIL1;
}
- /* Handle the various fallback formats (e.g. low bit-depth
XServers)
Post by Bill Spitzak
- * by coercing them to a simpler format using pixman.
- */
- clone = _cairo_image_surface_coerce (image);
- status = clone->base.status;
+ /* Don't coerce to a lower resolution format */
+ if (image->format == CAIRO_FORMAT_RGB96F ||
+ image->format == CAIRO_FORMAT_RGBA128F) {
+ u16_copy = _cairo_malloc_ab (image->width * 8,
image->height);
Post by Bill Spitzak
+ if (!u16_copy) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto BAIL1;
+ }
+ clone = (cairo_image_surface_t *)cairo_surface_reference
(&image->base);
Post by Bill Spitzak
+ } else {
+ /* Handle the various fallback formats (e.g. low bit-depth
XServers)
Post by Bill Spitzak
+ * by coercing them to a simpler format using pixman.
+ */
+ clone = _cairo_image_surface_coerce (image);
+ status = clone->base.status;
+ }
if (unlikely (status))
goto BAIL1;
@@ -212,8 +275,22 @@ write_png (cairo_surface_t *surface,
goto BAIL2;
}
- for (i = 0; i < clone->height; i++)
- rows[i] = (png_byte *) clone->data + i * clone->stride;
+ if (!u16_copy) {
+ for (i = 0; i < clone->height; i++)
+ rows[i] = (png_byte *)clone->data + i * clone->stride;
+ } else {
+ for (i = 0; i < clone->height; i++) {
+ float *float_line = (float *)&clone->data[i *
clone->stride];
Post by Bill Spitzak
+ uint16_t *u16_line = (uint16_t *)&u16_copy[i *
clone->width * 8];
Post by Bill Spitzak
+
+ if (image->format == CAIRO_FORMAT_RGBA128F)
+ unpremultiply_float (float_line, u16_line,
clone->width);
Post by Bill Spitzak
+ else
+ convert_float_to_u16 (float_line, u16_line,
clone->width);
Post by Bill Spitzak
+
+ rows[i] = (png_byte *)u16_line;
+ }
+ }
png = png_create_write_struct (PNG_LIBPNG_VER_STRING, &status,
png_simple_error_callback,
@@ -263,10 +340,16 @@ write_png (cairo_surface_t *surface,
png_set_packswap (png);
#endif
break;
+ bpc = 16;
+ png_color_type = PNG_COLOR_TYPE_RGB;
+ break;
+ bpc = 16;
+ png_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
+ break;
status = _cairo_error (CAIRO_STATUS_INVALID_FORMAT);
goto BAIL4;
@@ -298,9 +381,11 @@ write_png (cairo_surface_t *surface,
png_write_info (png, info);
if (png_color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
- png_set_write_user_transform_fn (png, unpremultiply_data);
+ if (clone->format != CAIRO_FORMAT_RGBA128F)
+ png_set_write_user_transform_fn (png,
unpremultiply_data);
Post by Bill Spitzak
} else if (png_color_type == PNG_COLOR_TYPE_RGB) {
- png_set_write_user_transform_fn (png,
convert_data_to_bytes);
Post by Bill Spitzak
+ if (clone->format != CAIRO_FORMAT_RGB96F)
+ png_set_write_user_transform_fn (png,
convert_data_to_bytes);
Post by Bill Spitzak
png_set_filler (png, 0, PNG_FILLER_AFTER);
}
free (rows);
cairo_surface_destroy (&clone->base);
+ free (u16_copy);
_cairo_surface_release_source_image (surface, image,
image_extra);
Post by Bill Spitzak
--
2.18.0
--
cairo mailing list
https://lists.cairographics.org/mailman/listinfo/cairo <
https://lists.cairographics.org/mailman/listinfo/cairo>
Maarten Lankhorst
2018-08-06 14:59:27 UTC
Permalink
All the cases are the same, except len is different.
Use the already calculated len parameter to handle all
cases except RGB24 the same.

Signed-off-by: Maarten Lankhorst <***@linux.intel.com>
Suggested-by: Bryce Harrington <***@bryceharrington.org>
---
util/cairo-trace/trace.c | 25 +++++--------------------
1 file changed, 5 insertions(+), 20 deletions(-)

diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c
index 87b2df46ef09..7a43b0f2c341 100644
--- a/util/cairo-trace/trace.c
+++ b/util/cairo-trace/trace.c
@@ -1680,24 +1680,6 @@ _emit_image (cairo_surface_t *image,

#ifdef WORDS_BIGENDIAN
switch (format) {
- case CAIRO_FORMAT_A1:
- for (row = height; row--; ) {
- _write_data (&stream, data, (width+7)/8);
- data += stride;
- }
- break;
- case CAIRO_FORMAT_A8:
- for (row = height; row--; ) {
- _write_data (&stream, data, width);
- data += stride;
- }
- break;
- case CAIRO_FORMAT_RGB16_565:
- for (row = height; row--; ) {
- _write_data (&stream, data, 2*width);
- data += stride;
- }
- break;
case CAIRO_FORMAT_RGB24:
for (row = height; row--; ) {
int col;
@@ -1709,10 +1691,13 @@ _emit_image (cairo_surface_t *image,
data += stride;
}
break;
+ case CAIRO_FORMAT_A1:
+ case CAIRO_FORMAT_A8:
+ case CAIRO_FORMAT_RGB16_565:
case CAIRO_FORMAT_RGB30:
case CAIRO_FORMAT_ARGB32:
for (row = height; row--; ) {
- _write_data (&stream, data, 4*width);
+ _write_data (&stream, data, len);
data += stride;
}
break;
@@ -1777,7 +1762,7 @@ _emit_image (cairo_surface_t *image,
int col;
for (col = 0; col < width; col++)
dst[col] = bswap_32 (src[col]);
- _write_data (&stream, rowdata, 4*width);
+ _write_data (&stream, rowdata, len);
data += stride;
}
break;
--
2.18.0
--
cairo mailing list
***@cairographics.or
Maarten Lankhorst
2018-08-06 14:59:31 UTC
Permalink
This will make it possible to actually test floating point support works.

Tested with CAIRO_TEST_TARGET=imagefloat.

All tests fail, because the comparison function is broken, but at least
it shows the RGB96/RGBA128F code works.

Signed-off-by: Maarten Lankhorst <***@linux.intel.com>
---
boilerplate/cairo-boilerplate.c | 154 ++++++++++++++++++++++++++------
1 file changed, 129 insertions(+), 25 deletions(-)

diff --git a/boilerplate/cairo-boilerplate.c b/boilerplate/cairo-boilerplate.c
index 4804deaffcb5..080b5c3006b3 100644
--- a/boilerplate/cairo-boilerplate.c
+++ b/boilerplate/cairo-boilerplate.c
@@ -241,6 +241,56 @@ _cairo_boilerplate_image16_create_similar (cairo_surface_t *other,
return surface;
}

+static cairo_surface_t *
+_cairo_boilerplate_imagefloat_create_surface (const char *name,
+ cairo_content_t content,
+ double width,
+ double height,
+ double max_width,
+ double max_height,
+ cairo_boilerplate_mode_t mode,
+ void **closure)
+{
+ *closure = NULL;
+
+ /* XXX force CAIRO_CONTENT_COLOR */
+ return cairo_image_surface_create (CAIRO_FORMAT_RGB96F, ceil (width), ceil (height));
+}
+
+static cairo_surface_t *
+_cairo_boilerplate_imagefloat_create_similar (cairo_surface_t *other,
+ cairo_content_t content,
+ int width, int height)
+{
+ cairo_format_t format;
+ cairo_surface_t *surface;
+ int stride;
+ void *ptr;
+
+ switch (content) {
+ case CAIRO_CONTENT_ALPHA:
+ format = CAIRO_FORMAT_A8;
+ break;
+ case CAIRO_CONTENT_COLOR:
+ format = CAIRO_FORMAT_RGB96F;
+ break;
+ case CAIRO_CONTENT_COLOR_ALPHA:
+ default:
+ format = CAIRO_FORMAT_RGBA128F;
+ break;
+ }
+
+ stride = cairo_format_stride_for_width(format, width);
+ ptr = malloc (stride* height);
+
+ surface = cairo_image_surface_create_for_data (ptr, format,
+ width, height, stride);
+ cairo_surface_set_user_data (surface, &key, ptr, free);
+
+ return surface;
+}
+
+
static char *
_cairo_boilerplate_image_describe (void *closure)
{
@@ -281,36 +331,16 @@ _cairo_boilerplate_recording_surface_cleanup (void *closure)

const cairo_user_data_key_t cairo_boilerplate_output_basename_key;

-cairo_surface_t *
-_cairo_boilerplate_get_image_surface (cairo_surface_t *src,
- int page,
- int width,
- int height)
+static cairo_surface_t *
+_cairo_boilerplate_get_image_surface_for_format(cairo_surface_t *src,
+ cairo_format_t format,
+ int width,
+ int height)
{
cairo_surface_t *surface, *image;
cairo_t *cr;
cairo_status_t status;
- cairo_format_t format;
-
- if (cairo_surface_status (src))
- return cairo_surface_reference (src);

- if (page != 0)
- return cairo_boilerplate_surface_create_in_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
-
- /* extract sub-surface */
- switch (cairo_surface_get_content (src)) {
- case CAIRO_CONTENT_ALPHA:
- format = CAIRO_FORMAT_A8;
- break;
- case CAIRO_CONTENT_COLOR:
- format = CAIRO_FORMAT_RGB24;
- break;
- default:
- case CAIRO_CONTENT_COLOR_ALPHA:
- format = CAIRO_FORMAT_ARGB32;
- break;
- }
surface = cairo_image_surface_create (format, width, height);
assert (cairo_surface_get_content (surface) == cairo_surface_get_content (src));
image = cairo_surface_reference (surface);
@@ -352,6 +382,67 @@ _cairo_boilerplate_get_image_surface (cairo_surface_t *src,
return image;
}

+cairo_surface_t *
+_cairo_boilerplate_get_image_surface (cairo_surface_t *src,
+ int page,
+ int width,
+ int height)
+{
+ cairo_format_t format;
+
+ if (cairo_surface_status (src))
+ return cairo_surface_reference (src);
+
+ if (page != 0)
+ return cairo_boilerplate_surface_create_in_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+
+ /* extract sub-surface */
+ switch (cairo_surface_get_content (src)) {
+ case CAIRO_CONTENT_ALPHA:
+ format = CAIRO_FORMAT_A8;
+ break;
+ case CAIRO_CONTENT_COLOR:
+ format = CAIRO_FORMAT_RGB24;
+ break;
+ default:
+ case CAIRO_CONTENT_COLOR_ALPHA:
+ format = CAIRO_FORMAT_ARGB32;
+ break;
+ }
+ return _cairo_boilerplate_get_image_surface_for_format(src, format, width, height);
+}
+
+static cairo_surface_t *
+_cairo_boilerplate_get_image_surface_float (cairo_surface_t *src,
+ int page,
+ int width,
+ int height)
+{
+ cairo_format_t format;
+
+ if (cairo_surface_status (src))
+ return cairo_surface_reference (src);
+
+ if (page != 0)
+ return cairo_boilerplate_surface_create_in_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+
+ /* extract sub-surface */
+ switch (cairo_surface_get_content (src)) {
+ case CAIRO_CONTENT_ALPHA:
+ format = CAIRO_FORMAT_A8;
+ break;
+ case CAIRO_CONTENT_COLOR:
+ format = CAIRO_FORMAT_RGB96F;
+ break;
+ default:
+ case CAIRO_CONTENT_COLOR_ALPHA:
+ format = CAIRO_FORMAT_RGBA128F;
+ break;
+ }
+
+ return _cairo_boilerplate_get_image_surface_for_format(src, format, width, height);
+}
+
cairo_surface_t *
cairo_boilerplate_get_image_surface_from_png (const char *filename,
int width,
@@ -454,6 +545,19 @@ static const cairo_boilerplate_target_t builtin_targets[] = {
_cairo_boilerplate_image_describe,
TRUE, FALSE, FALSE
},
+ {
+ "imagefloat", "image", NULL, NULL,
+ CAIRO_SURFACE_TYPE_IMAGE, CAIRO_CONTENT_COLOR, 0,
+ NULL,
+ _cairo_boilerplate_imagefloat_create_surface,
+ _cairo_boilerplate_imagefloat_create_similar,
+ NULL, NULL,
+ _cairo_boilerplate_get_image_surface_float,
+ cairo_surface_write_to_png,
+ NULL, NULL,
+ _cairo_boilerplate_image_describe,
+ TRUE, FALSE, FALSE
+ },
#if CAIRO_HAS_RECORDING_SURFACE
{
"recording", "image", NULL, NULL,
--
2.18.0
--
cairo mailing list
***@cairographics.org
https://lists.cairographics.org
Loading...