[cairo-commit] 5 commits - src/cairo.h src/cairo-output-stream.c src/cairo-output-stream-private.h src/cairo-png.c src/cairo-surface.c src/cairo-surface-fallback.c src/cairo-svg-surface.c test/Makefile.am test/mime-data.c test/mime-data.pdf.ref.png test/mime-data.ps.ref.png test/mime-data.ref.png test/mime-data.svg.ref.png test/png.png util/cairo-trace
Chris Wilson
ickle at kemper.freedesktop.org
Wed Nov 5 10:13:27 PST 2008
src/cairo-output-stream-private.h | 5
src/cairo-output-stream.c | 28 +++
src/cairo-png.c | 127 +++++++++------
src/cairo-surface-fallback.c | 20 +-
src/cairo-surface.c | 17 +-
src/cairo-svg-surface.c | 38 ++++
src/cairo.h | 1
test/Makefile.am | 1
test/mime-data.c | 67 +++++---
test/mime-data.pdf.ref.png |binary
test/mime-data.ps.ref.png |binary
test/mime-data.ref.png |binary
test/mime-data.svg.ref.png |binary
test/png.png |binary
util/cairo-trace/trace.c | 303 ++++++++++++++++++++++++++------------
15 files changed, 429 insertions(+), 178 deletions(-)
New commits:
commit ec559822cfe6df0006ca2db2aa3a11699326865c
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Wed Nov 5 18:11:36 2008 +0000
[trace] Use the mime-type image representation
When emitting image data, first check to see if we have a pre-compressed
alternate representation.
diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c
index 2ca184f..df2ec5c 100644
--- a/util/cairo-trace/trace.c
+++ b/util/cairo-trace/trace.c
@@ -989,8 +989,62 @@ _emit_data (const void *data, unsigned int length)
_write_data_end (&stream);
}
-static void
-_emit_image (cairo_surface_t *image)
+static const char *
+_format_to_string (cairo_format_t format)
+{
+ const char *names[] = {
+ "ARGB32", /* CAIRO_FORMAT_ARGB32 */
+ "RGB24", /* CAIRO_FORMAT_RGB24 */
+ "A8", /* CAIRO_FORMAT_A8 */
+ "A1" /* CAIRO_FORMAT_A1 */
+ };
+ return names[format];
+}
+
+static const char *
+_status_to_string (cairo_status_t status)
+{
+ const char *names[] = {
+ "STATUS_SUCCESS",
+ "STATUS_NO_MEMORY",
+ "STATUS_INVALID_RESTORE",
+ "STATUS_INVALID_POP_GROUP",
+ "STATUS_NO_CURRENT_POINT",
+ "STATUS_INVALID_MATRIX",
+ "STATUS_INVALID_STATUS",
+ "STATUS_NULL_POINTER",
+ "STATUS_INVALID_STRING",
+ "STATUS_INVALID_PATH_DATA",
+ "STATUS_READ_ERROR",
+ "STATUS_WRITE_ERROR",
+ "STATUS_SURFACE_FINISHED",
+ "STATUS_SURFACE_TYPE_MISMATCH",
+ "STATUS_PATTERN_TYPE_MISMATCH",
+ "STATUS_INVALID_CONTENT",
+ "STATUS_INVALID_FORMAT",
+ "STATUS_INVALID_VISUAL",
+ "STATUS_FILE_NOT_FOUND",
+ "STATUS_INVALID_DASH",
+ "STATUS_INVALID_DSC_COMMENT",
+ "STATUS_INVALID_INDEX",
+ "STATUS_CLIP_NOT_REPRESENTABLE",
+ "STATUS_TEMP_FILE_ERROR",
+ "STATUS_INVALID_STRIDE",
+ "STATUS_FONT_TYPE_MISMATCH",
+ "STATUS_USER_FONT_IMMUTABLE",
+ "STATUS_USER_FONT_ERROR",
+ "STATUS_NEGATIVE_COUNT",
+ "STATUS_INVALID_CLUSTERS",
+ "STATUS_INVALID_SLANT",
+ "STATUS_INVALID_WEIGHT"
+ };
+ return names[status];
+}
+
+static void CAIRO_PRINTF_FORMAT(2, 3)
+_emit_image (cairo_surface_t *image,
+ const char *info,
+ ...)
{
int stride, row, width, height;
cairo_format_t format;
@@ -998,6 +1052,20 @@ _emit_image (cairo_surface_t *image)
uint8_t *rowdata;
uint8_t *data;
struct _data_stream stream;
+ const char *mime_types[] = {
+ CAIRO_MIME_TYPE_JPEG,
+ CAIRO_MIME_TYPE_PNG,
+ NULL
+ }, **mime_type;
+
+ if (cairo_surface_status (image)) {
+ fprintf (logfile,
+ "dict\n"
+ " /status //%s set\n"
+ " image",
+ _status_to_string (cairo_surface_status (image)));
+ return;
+ }
width = cairo_image_surface_get_width (image);
height = cairo_image_surface_get_height (image);
@@ -1005,6 +1073,43 @@ _emit_image (cairo_surface_t *image)
format = cairo_image_surface_get_format (image);
data = cairo_image_surface_get_data (image);
+ fprintf (logfile,
+ "dict\n"
+ " /width %d set\n"
+ " /height %d set\n"
+ " /format //%s set\n",
+ width, height,
+ _format_to_string (format));
+ if (info != NULL) {
+ va_list ap;
+
+ va_start (ap, info);
+ vfprintf (logfile, info, ap);
+ va_end (ap);
+ }
+
+ for (mime_type = mime_types; *mime_type; mime_type++) {
+ const unsigned char *mime_data;
+ unsigned int mime_length;
+
+ cairo_surface_get_mime_data (image, *mime_type,
+ &mime_data, &mime_length);
+ if (mime_data != NULL) {
+ fprintf (logfile,
+ " /mime-type (%s) set\n"
+ " /source <~",
+ *mime_type);
+ _write_base85_data_start (&stream);
+ _write_base85_data (&stream, mime_data, mime_length);
+ _write_base85_data_end (&stream);
+ fprintf (logfile,
+ "~> set\n"
+ " image");
+ return;
+ }
+ }
+
+ fprintf (logfile, " /source ");
_write_data_start (&stream);
#ifdef WORDS_BIGENDIAN
@@ -1039,16 +1144,13 @@ _emit_image (cairo_surface_t *image)
}
break;
default:
- _write_data_end (&stream);
- return;
+ break;
}
#else
if (stride > ARRAY_LENGTH (row_stack)) {
rowdata = malloc (stride);
- if (rowdata == NULL) {
- _write_data_end (&stream);
- return;
- }
+ if (rowdata == NULL)
+ goto BAIL;
} else
rowdata = row_stack;
@@ -1099,8 +1201,87 @@ _emit_image (cairo_surface_t *image)
if (rowdata != row_stack)
free (rowdata);
+BAIL:
_write_data_end (&stream);
#endif
+ fprintf (logfile,
+ " /deflate filter set\n"
+ " image");
+}
+
+static void
+_encode_string_literal (char *out, int max,
+ const char *utf8, int len)
+{
+ char c;
+ const char *end;
+
+ *out++ = '(';
+ max--;
+
+ if (utf8 == NULL)
+ goto DONE;
+
+ if (len < 0)
+ len = strlen (utf8);
+ end = utf8 + len;
+
+ while (utf8 < end) {
+ if (max < 5)
+ break;
+
+ switch ((c = *utf8++)) {
+ case '\n':
+ *out++ = '\\';
+ *out++ = 'n';
+ max -= 2;
+ break;
+ case '\r':
+ *out++ = '\\';
+ *out++ = 'n';
+ max -= 2;
+ case '\t':
+ *out++ = '\\';
+ *out++ = 't';
+ max -= 2;
+ break;
+ case '\b':
+ *out++ = '\\';
+ *out++ = 'b';
+ max -= 2;
+ break;
+ case '\f':
+ *out++ = '\\';
+ *out++ = 'r';
+ max -= 2;
+ break;
+ case '\\':
+ case '(':
+ case ')':
+ *out++ = '\\';
+ *out++ = c;
+ max -= 2;
+ break;
+ default:
+ if (isprint (c) || isspace (c)) {
+ *out++ = c;
+ } else {
+ int octal = 0;
+ while (c) {
+ octal *= 10;
+ octal += c&7;
+ c /= 8;
+ }
+ octal = snprintf (out, max, "\\%03d", octal);
+ out += octal;
+ max -= octal;
+ }
+ break;
+ }
+ }
+DONE:
+ *out++ = ')';
+ *out = '\0';
}
static void
@@ -1357,17 +1538,9 @@ _emit_source_image (cairo_surface_t *surface)
DLCALL (cairo_paint, cr);
DLCALL (cairo_destroy, cr);
+ _emit_image (image, NULL);
fprintf (logfile,
- "dict\n"
- " /width %d set\n"
- " /height %d set\n"
- " /format //ARGB32 set\n"
- " /source ",
- obj->width, obj->height);
- _emit_image (image);
- fprintf (logfile,
- " /deflate filter set\n"
- " image set_source_image ");
+ " set_source_image ");
DLCALL (cairo_surface_destroy, image);
_get_object (SURFACE, surface)->foreign = false;
@@ -2238,7 +2411,7 @@ _emit_glyphs (cairo_scaled_font_t *font,
struct _data_stream stream;
if (num_glyphs == 1) {
- fprintf (logfile, "[%g %g <%x>]", x, y, glyphs->index);
+ fprintf (logfile, "[%g %g <%lx>]", x, y, glyphs->index);
} else {
fprintf (logfile, "[%g %g <~", x, y);
_write_base85_data_start (&stream);
@@ -2407,18 +2580,6 @@ cairo_append_path (cairo_t *cr, const cairo_path_t *path)
}
}
-static const char *
-_format_to_string (cairo_format_t format)
-{
- const char *names[] = {
- "ARGB32", /* CAIRO_FORMAT_ARGB32 */
- "RGB24", /* CAIRO_FORMAT_RGB24 */
- "A8", /* CAIRO_FORMAT_A8 */
- "A1" /* CAIRO_FORMAT_A1 */
- };
- return names[format];
-}
-
cairo_surface_t *
cairo_image_surface_create (cairo_format_t format, int width, int height)
{
@@ -2452,22 +2613,11 @@ cairo_image_surface_create_for_data (unsigned char *data, cairo_format_t format,
{
cairo_surface_t *ret;
long surface_id;
- const char *format_str;
ret = DLCALL (cairo_image_surface_create_for_data, data, format, width, height, stride);
surface_id = _create_surface_id (ret);
if (data != NULL && _write_lock ()) {
- format_str = _format_to_string (format);
-
- fprintf (logfile,
- "dict\n"
- " /width %d set\n"
- " /height %d set\n"
- " /format //%s set\n",
- width, height,
- format_str);
-
/* cairo_image_surface_create_for_data() is both used to supply
* foreign pixel data to cairo and in order to read pixels back.
* Defer grabbing the pixel contents until we have to, but only for
@@ -2476,17 +2626,26 @@ cairo_image_surface_create_for_data (unsigned char *data, cairo_format_t format,
*/
if (width * height < 128) {
fprintf (logfile, " /source ");
- _emit_image (ret);
- fprintf (logfile, " /deflate filter set\n");
+ _emit_image (ret, NULL);
+ fprintf (logfile,
+ " dup /s%ld exch def\n",
+ surface_id);
} else {
+ fprintf (logfile,
+ "dict\n"
+ " /width %d set\n"
+ " /height %d set\n"
+ " /format //%s set\n"
+ " image dup /s%ld exch def\n",
+ width, height,
+ _format_to_string (format),
+ surface_id);
+
_get_object (SURFACE, ret)->width = width;
_get_object (SURFACE, ret)->height = height;
_get_object (SURFACE, ret)->foreign = true;
}
- fprintf (logfile,
- " image dup /s%ld exch def\n",
- surface_id);
_get_object (SURFACE, ret)->defined = true;
_push_operand (SURFACE, ret);
_write_unlock ();
@@ -3243,37 +3402,20 @@ cairo_surface_t *
cairo_image_surface_create_from_png (const char *filename)
{
cairo_surface_t *ret;
- cairo_format_t format;
- int width;
- int height;
long surface_id;
- const char *format_str;
ret = DLCALL (cairo_image_surface_create_from_png, filename);
- width = cairo_image_surface_get_width (ret);
- height = cairo_image_surface_get_height (ret);
- format = cairo_image_surface_get_format (ret);
-
surface_id = _create_surface_id (ret);
- format_str = _format_to_string (format);
if (_write_lock ()) {
+ char filename_string[4096];
+
+ _encode_string_literal (filename_string, sizeof (filename_string),
+ filename, -1);
+ _emit_image (ret, " /filename %s set\n", filename_string);
fprintf (logfile,
- "dict\n"
- " /width %d set\n"
- " /height %d set\n"
- " /format //%s set\n"
- " /filename ",
- width, height, format_str);
- _emit_string_literal (filename, -1);
- fprintf (logfile,
- " set\n"
- " /source ");
- _emit_image (ret);
- fprintf (logfile,
- " /deflate filter set\n"
- " image dup /s%ld exch def\n",
+ " dup /s%ld exch def\n",
surface_id);
_get_object (SURFACE, ret)->defined = true;
_push_operand (SURFACE, ret);
@@ -3287,32 +3429,15 @@ cairo_surface_t *
cairo_image_surface_create_from_png_stream (cairo_read_func_t read_func, void *closure)
{
cairo_surface_t *ret;
- cairo_format_t format;
- int width;
- int height;
- const char *format_str;
long surface_id;
ret = DLCALL (cairo_image_surface_create_from_png_stream, read_func, closure);
- width = cairo_image_surface_get_width (ret);
- height = cairo_image_surface_get_height (ret);
- format = cairo_image_surface_get_format (ret);
-
surface_id = _create_surface_id (ret);
- format_str = _format_to_string (format);
if (_write_lock ()) {
+ _emit_image (ret, NULL);
fprintf (logfile,
- "dict\n"
- " /width %d set\n"
- " /height %d set\n"
- " /format //%s set\n"
- " /source ",
- width, height, format_str);
- _emit_image (ret);
- fprintf (logfile,
- " /deflate filter set\n"
- " image dup /s%ld exch def\n",
+ " dup /s%ld exch def\n",
surface_id);
_get_object (SURFACE, ret)->defined = true;
_push_operand (SURFACE, ret);
commit d63267e4e7e148836dcfc4c8e2a8396ddaab70d8
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Wed Nov 5 17:18:51 2008 +0000
[test] Update mime-data to check image/png
Add a "image/png" mime-type test.
diff --git a/test/Makefile.am b/test/Makefile.am
index d9d4d39..131ed60 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -1012,6 +1012,7 @@ EXTRA_DIST += \
6x13.pcf \
make-html.pl \
jpeg.jpg \
+png.png \
romedalen.jpg \
romedalen.png \
scarab.jpg \
diff --git a/test/mime-data.c b/test/mime-data.c
index a387d67..87fe74c 100644
--- a/test/mime-data.c
+++ b/test/mime-data.c
@@ -31,27 +31,23 @@
/* Basic test to exercise the new mime-data embedding. */
static cairo_status_t
-read_jpg_file (const cairo_test_context_t *ctx,
- unsigned char **data_out,
- unsigned int *length_out)
+read_file (const cairo_test_context_t *ctx,
+ const char *filename,
+ unsigned char **data_out,
+ unsigned int *length_out)
{
- /* Deliberately use a non-matching jpeg image, so that we can identify
- * when the JPEG representation is used in preference to the image
- * surface.
- */
- const char jpg_filename[] = "jpeg.jpg";
FILE *file;
unsigned char *buf;
unsigned int len;
- file = fopen (jpg_filename, "rb");
+ file = fopen (filename, "rb");
if (file == NULL) {
- char filename[4096];
+ char path[4096];
/* try again with srcdir */
- snprintf (filename, sizeof (filename),
- "%s/%s", ctx->srcdir, jpg_filename);
- file = fopen (filename, "rb");
+ snprintf (path, sizeof (path),
+ "%s/%s", ctx->srcdir, filename);
+ file = fopen (path, "rb");
}
if (file == NULL) {
switch (errno) {
@@ -79,37 +75,62 @@ read_jpg_file (const cairo_test_context_t *ctx,
}
static cairo_test_status_t
-draw (cairo_t *cr, int width, int height)
+paint_file (cairo_t *cr,
+ const char *filename, const char *mime_type,
+ int x, int y)
{
const cairo_test_context_t *ctx = cairo_test_get_context (cr);
cairo_surface_t *image;
- unsigned char *jpg_data;
- unsigned int jpg_len;
+ unsigned char *mime_data;
+ unsigned int mime_length;
cairo_status_t status;
- status = read_jpg_file (ctx, &jpg_data, &jpg_len);
- if (status) {
+ /* Deliberately use a non-matching MIME images, so that we can identify
+ * when the MIME representation is used in preference to the plain image
+ * surface.
+ */
+ status = read_file (ctx, filename, &mime_data, &mime_length);
+ if (status)
return cairo_test_status_from_status (ctx, status);
- }
image = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 200, 50);
- status = cairo_surface_set_mime_data (image, CAIRO_MIME_TYPE_JPEG,
- jpg_data, jpg_len, free);
+
+ status = cairo_surface_set_mime_data (image, mime_type,
+ mime_data, mime_length, free);
if (status) {
cairo_surface_destroy (image);
return cairo_test_status_from_status (ctx, status);
}
- cairo_set_source_surface (cr, image, 0, 0);
+ cairo_set_source_surface (cr, image, x, y);
cairo_surface_destroy (image);
+
cairo_paint (cr);
return CAIRO_TEST_SUCCESS;
}
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ const char jpg_filename[] = "jpeg.jpg";
+ const char png_filename[] = "png.png";
+ cairo_test_status_t status;
+
+ status = paint_file (cr, jpg_filename, CAIRO_MIME_TYPE_JPEG, 0, 0);
+ if (status)
+ return status;
+
+ status = paint_file (cr, png_filename, CAIRO_MIME_TYPE_PNG, 0, 50);
+ if (status)
+ return status;
+
+ return CAIRO_TEST_SUCCESS;
+}
+
CAIRO_TEST (mime_data,
"Check that the mime-data embedding works",
"jpeg, api", /* keywords */
NULL, /* requirements */
- 200, 50,
+ 200, 100,
NULL, draw)
diff --git a/test/mime-data.pdf.ref.png b/test/mime-data.pdf.ref.png
index cf53a61..ebfcb79 100644
Binary files a/test/mime-data.pdf.ref.png and b/test/mime-data.pdf.ref.png differ
diff --git a/test/mime-data.ps.ref.png b/test/mime-data.ps.ref.png
index cf53a61..ebfcb79 100644
Binary files a/test/mime-data.ps.ref.png and b/test/mime-data.ps.ref.png differ
diff --git a/test/mime-data.ref.png b/test/mime-data.ref.png
index 782a2ee..ccbf1b6 100644
Binary files a/test/mime-data.ref.png and b/test/mime-data.ref.png differ
diff --git a/test/mime-data.svg.ref.png b/test/mime-data.svg.ref.png
new file mode 100644
index 0000000..96a7bec
Binary files /dev/null and b/test/mime-data.svg.ref.png differ
diff --git a/test/png.png b/test/png.png
new file mode 100644
index 0000000..56c428e
Binary files /dev/null and b/test/png.png differ
commit e4ec5c762f6d01cc5af28dc0a256e268a04101aa
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Wed Nov 5 16:44:49 2008 +0000
[svg] Embed original PNG data.
Embed the attached PNG representation of a surface in preference to
re-encoding the surface.
diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 8c23242..cfc56c4 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -1016,6 +1016,40 @@ _cairo_surface_base64_encode_jpeg (cairo_surface_t *surface,
}
static cairo_int_status_t
+_cairo_surface_base64_encode_png (cairo_surface_t *surface,
+ cairo_output_stream_t *output)
+{
+ const unsigned char *mime_data;
+ unsigned int mime_data_length;
+ base64_write_closure_t info;
+ cairo_status_t status;
+
+ cairo_surface_get_mime_data (surface, CAIRO_MIME_TYPE_PNG,
+ &mime_data, &mime_data_length);
+ if (mime_data == NULL)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ _cairo_output_stream_printf (output, "data:image/png;base64,");
+
+ info.output = output;
+ info.in_mem = 0;
+ info.trailing = 0;
+
+ status = base64_write_func (&info, mime_data, mime_data_length);
+ if (status)
+ return status;
+
+ if (info.in_mem > 0) {
+ memset (info.src + info.in_mem, 0, 3 - info.in_mem);
+ info.trailing = 3 - info.in_mem;
+ info.in_mem = 3;
+ status = base64_write_func (&info, NULL, 0);
+ }
+
+ return status;
+}
+
+static cairo_int_status_t
_cairo_surface_base64_encode (cairo_surface_t *surface,
cairo_output_stream_t *output)
{
@@ -1026,6 +1060,10 @@ _cairo_surface_base64_encode (cairo_surface_t *surface,
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
+ status = _cairo_surface_base64_encode_png (surface, output);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+
info.output = output;
info.in_mem = 0;
info.trailing = 0;
commit e40d62a0fe96b8b937017a3bc2f18766c411ec41
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Wed Nov 5 16:38:34 2008 +0000
[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().
diff --git a/src/cairo-output-stream-private.h b/src/cairo-output-stream-private.h
index 787d061..6f10483 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 bae6ac4..c31c2da 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 4721825..b4aeb08 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 f8f8902..bb29a9f 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 a1cd0c5..cbc109f 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,
commit 89616dee8f11c6a7de3fa476b13661420648786f
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Wed Nov 5 16:41:13 2008 +0000
[surface] Don't allocate a structure for mime_data == NULL.
If the user attempts to clear the attached mime data representation, just
clear the user data slot and do not allocate an empty structure.
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 72997b0..9df75ca 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -682,15 +682,18 @@ cairo_surface_set_mime_data (cairo_surface_t *surface,
if (status)
return _cairo_surface_set_error (surface, status);
- mime_data = malloc (sizeof (cairo_mime_data_t));
- if (mime_data == NULL)
- return _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_NO_MEMORY));
+ if (data != NULL) {
+ mime_data = malloc (sizeof (cairo_mime_data_t));
+ if (mime_data == NULL)
+ return _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_NO_MEMORY));
- CAIRO_REFERENCE_COUNT_INIT (&mime_data->ref_count, 1);
+ CAIRO_REFERENCE_COUNT_INIT (&mime_data->ref_count, 1);
- mime_data->data = (unsigned char *) data;
- mime_data->length = length;
- mime_data->destroy = destroy;
+ mime_data->data = (unsigned char *) data;
+ mime_data->length = length;
+ mime_data->destroy = destroy;
+ } else
+ mime_data = NULL;
status = _cairo_user_data_array_set_data (&surface->user_data,
(cairo_user_data_key_t *) mime_type,
More information about the cairo-commit
mailing list