Add stubs for Direct3D9 backend.
[cairo/gpu.git] / src / cairo-png.c
blobd4f04760baa675bd67c5f181be4fa284bca9aa4b
1 /* cairo - a vector graphics library with display and print output
3 * Copyright © 2003 University of Southern California
5 * This library is free software; you can redistribute it and/or
6 * modify it either under the terms of the GNU Lesser General Public
7 * License version 2.1 as published by the Free Software Foundation
8 * (the "LGPL") or, at your option, under the terms of the Mozilla
9 * Public License Version 1.1 (the "MPL"). If you do not alter this
10 * notice, a recipient may use your version of this file under either
11 * the MPL or the LGPL.
13 * You should have received a copy of the LGPL along with this library
14 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 * You should have received a copy of the MPL along with this library
17 * in the file COPYING-MPL-1.1
19 * The contents of this file are subject to the Mozilla Public License
20 * Version 1.1 (the "License"); you may not use this file except in
21 * compliance with the License. You may obtain a copy of the License at
22 * http://www.mozilla.org/MPL/
24 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
25 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
26 * the specific language governing rights and limitations.
28 * The Original Code is the cairo graphics library.
30 * The Initial Developer of the Original Code is University of Southern
31 * California.
33 * Contributor(s):
34 * Carl D. Worth <cworth@cworth.org>
35 * Kristian Høgsberg <krh@redhat.com>
36 * Chris Wilson <chris@chris-wilson.co.uk>
39 #include "cairoint.h"
40 #include "cairo-output-stream-private.h"
42 #include <stdio.h>
43 #include <errno.h>
44 #include <png.h>
46 struct png_read_closure_t {
47 cairo_read_func_t read_func;
48 void *closure;
49 cairo_output_stream_t *png_data;
53 /* Unpremultiplies data and converts native endian ARGB => RGBA bytes */
54 static void
55 unpremultiply_data (png_structp png, png_row_infop row_info, png_bytep data)
57 unsigned int i;
59 for (i = 0; i < row_info->rowbytes; i += 4) {
60 uint8_t *b = &data[i];
61 uint32_t pixel;
62 uint8_t alpha;
64 memcpy (&pixel, b, sizeof (uint32_t));
65 alpha = (pixel & 0xff000000) >> 24;
66 if (alpha == 0) {
67 b[0] = b[1] = b[2] = b[3] = 0;
68 } else {
69 b[0] = (((pixel & 0xff0000) >> 16) * 255 + alpha / 2) / alpha;
70 b[1] = (((pixel & 0x00ff00) >> 8) * 255 + alpha / 2) / alpha;
71 b[2] = (((pixel & 0x0000ff) >> 0) * 255 + alpha / 2) / alpha;
72 b[3] = alpha;
77 /* Converts native endian xRGB => RGBx bytes */
78 static void
79 convert_data_to_bytes (png_structp png, png_row_infop row_info, png_bytep data)
81 unsigned int i;
83 for (i = 0; i < row_info->rowbytes; i += 4) {
84 uint8_t *b = &data[i];
85 uint32_t pixel;
87 memcpy (&pixel, b, sizeof (uint32_t));
89 b[0] = (pixel & 0xff0000) >> 16;
90 b[1] = (pixel & 0x00ff00) >> 8;
91 b[2] = (pixel & 0x0000ff) >> 0;
92 b[3] = 0;
96 /* Use a couple of simple error callbacks that do not print anything to
97 * stderr and rely on the user to check for errors via the #cairo_status_t
98 * return.
100 static void
101 png_simple_error_callback (png_structp png,
102 png_const_charp error_msg)
104 cairo_status_t *error = png_get_error_ptr (png);
106 /* default to the most likely error */
107 if (*error == CAIRO_STATUS_SUCCESS)
108 *error = _cairo_error (CAIRO_STATUS_NO_MEMORY);
110 #ifdef PNG_SETJMP_SUPPORTED
111 longjmp (png_jmpbuf (png), 1);
112 #endif
114 /* if we get here, then we have to choice but to abort ... */
117 static void
118 png_simple_warning_callback (png_structp png,
119 png_const_charp error_msg)
121 cairo_status_t *error = png_get_error_ptr (png);
123 /* default to the most likely error */
124 if (*error == CAIRO_STATUS_SUCCESS)
125 *error = _cairo_error (CAIRO_STATUS_NO_MEMORY);
127 /* png does not expect to abort and will try to tidy up after a warning */
131 /* Starting with libpng-1.2.30, we must explicitly specify an output_flush_fn.
132 * Otherwise, we will segfault if we are writing to a stream. */
133 static void
134 png_simple_output_flush_fn (png_structp png_ptr)
138 static cairo_status_t
139 write_png (cairo_surface_t *surface,
140 png_rw_ptr write_func,
141 void *closure)
143 int i;
144 cairo_status_t status;
145 cairo_image_surface_t *image;
146 cairo_image_surface_t * volatile clone;
147 void *image_extra;
148 png_struct *png;
149 png_info *info;
150 png_byte **volatile rows = NULL;
151 png_color_16 white;
152 int png_color_type;
153 int depth;
155 status = _cairo_surface_acquire_source_image (surface,
156 &image,
157 &image_extra);
159 if (status == CAIRO_INT_STATUS_UNSUPPORTED)
160 return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
161 else if (unlikely (status))
162 return status;
164 /* PNG complains about "Image width or height is zero in IHDR" */
165 if (image->width == 0 || image->height == 0) {
166 status = _cairo_error (CAIRO_STATUS_WRITE_ERROR);
167 goto BAIL1;
170 /* Handle the various fallback formats (e.g. low bit-depth XServers)
171 * by coercing them to a simpler format using pixman.
173 if (image->format == CAIRO_FORMAT_INVALID) {
174 clone = _cairo_image_surface_coerce (image,
175 _cairo_format_from_content (image->base.content));
176 status = clone->base.status;
177 if (unlikely (status))
178 goto BAIL1;
179 } else
180 clone = image;
182 rows = _cairo_malloc_ab (clone->height, sizeof (png_byte*));
183 if (unlikely (rows == NULL)) {
184 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
185 goto BAIL2;
188 for (i = 0; i < clone->height; i++)
189 rows[i] = (png_byte *) clone->data + i * clone->stride;
191 png = png_create_write_struct (PNG_LIBPNG_VER_STRING, &status,
192 png_simple_error_callback,
193 png_simple_warning_callback);
194 if (unlikely (png == NULL)) {
195 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
196 goto BAIL3;
199 info = png_create_info_struct (png);
200 if (unlikely (info == NULL)) {
201 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
202 goto BAIL4;
205 #ifdef PNG_SETJMP_SUPPORTED
206 if (setjmp (png_jmpbuf (png)))
207 goto BAIL4;
208 #endif
210 png_set_write_fn (png, closure, write_func, png_simple_output_flush_fn);
212 switch (clone->format) {
213 case CAIRO_FORMAT_ARGB32:
214 depth = 8;
215 if (_cairo_image_analyze_transparency (clone) == CAIRO_IMAGE_IS_OPAQUE)
216 png_color_type = PNG_COLOR_TYPE_RGB;
217 else
218 png_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
219 break;
220 case CAIRO_FORMAT_RGB24:
221 depth = 8;
222 png_color_type = PNG_COLOR_TYPE_RGB;
223 break;
224 case CAIRO_FORMAT_A8:
225 depth = 8;
226 png_color_type = PNG_COLOR_TYPE_GRAY;
227 break;
228 case CAIRO_FORMAT_A1:
229 depth = 1;
230 png_color_type = PNG_COLOR_TYPE_GRAY;
231 #ifndef WORDS_BIGENDIAN
232 png_set_packswap (png);
233 #endif
234 break;
235 default:
236 status = _cairo_error (CAIRO_STATUS_INVALID_FORMAT);
237 goto BAIL4;
240 png_set_IHDR (png, info,
241 clone->width,
242 clone->height, depth,
243 png_color_type,
244 PNG_INTERLACE_NONE,
245 PNG_COMPRESSION_TYPE_DEFAULT,
246 PNG_FILTER_TYPE_DEFAULT);
248 white.gray = (1 << depth) - 1;
249 white.red = white.blue = white.green = white.gray;
250 png_set_bKGD (png, info, &white);
252 if (0) { /* XXX extract meta-data from surface (i.e. creation date) */
253 png_time pt;
255 png_convert_from_time_t (&pt, time (NULL));
256 png_set_tIME (png, info, &pt);
259 /* We have to call png_write_info() before setting up the write
260 * transformation, since it stores data internally in 'png'
261 * that is needed for the write transformation functions to work.
263 png_write_info (png, info);
265 if (png_color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
266 png_set_write_user_transform_fn (png, unpremultiply_data);
267 } else if (png_color_type == PNG_COLOR_TYPE_RGB) {
268 png_set_write_user_transform_fn (png, convert_data_to_bytes);
269 png_set_filler (png, 0, PNG_FILLER_AFTER);
272 png_write_image (png, rows);
273 png_write_end (png, info);
275 BAIL4:
276 png_destroy_write_struct (&png, &info);
277 BAIL3:
278 free (rows);
279 BAIL2:
280 if (clone != image)
281 cairo_surface_destroy (&clone->base);
282 BAIL1:
283 _cairo_surface_release_source_image (surface, image, image_extra);
285 return status;
288 static void
289 stdio_write_func (png_structp png, png_bytep data, png_size_t size)
291 FILE *fp;
293 fp = png_get_io_ptr (png);
294 while (size) {
295 size_t ret = fwrite (data, 1, size, fp);
296 size -= ret;
297 data += ret;
298 if (size && ferror (fp)) {
299 cairo_status_t *error = png_get_error_ptr (png);
300 if (*error == CAIRO_STATUS_SUCCESS)
301 *error = _cairo_error (CAIRO_STATUS_WRITE_ERROR);
302 png_error (png, NULL);
308 * cairo_surface_write_to_png:
309 * @surface: a #cairo_surface_t with pixel contents
310 * @filename: the name of a file to write to
312 * Writes the contents of @surface to a new file @filename as a PNG
313 * image.
315 * Return value: %CAIRO_STATUS_SUCCESS if the PNG file was written
316 * successfully. Otherwise, %CAIRO_STATUS_NO_MEMORY if memory could not
317 * be allocated for the operation or
318 * %CAIRO_STATUS_SURFACE_TYPE_MISMATCH if the surface does not have
319 * pixel contents, or %CAIRO_STATUS_WRITE_ERROR if an I/O error occurs
320 * while attempting to write the file.
322 cairo_status_t
323 cairo_surface_write_to_png (cairo_surface_t *surface,
324 const char *filename)
326 FILE *fp;
327 cairo_status_t status;
329 if (surface->status)
330 return surface->status;
332 if (surface->finished)
333 return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED);
335 fp = fopen (filename, "wb");
336 if (fp == NULL) {
337 switch (errno) {
338 case ENOMEM:
339 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
340 default:
341 return _cairo_error (CAIRO_STATUS_WRITE_ERROR);
345 status = write_png (surface, stdio_write_func, fp);
347 if (fclose (fp) && status == CAIRO_STATUS_SUCCESS)
348 status = _cairo_error (CAIRO_STATUS_WRITE_ERROR);
350 return status;
353 struct png_write_closure_t {
354 cairo_write_func_t write_func;
355 void *closure;
358 static void
359 stream_write_func (png_structp png, png_bytep data, png_size_t size)
361 cairo_status_t status;
362 struct png_write_closure_t *png_closure;
364 png_closure = png_get_io_ptr (png);
365 status = png_closure->write_func (png_closure->closure, data, size);
366 if (unlikely (status)) {
367 cairo_status_t *error = png_get_error_ptr (png);
368 if (*error == CAIRO_STATUS_SUCCESS)
369 *error = status;
370 png_error (png, NULL);
375 * cairo_surface_write_to_png_stream:
376 * @surface: a #cairo_surface_t with pixel contents
377 * @write_func: a #cairo_write_func_t
378 * @closure: closure data for the write function
380 * Writes the image surface to the write function.
382 * Return value: %CAIRO_STATUS_SUCCESS if the PNG file was written
383 * successfully. Otherwise, %CAIRO_STATUS_NO_MEMORY is returned if
384 * memory could not be allocated for the operation,
385 * %CAIRO_STATUS_SURFACE_TYPE_MISMATCH if the surface does not have
386 * pixel contents.
388 cairo_status_t
389 cairo_surface_write_to_png_stream (cairo_surface_t *surface,
390 cairo_write_func_t write_func,
391 void *closure)
393 struct png_write_closure_t png_closure;
395 if (surface->status)
396 return surface->status;
398 if (surface->finished)
399 return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED);
401 png_closure.write_func = write_func;
402 png_closure.closure = closure;
404 return write_png (surface, stream_write_func, &png_closure);
406 slim_hidden_def (cairo_surface_write_to_png_stream);
408 static inline int
409 multiply_alpha (int alpha, int color)
411 int temp = (alpha * color) + 0x80;
412 return ((temp + (temp >> 8)) >> 8);
415 /* Premultiplies data and converts RGBA bytes => native endian */
416 static void
417 premultiply_data (png_structp png,
418 png_row_infop row_info,
419 png_bytep data)
421 unsigned int i;
423 for (i = 0; i < row_info->rowbytes; i += 4) {
424 uint8_t *base = &data[i];
425 uint8_t alpha = base[3];
426 uint32_t p;
428 if (alpha == 0) {
429 p = 0;
430 } else {
431 uint8_t red = base[0];
432 uint8_t green = base[1];
433 uint8_t blue = base[2];
435 if (alpha != 0xff) {
436 red = multiply_alpha (alpha, red);
437 green = multiply_alpha (alpha, green);
438 blue = multiply_alpha (alpha, blue);
440 p = (alpha << 24) | (red << 16) | (green << 8) | (blue << 0);
442 memcpy (base, &p, sizeof (uint32_t));
446 /* Converts RGBx bytes to native endian xRGB */
447 static void
448 convert_bytes_to_data (png_structp png, png_row_infop row_info, png_bytep data)
450 unsigned int i;
452 for (i = 0; i < row_info->rowbytes; i += 4) {
453 uint8_t *base = &data[i];
454 uint8_t red = base[0];
455 uint8_t green = base[1];
456 uint8_t blue = base[2];
457 uint32_t pixel;
459 pixel = (0xff << 24) | (red << 16) | (green << 8) | (blue << 0);
460 memcpy (base, &pixel, sizeof (uint32_t));
464 static cairo_status_t
465 stdio_read_func (void *closure, unsigned char *data, unsigned int size)
467 FILE *file = closure;
469 while (size) {
470 size_t ret;
472 ret = fread (data, 1, size, file);
473 size -= ret;
474 data += ret;
476 if (size && (feof (file) || ferror (file)))
477 return _cairo_error (CAIRO_STATUS_READ_ERROR);
480 return CAIRO_STATUS_SUCCESS;
483 static void
484 stream_read_func (png_structp png, png_bytep data, png_size_t size)
486 cairo_status_t status;
487 struct png_read_closure_t *png_closure;
489 png_closure = png_get_io_ptr (png);
490 status = png_closure->read_func (png_closure->closure, data, size);
491 if (unlikely (status)) {
492 cairo_status_t *error = png_get_error_ptr (png);
493 if (*error == CAIRO_STATUS_SUCCESS)
494 *error = status;
495 png_error (png, NULL);
498 _cairo_output_stream_write (png_closure->png_data, data, size);
501 static cairo_surface_t *
502 read_png (struct png_read_closure_t *png_closure)
504 cairo_surface_t *surface;
505 png_struct *png = NULL;
506 png_info *info;
507 png_byte *data = NULL;
508 png_byte **row_pointers = NULL;
509 png_uint_32 png_width, png_height;
510 int depth, color_type, interlace, stride;
511 unsigned int i;
512 cairo_format_t format;
513 cairo_status_t status;
514 unsigned char *mime_data;
515 unsigned int mime_data_length;
517 png_closure->png_data = _cairo_memory_stream_create ();
519 /* XXX: Perhaps we'll want some other error handlers? */
520 png = png_create_read_struct (PNG_LIBPNG_VER_STRING,
521 &status,
522 png_simple_error_callback,
523 png_simple_warning_callback);
524 if (unlikely (png == NULL)) {
525 surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
526 goto BAIL;
529 info = png_create_info_struct (png);
530 if (unlikely (info == NULL)) {
531 surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
532 goto BAIL;
535 png_set_read_fn (png, png_closure, stream_read_func);
537 status = CAIRO_STATUS_SUCCESS;
538 #ifdef PNG_SETJMP_SUPPORTED
539 if (setjmp (png_jmpbuf (png))) {
540 surface = _cairo_surface_create_in_error (status);
541 goto BAIL;
543 #endif
545 png_read_info (png, info);
547 png_get_IHDR (png, info,
548 &png_width, &png_height, &depth,
549 &color_type, &interlace, NULL, NULL);
550 if (unlikely (status)) { /* catch any early warnings */
551 surface = _cairo_surface_create_in_error (status);
552 goto BAIL;
555 /* convert palette/gray image to rgb */
556 if (color_type == PNG_COLOR_TYPE_PALETTE)
557 png_set_palette_to_rgb (png);
559 /* expand gray bit depth if needed */
560 if (color_type == PNG_COLOR_TYPE_GRAY) {
561 #if PNG_LIBPNG_VER >= 10209
562 png_set_expand_gray_1_2_4_to_8 (png);
563 #else
564 png_set_gray_1_2_4_to_8 (png);
565 #endif
568 /* transform transparency to alpha */
569 if (png_get_valid (png, info, PNG_INFO_tRNS))
570 png_set_tRNS_to_alpha (png);
572 if (depth == 16)
573 png_set_strip_16 (png);
575 if (depth < 8)
576 png_set_packing (png);
578 /* convert grayscale to RGB */
579 if (color_type == PNG_COLOR_TYPE_GRAY ||
580 color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
582 png_set_gray_to_rgb (png);
585 if (interlace != PNG_INTERLACE_NONE)
586 png_set_interlace_handling (png);
588 png_set_filler (png, 0xff, PNG_FILLER_AFTER);
590 /* recheck header after setting EXPAND options */
591 png_read_update_info (png, info);
592 png_get_IHDR (png, info,
593 &png_width, &png_height, &depth,
594 &color_type, &interlace, NULL, NULL);
595 if (depth != 8 ||
596 ! (color_type == PNG_COLOR_TYPE_RGB ||
597 color_type == PNG_COLOR_TYPE_RGB_ALPHA))
599 surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_READ_ERROR));
600 goto BAIL;
603 switch (color_type) {
604 default:
605 ASSERT_NOT_REACHED;
606 /* fall-through just in case ;-) */
608 case PNG_COLOR_TYPE_RGB_ALPHA:
609 format = CAIRO_FORMAT_ARGB32;
610 png_set_read_user_transform_fn (png, premultiply_data);
611 break;
613 case PNG_COLOR_TYPE_RGB:
614 format = CAIRO_FORMAT_RGB24;
615 png_set_read_user_transform_fn (png, convert_bytes_to_data);
616 break;
619 stride = cairo_format_stride_for_width (format, png_width);
620 if (stride < 0) {
621 surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_STRIDE));
622 goto BAIL;
625 data = _cairo_malloc_ab (png_height, stride);
626 if (unlikely (data == NULL)) {
627 surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
628 goto BAIL;
631 row_pointers = _cairo_malloc_ab (png_height, sizeof (char *));
632 if (unlikely (row_pointers == NULL)) {
633 surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
634 goto BAIL;
637 for (i = 0; i < png_height; i++)
638 row_pointers[i] = &data[i * stride];
640 png_read_image (png, row_pointers);
641 png_read_end (png, info);
643 if (unlikely (status)) { /* catch any late warnings - probably hit an error already */
644 surface = _cairo_surface_create_in_error (status);
645 goto BAIL;
648 surface = cairo_image_surface_create_for_data (data, format,
649 png_width, png_height,
650 stride);
651 if (surface->status)
652 goto BAIL;
654 _cairo_image_surface_assume_ownership_of_data ((cairo_image_surface_t*)surface);
655 data = NULL;
657 _cairo_debug_check_image_surface_is_defined (surface);
659 status = _cairo_memory_stream_destroy (png_closure->png_data,
660 &mime_data,
661 &mime_data_length);
662 png_closure->png_data = NULL;
663 if (unlikely (status)) {
664 cairo_surface_destroy (surface);
665 surface = _cairo_surface_create_in_error (status);
666 goto BAIL;
669 status = cairo_surface_set_mime_data (surface,
670 CAIRO_MIME_TYPE_PNG,
671 mime_data,
672 mime_data_length,
673 free,
674 mime_data);
675 if (unlikely (status)) {
676 free (mime_data);
677 cairo_surface_destroy (surface);
678 surface = _cairo_surface_create_in_error (status);
679 goto BAIL;
682 BAIL:
683 if (row_pointers != NULL)
684 free (row_pointers);
685 if (data != NULL)
686 free (data);
687 if (png != NULL)
688 png_destroy_read_struct (&png, &info, NULL);
689 if (png_closure->png_data != NULL) {
690 cairo_status_t status_ignored;
692 status_ignored = _cairo_output_stream_destroy (png_closure->png_data);
695 return surface;
699 * cairo_image_surface_create_from_png:
700 * @filename: name of PNG file to load
702 * Creates a new image surface and initializes the contents to the
703 * given PNG file.
705 * Return value: a new #cairo_surface_t initialized with the contents
706 * of the PNG file, or a "nil" surface if any error occurred. A nil
707 * surface can be checked for with cairo_surface_status(surface) which
708 * may return one of the following values:
710 * %CAIRO_STATUS_NO_MEMORY
711 * %CAIRO_STATUS_FILE_NOT_FOUND
712 * %CAIRO_STATUS_READ_ERROR
714 * Alternatively, you can allow errors to propagate through the drawing
715 * operations and check the status on the context upon completion
716 * using cairo_status().
718 cairo_surface_t *
719 cairo_image_surface_create_from_png (const char *filename)
721 struct png_read_closure_t png_closure;
722 cairo_surface_t *surface;
724 png_closure.closure = fopen (filename, "rb");
725 if (png_closure.closure == NULL) {
726 cairo_status_t status;
727 switch (errno) {
728 case ENOMEM:
729 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
730 break;
731 case ENOENT:
732 status = _cairo_error (CAIRO_STATUS_FILE_NOT_FOUND);
733 break;
734 default:
735 status = _cairo_error (CAIRO_STATUS_READ_ERROR);
736 break;
738 return _cairo_surface_create_in_error (status);
741 png_closure.read_func = stdio_read_func;
743 surface = read_png (&png_closure);
745 fclose (png_closure.closure);
747 return surface;
751 * cairo_image_surface_create_from_png_stream:
752 * @read_func: function called to read the data of the file
753 * @closure: data to pass to @read_func.
755 * Creates a new image surface from PNG data read incrementally
756 * via the @read_func function.
758 * Return value: a new #cairo_surface_t initialized with the contents
759 * of the PNG file or a "nil" surface if the data read is not a valid PNG image
760 * or memory could not be allocated for the operation. A nil
761 * surface can be checked for with cairo_surface_status(surface) which
762 * may return one of the following values:
764 * %CAIRO_STATUS_NO_MEMORY
765 * %CAIRO_STATUS_READ_ERROR
767 * Alternatively, you can allow errors to propagate through the drawing
768 * operations and check the status on the context upon completion
769 * using cairo_status().
771 cairo_surface_t *
772 cairo_image_surface_create_from_png_stream (cairo_read_func_t read_func,
773 void *closure)
775 struct png_read_closure_t png_closure;
777 png_closure.read_func = read_func;
778 png_closure.closure = closure;
780 return read_png (&png_closure);