diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2008-11-05 16:38:34 +0000 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2008-11-05 18:13:09 +0000 |
commit | e40d62a0fe96b8b937017a3bc2f18766c411ec41 (patch) | |
tree | a00ea404aaf2f1ec3b97f01bf968c3085a8d0007 | |
parent | 89616dee8f11c6a7de3fa476b13661420648786f (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.h | 5 | ||||
-rw-r--r-- | src/cairo-output-stream.c | 28 | ||||
-rw-r--r-- | src/cairo-png.c | 127 | ||||
-rw-r--r-- | src/cairo-surface-fallback.c | 20 | ||||
-rw-r--r-- | src/cairo.h | 1 |
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, |