summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2008-11-05 16:38:34 +0000
committerChris Wilson <chris@chris-wilson.co.uk>2008-11-05 18:13:09 +0000
commite40d62a0fe96b8b937017a3bc2f18766c411ec41 (patch)
treea00ea404aaf2f1ec3b97f01bf968c3085a8d0007
parent89616dee8f11c6a7de3fa476b13661420648786f (diff)
[png] Attach the png representation to cairo_surface_create_from_png().
Attach the original png data as an alternate representation for image surfaces created by cairo_surface_create_from_png().
-rw-r--r--src/cairo-output-stream-private.h5
-rw-r--r--src/cairo-output-stream.c28
-rw-r--r--src/cairo-png.c127
-rw-r--r--src/cairo-surface-fallback.c20
-rw-r--r--src/cairo.h1
5 files changed, 122 insertions, 59 deletions
diff --git a/src/cairo-output-stream-private.h b/src/cairo-output-stream-private.h
index 787d0616..6f10483f 100644
--- a/src/cairo-output-stream-private.h
+++ b/src/cairo-output-stream-private.h
@@ -161,6 +161,11 @@ _cairo_memory_stream_copy (cairo_output_stream_t *base,
cairo_private int
_cairo_memory_stream_length (cairo_output_stream_t *stream);
+cairo_private cairo_status_t
+_cairo_memory_stream_destroy (cairo_output_stream_t *abstract_stream,
+ unsigned char **data_out,
+ unsigned int *length_out);
+
cairo_private cairo_output_stream_t *
_cairo_null_stream_create (void);
diff --git a/src/cairo-output-stream.c b/src/cairo-output-stream.c
index bae6ac4f..c31c2da5 100644
--- a/src/cairo-output-stream.c
+++ b/src/cairo-output-stream.c
@@ -656,6 +656,32 @@ _cairo_memory_stream_create (void)
return &stream->base;
}
+cairo_status_t
+_cairo_memory_stream_destroy (cairo_output_stream_t *abstract_stream,
+ unsigned char **data_out,
+ unsigned int *length_out)
+{
+ memory_stream_t *stream;
+ cairo_status_t status;
+
+ status = abstract_stream->status;
+ if (status)
+ return _cairo_output_stream_destroy (abstract_stream);
+
+ stream = (memory_stream_t *) abstract_stream;
+
+ *length_out = _cairo_array_num_elements (&stream->array);
+ *data_out = malloc (*length_out);
+ if (*data_out == NULL) {
+ status = _cairo_output_stream_destroy (abstract_stream);
+ assert (status == CAIRO_STATUS_SUCCESS);
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+ memcpy (*data_out, _cairo_array_index (&stream->array, 0), *length_out);
+
+ return _cairo_output_stream_destroy (abstract_stream);
+}
+
void
_cairo_memory_stream_copy (cairo_output_stream_t *base,
cairo_output_stream_t *dest)
@@ -670,7 +696,7 @@ _cairo_memory_stream_copy (cairo_output_stream_t *base,
return;
}
- _cairo_output_stream_write (dest,
+ _cairo_output_stream_write (dest,
_cairo_array_index (&stream->array, 0),
_cairo_array_num_elements (&stream->array));
}
diff --git a/src/cairo-png.c b/src/cairo-png.c
index 4721825e..b4aeb081 100644
--- a/src/cairo-png.c
+++ b/src/cairo-png.c
@@ -37,10 +37,19 @@
*/
#include "cairoint.h"
+#include "cairo-output-stream-private.h"
+#include <stdio.h>
#include <errno.h>
#include <png.h>
+struct png_read_closure_t {
+ cairo_read_func_t read_func;
+ void *closure;
+ cairo_output_stream_t *png_data;
+};
+
+
/* Unpremultiplies data and converts native endian ARGB => RGBA bytes */
static void
unpremultiply_data (png_structp png, png_row_infop row_info, png_bytep data)
@@ -436,9 +445,43 @@ convert_bytes_to_data (png_structp png, png_row_infop row_info, png_bytep data)
}
}
+static cairo_status_t
+stdio_read_func (void *closure, unsigned char *data, unsigned int size)
+{
+ while (size) {
+ size_t ret;
+
+ ret = fread (data, 1, size, closure);
+ size -= ret;
+ data += ret;
+
+ if (size && (feof (closure) || ferror (closure)))
+ return _cairo_error (CAIRO_STATUS_READ_ERROR);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+stream_read_func (png_structp png, png_bytep data, png_size_t size)
+{
+ cairo_status_t status;
+ struct png_read_closure_t *png_closure;
+
+ png_closure = png_get_io_ptr (png);
+ status = png_closure->read_func (png_closure->closure, data, size);
+ if (status) {
+ cairo_status_t *error = png_get_error_ptr (png);
+ if (*error == CAIRO_STATUS_SUCCESS)
+ *error = status;
+ png_error (png, NULL);
+ }
+
+ _cairo_output_stream_write (png_closure->png_data, data, size);
+}
+
static cairo_surface_t *
-read_png (png_rw_ptr read_func,
- void *closure)
+read_png (struct png_read_closure_t *png_closure)
{
cairo_surface_t *surface;
png_struct *png = NULL;
@@ -450,6 +493,8 @@ read_png (png_rw_ptr read_func,
unsigned int i;
cairo_format_t format;
cairo_status_t status;
+ unsigned char *mime_data;
+ unsigned int mime_data_length;
/* XXX: Perhaps we'll want some other error handlers? */
png = png_create_read_struct (PNG_LIBPNG_VER_STRING,
@@ -467,7 +512,8 @@ read_png (png_rw_ptr read_func,
goto BAIL;
}
- png_set_read_fn (png, closure, read_func);
+ png_closure->png_data = _cairo_memory_stream_create ();
+ png_set_read_fn (png, png_closure, stream_read_func);
status = CAIRO_STATUS_SUCCESS;
#ifdef PNG_SETJMP_SUPPORTED
@@ -589,6 +635,27 @@ read_png (png_rw_ptr read_func,
_cairo_image_surface_assume_ownership_of_data ((cairo_image_surface_t*)surface);
data = NULL;
+ status = _cairo_memory_stream_destroy (png_closure->png_data,
+ &mime_data,
+ &mime_data_length);
+ if (status) {
+ cairo_surface_destroy (surface);
+ surface = _cairo_surface_create_in_error (status);
+ goto BAIL;
+ }
+
+ status = cairo_surface_set_mime_data (surface,
+ CAIRO_MIME_TYPE_PNG,
+ mime_data,
+ mime_data_length,
+ free);
+ if (status) {
+ free (mime_data);
+ cairo_surface_destroy (surface);
+ surface = _cairo_surface_create_in_error (status);
+ goto BAIL;
+ }
+
BAIL:
if (row_pointers)
free (row_pointers);
@@ -600,25 +667,6 @@ read_png (png_rw_ptr read_func,
return surface;
}
-static void
-stdio_read_func (png_structp png, png_bytep data, png_size_t size)
-{
- FILE *fp;
-
- fp = png_get_io_ptr (png);
- while (size) {
- size_t ret = fread (data, 1, size, fp);
- size -= ret;
- data += ret;
- if (size && (feof (fp) || ferror (fp))) {
- cairo_status_t *error = png_get_error_ptr (png);
- if (*error == CAIRO_STATUS_SUCCESS)
- *error = _cairo_error (CAIRO_STATUS_READ_ERROR);
- png_error (png, NULL);
- }
- }
-}
-
/**
* cairo_image_surface_create_from_png:
* @filename: name of PNG file to load
@@ -638,11 +686,11 @@ stdio_read_func (png_structp png, png_bytep data, png_size_t size)
cairo_surface_t *
cairo_image_surface_create_from_png (const char *filename)
{
- FILE *fp;
+ struct png_read_closure_t png_closure;
cairo_surface_t *surface;
- fp = fopen (filename, "rb");
- if (fp == NULL) {
+ png_closure.closure = fopen (filename, "rb");
+ if (png_closure.closure == NULL) {
cairo_status_t status;
switch (errno) {
case ENOMEM:
@@ -658,32 +706,13 @@ cairo_image_surface_create_from_png (const char *filename)
return _cairo_surface_create_in_error (status);
}
- surface = read_png (stdio_read_func, fp);
-
- fclose (fp);
+ png_closure.read_func = stdio_read_func;
- return surface;
-}
+ surface = read_png (&png_closure);
-struct png_read_closure_t {
- cairo_read_func_t read_func;
- void *closure;
-};
+ fclose (png_closure.closure);
-static void
-stream_read_func (png_structp png, png_bytep data, png_size_t size)
-{
- cairo_status_t status;
- struct png_read_closure_t *png_closure;
-
- png_closure = png_get_io_ptr (png);
- status = png_closure->read_func (png_closure->closure, data, size);
- if (status) {
- cairo_status_t *error = png_get_error_ptr (png);
- if (*error == CAIRO_STATUS_SUCCESS)
- *error = status;
- png_error (png, NULL);
- }
+ return surface;
}
/**
@@ -707,5 +736,5 @@ cairo_image_surface_create_from_png_stream (cairo_read_func_t read_func,
png_closure.read_func = read_func;
png_closure.closure = closure;
- return read_png (stream_read_func, &png_closure);
+ return read_png (&png_closure);
}
diff --git a/src/cairo-surface-fallback.c b/src/cairo-surface-fallback.c
index f8f89025..bb29a9f0 100644
--- a/src/cairo-surface-fallback.c
+++ b/src/cairo-surface-fallback.c
@@ -1036,6 +1036,11 @@ _cairo_surface_fallback_snapshot (cairo_surface_t *surface)
cairo_surface_pattern_t pattern;
cairo_image_surface_t *image;
void *image_extra;
+ const char *mime_types[] = {
+ CAIRO_MIME_TYPE_JPEG,
+ CAIRO_MIME_TYPE_PNG,
+ NULL
+ }, **mime_type;
status = _cairo_surface_acquire_source_image (surface,
&image, &image_extra);
@@ -1075,15 +1080,12 @@ _cairo_surface_fallback_snapshot (cairo_surface_t *surface)
snapshot->device_transform = surface->device_transform;
snapshot->device_transform_inverse = surface->device_transform_inverse;
- /* XXX Need to copy all known image representations...
- * For now, just copy "image/jpeg", but in future we should construct
- * an array of known types and iterate.
- */
- status = _cairo_surface_copy_mime_data (snapshot, surface,
- CAIRO_MIME_TYPE_JPEG);
- if (status) {
- cairo_surface_destroy (snapshot);
- return _cairo_surface_create_in_error (status);
+ for (mime_type = mime_types; *mime_type; mime_type++) {
+ status = _cairo_surface_copy_mime_data (snapshot, surface, *mime_type);
+ if (status) {
+ cairo_surface_destroy (snapshot);
+ return _cairo_surface_create_in_error (status);
+ }
}
snapshot->is_snapshot = TRUE;
diff --git a/src/cairo.h b/src/cairo.h
index a1cd0c55..cbc109f3 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -1948,6 +1948,7 @@ cairo_surface_set_user_data (cairo_surface_t *surface,
cairo_destroy_func_t destroy);
#define CAIRO_MIME_TYPE_JPEG "image/jpeg"
+#define CAIRO_MIME_TYPE_PNG "image/png"
cairo_public void
cairo_surface_get_mime_data (cairo_surface_t *surface,