summaryrefslogtreecommitdiff
path: root/src/cairo-png.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cairo-png.c')
-rw-r--r--src/cairo-png.c49
1 files changed, 37 insertions, 12 deletions
diff --git a/src/cairo-png.c b/src/cairo-png.c
index d7297848d..532054e51 100644
--- a/src/cairo-png.c
+++ b/src/cairo-png.c
@@ -38,6 +38,7 @@
#include <png.h>
#include "cairoint.h"
+/* Unpremultiplies data and converts native endian ARGB => RGBA bytes */
static void
unpremultiply_data (png_structp png, png_row_infop row_info, png_bytep data)
{
@@ -53,14 +54,33 @@ unpremultiply_data (png_structp png, png_row_infop row_info, png_bytep data)
if (alpha == 0) {
b[0] = b[1] = b[2] = b[3] = 0;
} else {
- b[0] = (((pixel & 0x0000ff) >> 0) * 255 + alpha / 2) / alpha;
+ b[0] = (((pixel & 0xff0000) >> 16) * 255 + alpha / 2) / alpha;
b[1] = (((pixel & 0x00ff00) >> 8) * 255 + alpha / 2) / alpha;
- b[2] = (((pixel & 0xff0000) >> 16) * 255 + alpha / 2) / alpha;
+ b[2] = (((pixel & 0x0000ff) >> 0) * 255 + alpha / 2) / alpha;
b[3] = alpha;
}
}
}
+/* Converts native endian xRGB => RGBx bytes */
+static void
+convert_data_to_bytes (png_structp png, png_row_infop row_info, png_bytep data)
+{
+ int i;
+
+ for (i = 0; i < row_info->rowbytes; i += 4) {
+ uint8_t *b = &data[i];
+ uint32_t pixel;
+
+ memcpy (&pixel, b, sizeof (uint32_t));
+
+ b[0] = (pixel & 0xff0000) >> 16;
+ b[1] = (pixel & 0x00ff00) >> 8;
+ b[2] = (pixel & 0x0000ff) >> 0;
+ b[3] = 0;
+ }
+}
+
static cairo_status_t
write_png (cairo_surface_t *surface,
png_rw_ptr write_func,
@@ -153,14 +173,19 @@ write_png (cairo_surface_t *surface,
png_convert_from_time_t (&pt, time (NULL));
png_set_tIME (png, info, &pt);
- png_set_write_user_transform_fn (png, unpremultiply_data);
- if (image->format == CAIRO_FORMAT_ARGB32 ||
- image->format == CAIRO_FORMAT_RGB24)
- png_set_bgr (png);
+ /* We have to call png_write_info() before setting up the write
+ * transformation, since it stores data internally in 'png'
+ * that is needed for the write transformation functions to work.
+ */
+ png_write_info (png, info);
+
+ if (image->format == CAIRO_FORMAT_ARGB32)
+ png_set_write_user_transform_fn (png, unpremultiply_data);
+ else if (image->format == CAIRO_FORMAT_RGB24)
+ png_set_write_user_transform_fn (png, convert_data_to_bytes);
if (image->format == CAIRO_FORMAT_RGB24)
png_set_filler (png, 0, PNG_FILLER_AFTER);
-
- png_write_info (png, info);
+
png_write_image (png, rows);
png_write_end (png, info);
@@ -262,6 +287,7 @@ cairo_surface_write_to_png_stream (cairo_surface_t *surface,
return write_png (surface, stream_write_func, &png_closure);
}
+/* Premultiplies data and converts RGBA bytes => native endian */
static void
premultiply_data (png_structp png,
png_row_infop row_info,
@@ -271,9 +297,9 @@ premultiply_data (png_structp png,
for (i = 0; i < row_info->rowbytes; i += 4) {
uint8_t *base = &data[i];
- uint8_t blue = base[0];
+ uint8_t red = base[0];
uint8_t green = base[1];
- uint8_t red = base[2];
+ uint8_t blue = base[2];
uint8_t alpha = base[3];
uint32_t p;
@@ -352,7 +378,6 @@ read_png (png_rw_ptr read_func,
if (interlace != PNG_INTERLACE_NONE)
png_set_interlace_handling (png);
- png_set_bgr (png);
png_set_filler (png, 0xff, PNG_FILLER_AFTER);
png_set_read_user_transform_fn (png, premultiply_data);
@@ -383,7 +408,7 @@ read_png (png_rw_ptr read_func,
BAIL:
free (row_pointers);
free (data);
- png_destroy_read_struct (&png, NULL, NULL);
+ png_destroy_read_struct (&png, &info, NULL);
return surface;
}