Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4349 Serge 1
/* cairo - a vector graphics library with display and print output
2
 *
3
 * Copyright © 2003 University of Southern California
4
 *
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.
12
 *
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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
16
 * You should have received a copy of the MPL along with this library
17
 * in the file COPYING-MPL-1.1
18
 *
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/
23
 *
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.
27
 *
28
 * The Original Code is the cairo graphics library.
29
 *
30
 * The Initial Developer of the Original Code is University of Southern
31
 * California.
32
 *
33
 * Contributor(s):
34
 *	Carl D. Worth 
35
 *	Kristian Høgsberg 
36
 *	Chris Wilson 
37
 */
38
 
39
#include "cairoint.h"
40
 
41
#include "cairo-error-private.h"
42
#include "cairo-image-surface-private.h"
43
#include "cairo-output-stream-private.h"
44
 
45
#include 
46
#include 
47
#include 
48
 
49
/**
50
 * SECTION:cairo-png
51
 * @Title: PNG Support
52
 * @Short_Description: Reading and writing PNG images
53
 * @See_Also: #cairo_surface_t
54
 *
55
 * The PNG functions allow reading PNG images into image surfaces, and writing
56
 * any surface to a PNG file.
57
 *
58
 * It is a toy API. It only offers very simple support for reading and
59
 * writing PNG files, which is sufficient for testing and
60
 * demonstration purposes. Applications which need more control over
61
 * the generated PNG file should access the pixel data directly, using
62
 * cairo_image_surface_get_data() or a backend-specific access
63
 * function, and process it with another library, e.g. gdk-pixbuf or
64
 * libpng.
65
 **/
66
 
67
/**
68
 * CAIRO_HAS_PNG_FUNCTIONS:
69
 *
70
 * Defined if the PNG functions are available.
71
 * This macro can be used to conditionally compile code using the cairo
72
 * PNG functions.
73
 *
74
 * Since: 1.0
75
 **/
76
 
77
struct png_read_closure_t {
78
    cairo_read_func_t		 read_func;
79
    void			*closure;
80
    cairo_output_stream_t	*png_data;
81
};
82
 
83
 
84
/* Unpremultiplies data and converts native endian ARGB => RGBA bytes */
85
static void
86
unpremultiply_data (png_structp png, png_row_infop row_info, png_bytep data)
87
{
88
    unsigned int i;
89
 
90
    for (i = 0; i < row_info->rowbytes; i += 4) {
91
        uint8_t *b = &data[i];
92
        uint32_t pixel;
93
        uint8_t  alpha;
94
 
95
	memcpy (&pixel, b, sizeof (uint32_t));
96
	alpha = (pixel & 0xff000000) >> 24;
97
        if (alpha == 0) {
98
	    b[0] = b[1] = b[2] = b[3] = 0;
99
	} else {
100
            b[0] = (((pixel & 0xff0000) >> 16) * 255 + alpha / 2) / alpha;
101
            b[1] = (((pixel & 0x00ff00) >>  8) * 255 + alpha / 2) / alpha;
102
            b[2] = (((pixel & 0x0000ff) >>  0) * 255 + alpha / 2) / alpha;
103
	    b[3] = alpha;
104
	}
105
    }
106
}
107
 
108
/* Converts native endian xRGB => RGBx bytes */
109
static void
110
convert_data_to_bytes (png_structp png, png_row_infop row_info, png_bytep data)
111
{
112
    unsigned int i;
113
 
114
    for (i = 0; i < row_info->rowbytes; i += 4) {
115
        uint8_t *b = &data[i];
116
        uint32_t pixel;
117
 
118
	memcpy (&pixel, b, sizeof (uint32_t));
119
 
120
	b[0] = (pixel & 0xff0000) >> 16;
121
	b[1] = (pixel & 0x00ff00) >>  8;
122
	b[2] = (pixel & 0x0000ff) >>  0;
123
	b[3] = 0;
124
    }
125
}
126
 
127
/* Use a couple of simple error callbacks that do not print anything to
128
 * stderr and rely on the user to check for errors via the #cairo_status_t
129
 * return.
130
 */
131
static void
132
png_simple_error_callback (png_structp png,
133
	                   png_const_charp error_msg)
134
{
135
    cairo_status_t *error = png_get_error_ptr (png);
136
 
137
    /* default to the most likely error */
138
    if (*error == CAIRO_STATUS_SUCCESS)
139
	*error = _cairo_error (CAIRO_STATUS_NO_MEMORY);
140
 
141
#ifdef PNG_SETJMP_SUPPORTED
142
    longjmp (png_jmpbuf (png), 1);
143
#endif
144
 
145
    /* if we get here, then we have to choice but to abort ... */
146
}
147
 
148
static void
149
png_simple_warning_callback (png_structp png,
150
	                     png_const_charp error_msg)
151
{
152
    /* png does not expect to abort and will try to tidy up and continue
153
     * loading the image after a warning. So we also want to return the
154
     * (incorrect?) surface.
155
     *
156
     * We use our own warning callback to squelch any attempts by libpng
157
     * to write to stderr as we may not be in control of that output.
158
     */
159
}
160
 
161
 
162
/* Starting with libpng-1.2.30, we must explicitly specify an output_flush_fn.
163
 * Otherwise, we will segfault if we are writing to a stream. */
164
static void
165
png_simple_output_flush_fn (png_structp png_ptr)
166
{
167
}
168
 
169
static cairo_status_t
170
write_png (cairo_surface_t	*surface,
171
	   png_rw_ptr		write_func,
172
	   void			*closure)
173
{
174
    int i;
175
    cairo_int_status_t status;
176
    cairo_image_surface_t *image;
177
    cairo_image_surface_t * volatile clone;
178
    void *image_extra;
179
    png_struct *png;
180
    png_info *info;
181
    png_byte **volatile rows = NULL;
182
    png_color_16 white;
183
    int png_color_type;
184
    int bpc;
185
 
186
    status = _cairo_surface_acquire_source_image (surface,
187
						  &image,
188
						  &image_extra);
189
 
190
    if (status == CAIRO_INT_STATUS_UNSUPPORTED)
191
	return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
192
    else if (unlikely (status))
193
        return status;
194
 
195
    /* PNG complains about "Image width or height is zero in IHDR" */
196
    if (image->width == 0 || image->height == 0) {
197
	status = _cairo_error (CAIRO_STATUS_WRITE_ERROR);
198
	goto BAIL1;
199
    }
200
 
201
    /* Handle the various fallback formats (e.g. low bit-depth XServers)
202
     * by coercing them to a simpler format using pixman.
203
     */
204
    clone = _cairo_image_surface_coerce (image);
205
    status = clone->base.status;
206
    if (unlikely (status))
207
        goto BAIL1;
208
 
209
    rows = _cairo_malloc_ab (clone->height, sizeof (png_byte*));
210
    if (unlikely (rows == NULL)) {
211
	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
212
	goto BAIL2;
213
    }
214
 
215
    for (i = 0; i < clone->height; i++)
216
	rows[i] = (png_byte *) clone->data + i * clone->stride;
217
 
218
    png = png_create_write_struct (PNG_LIBPNG_VER_STRING, &status,
219
	                           png_simple_error_callback,
220
	                           png_simple_warning_callback);
221
    if (unlikely (png == NULL)) {
222
	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
223
	goto BAIL3;
224
    }
225
 
226
    info = png_create_info_struct (png);
227
    if (unlikely (info == NULL)) {
228
	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
229
	goto BAIL4;
230
    }
231
 
232
#ifdef PNG_SETJMP_SUPPORTED
233
    if (setjmp (png_jmpbuf (png)))
234
	goto BAIL4;
235
#endif
236
 
237
    png_set_write_fn (png, closure, write_func, png_simple_output_flush_fn);
238
 
239
    switch (clone->format) {
240
    case CAIRO_FORMAT_ARGB32:
241
	bpc = 8;
242
	if (_cairo_image_analyze_transparency (clone) == CAIRO_IMAGE_IS_OPAQUE)
243
	    png_color_type = PNG_COLOR_TYPE_RGB;
244
	else
245
	    png_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
246
	break;
247
    case CAIRO_FORMAT_RGB30:
248
	bpc = 10;
249
	png_color_type = PNG_COLOR_TYPE_RGB;
250
	break;
251
    case CAIRO_FORMAT_RGB24:
252
	bpc = 8;
253
	png_color_type = PNG_COLOR_TYPE_RGB;
254
	break;
255
    case CAIRO_FORMAT_A8:
256
	bpc = 8;
257
	png_color_type = PNG_COLOR_TYPE_GRAY;
258
	break;
259
    case CAIRO_FORMAT_A1:
260
	bpc = 1;
261
	png_color_type = PNG_COLOR_TYPE_GRAY;
262
#ifndef WORDS_BIGENDIAN
263
	png_set_packswap (png);
264
#endif
265
	break;
266
    case CAIRO_FORMAT_INVALID:
267
    case CAIRO_FORMAT_RGB16_565:
268
    default:
269
	status = _cairo_error (CAIRO_STATUS_INVALID_FORMAT);
270
	goto BAIL4;
271
    }
272
 
273
    png_set_IHDR (png, info,
274
		  clone->width,
275
		  clone->height, bpc,
276
		  png_color_type,
277
		  PNG_INTERLACE_NONE,
278
		  PNG_COMPRESSION_TYPE_DEFAULT,
279
		  PNG_FILTER_TYPE_DEFAULT);
280
 
281
    white.gray = (1 << bpc) - 1;
282
    white.red = white.blue = white.green = white.gray;
283
    png_set_bKGD (png, info, &white);
284
 
285
    if (0) { /* XXX extract meta-data from surface (i.e. creation date) */
286
	png_time pt;
287
 
288
	png_convert_from_time_t (&pt, time (NULL));
289
	png_set_tIME (png, info, &pt);
290
    }
291
 
292
    /* We have to call png_write_info() before setting up the write
293
     * transformation, since it stores data internally in 'png'
294
     * that is needed for the write transformation functions to work.
295
     */
296
    png_write_info (png, info);
297
 
298
    if (png_color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
299
	png_set_write_user_transform_fn (png, unpremultiply_data);
300
    } else if (png_color_type == PNG_COLOR_TYPE_RGB) {
301
	png_set_write_user_transform_fn (png, convert_data_to_bytes);
302
	png_set_filler (png, 0, PNG_FILLER_AFTER);
303
    }
304
 
305
    png_write_image (png, rows);
306
    png_write_end (png, info);
307
 
308
BAIL4:
309
    png_destroy_write_struct (&png, &info);
310
BAIL3:
311
    free (rows);
312
BAIL2:
313
    cairo_surface_destroy (&clone->base);
314
BAIL1:
315
    _cairo_surface_release_source_image (surface, image, image_extra);
316
 
317
    return status;
318
}
319
 
320
static void
321
stdio_write_func (png_structp png, png_bytep data, png_size_t size)
322
{
323
    FILE *fp;
324
 
325
    fp = png_get_io_ptr (png);
326
    while (size) {
327
	size_t ret = fwrite (data, 1, size, fp);
328
	size -= ret;
329
	data += ret;
330
	if (size && ferror (fp)) {
331
	    cairo_status_t *error = png_get_error_ptr (png);
332
	    if (*error == CAIRO_STATUS_SUCCESS)
333
		*error = _cairo_error (CAIRO_STATUS_WRITE_ERROR);
334
	    png_error (png, NULL);
335
	}
336
    }
337
}
338
 
339
/**
340
 * cairo_surface_write_to_png:
341
 * @surface: a #cairo_surface_t with pixel contents
342
 * @filename: the name of a file to write to
343
 *
344
 * Writes the contents of @surface to a new file @filename as a PNG
345
 * image.
346
 *
347
 * Return value: %CAIRO_STATUS_SUCCESS if the PNG file was written
348
 * successfully. Otherwise, %CAIRO_STATUS_NO_MEMORY if memory could not
349
 * be allocated for the operation or
350
 * %CAIRO_STATUS_SURFACE_TYPE_MISMATCH if the surface does not have
351
 * pixel contents, or %CAIRO_STATUS_WRITE_ERROR if an I/O error occurs
352
 * while attempting to write the file.
353
 *
354
 * Since: 1.0
355
 **/
356
cairo_status_t
357
cairo_surface_write_to_png (cairo_surface_t	*surface,
358
			    const char		*filename)
359
{
360
    FILE *fp;
361
    cairo_status_t status;
362
 
363
    if (surface->status)
364
	return surface->status;
365
 
366
    if (surface->finished)
367
	return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED);
368
 
369
    fp = fopen (filename, "wb");
370
    if (fp == NULL) {
371
	switch (errno) {
372
	case ENOMEM:
373
	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
374
	default:
375
	    return _cairo_error (CAIRO_STATUS_WRITE_ERROR);
376
	}
377
    }
378
 
379
    status = write_png (surface, stdio_write_func, fp);
380
 
381
    if (fclose (fp) && status == CAIRO_STATUS_SUCCESS)
382
	status = _cairo_error (CAIRO_STATUS_WRITE_ERROR);
383
 
384
    return status;
385
}
386
 
387
struct png_write_closure_t {
388
    cairo_write_func_t		 write_func;
389
    void			*closure;
390
};
391
 
392
static void
393
stream_write_func (png_structp png, png_bytep data, png_size_t size)
394
{
395
    cairo_status_t status;
396
    struct png_write_closure_t *png_closure;
397
 
398
    png_closure = png_get_io_ptr (png);
399
    status = png_closure->write_func (png_closure->closure, data, size);
400
    if (unlikely (status)) {
401
	cairo_status_t *error = png_get_error_ptr (png);
402
	if (*error == CAIRO_STATUS_SUCCESS)
403
	    *error = status;
404
	png_error (png, NULL);
405
    }
406
}
407
 
408
/**
409
 * cairo_surface_write_to_png_stream:
410
 * @surface: a #cairo_surface_t with pixel contents
411
 * @write_func: a #cairo_write_func_t
412
 * @closure: closure data for the write function
413
 *
414
 * Writes the image surface to the write function.
415
 *
416
 * Return value: %CAIRO_STATUS_SUCCESS if the PNG file was written
417
 * successfully.  Otherwise, %CAIRO_STATUS_NO_MEMORY is returned if
418
 * memory could not be allocated for the operation,
419
 * %CAIRO_STATUS_SURFACE_TYPE_MISMATCH if the surface does not have
420
 * pixel contents.
421
 *
422
 * Since: 1.0
423
 **/
424
cairo_status_t
425
cairo_surface_write_to_png_stream (cairo_surface_t	*surface,
426
				   cairo_write_func_t	write_func,
427
				   void			*closure)
428
{
429
    struct png_write_closure_t png_closure;
430
 
431
    if (surface->status)
432
	return surface->status;
433
 
434
    if (surface->finished)
435
	return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED);
436
 
437
    png_closure.write_func = write_func;
438
    png_closure.closure = closure;
439
 
440
    return write_png (surface, stream_write_func, &png_closure);
441
}
442
slim_hidden_def (cairo_surface_write_to_png_stream);
443
 
444
static inline int
445
multiply_alpha (int alpha, int color)
446
{
447
    int temp = (alpha * color) + 0x80;
448
    return ((temp + (temp >> 8)) >> 8);
449
}
450
 
451
/* Premultiplies data and converts RGBA bytes => native endian */
452
static void
453
premultiply_data (png_structp   png,
454
                  png_row_infop row_info,
455
                  png_bytep     data)
456
{
457
    unsigned int i;
458
 
459
    for (i = 0; i < row_info->rowbytes; i += 4) {
460
	uint8_t *base  = &data[i];
461
	uint8_t  alpha = base[3];
462
	uint32_t p;
463
 
464
	if (alpha == 0) {
465
	    p = 0;
466
	} else {
467
	    uint8_t  red   = base[0];
468
	    uint8_t  green = base[1];
469
	    uint8_t  blue  = base[2];
470
 
471
	    if (alpha != 0xff) {
472
		red   = multiply_alpha (alpha, red);
473
		green = multiply_alpha (alpha, green);
474
		blue  = multiply_alpha (alpha, blue);
475
	    }
476
	    p = (alpha << 24) | (red << 16) | (green << 8) | (blue << 0);
477
	}
478
	memcpy (base, &p, sizeof (uint32_t));
479
    }
480
}
481
 
482
/* Converts RGBx bytes to native endian xRGB */
483
static void
484
convert_bytes_to_data (png_structp png, png_row_infop row_info, png_bytep data)
485
{
486
    unsigned int i;
487
 
488
    for (i = 0; i < row_info->rowbytes; i += 4) {
489
	uint8_t *base  = &data[i];
490
	uint8_t  red   = base[0];
491
	uint8_t  green = base[1];
492
	uint8_t  blue  = base[2];
493
	uint32_t pixel;
494
 
495
	pixel = (0xff << 24) | (red << 16) | (green << 8) | (blue << 0);
496
	memcpy (base, &pixel, sizeof (uint32_t));
497
    }
498
}
499
 
500
static cairo_status_t
501
stdio_read_func (void *closure, unsigned char *data, unsigned int size)
502
{
503
    FILE *file = closure;
504
 
505
    while (size) {
506
	size_t ret;
507
 
508
	ret = fread (data, 1, size, file);
509
	size -= ret;
510
	data += ret;
511
 
512
	if (size && (feof (file) || ferror (file)))
513
	    return _cairo_error (CAIRO_STATUS_READ_ERROR);
514
    }
515
 
516
    return CAIRO_STATUS_SUCCESS;
517
}
518
 
519
static void
520
stream_read_func (png_structp png, png_bytep data, png_size_t size)
521
{
522
    cairo_status_t status;
523
    struct png_read_closure_t *png_closure;
524
 
525
    png_closure = png_get_io_ptr (png);
526
    status = png_closure->read_func (png_closure->closure, data, size);
527
    if (unlikely (status)) {
528
	cairo_status_t *error = png_get_error_ptr (png);
529
	if (*error == CAIRO_STATUS_SUCCESS)
530
	    *error = status;
531
	png_error (png, NULL);
532
    }
533
 
534
    _cairo_output_stream_write (png_closure->png_data, data, size);
535
}
536
 
537
static cairo_surface_t *
538
read_png (struct png_read_closure_t *png_closure)
539
{
540
    cairo_surface_t *surface;
541
    png_struct *png = NULL;
542
    png_info *info;
543
    png_byte *data = NULL;
544
    png_byte **row_pointers = NULL;
545
    png_uint_32 png_width, png_height;
546
    int depth, color_type, interlace, stride;
547
    unsigned int i;
548
    cairo_format_t format;
549
    cairo_status_t status;
550
    unsigned char *mime_data;
551
    unsigned long mime_data_length;
552
 
553
    png_closure->png_data = _cairo_memory_stream_create ();
554
 
555
    /* XXX: Perhaps we'll want some other error handlers? */
556
    png = png_create_read_struct (PNG_LIBPNG_VER_STRING,
557
                                  &status,
558
	                          png_simple_error_callback,
559
	                          png_simple_warning_callback);
560
    if (unlikely (png == NULL)) {
561
	surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
562
	goto BAIL;
563
    }
564
 
565
    info = png_create_info_struct (png);
566
    if (unlikely (info == NULL)) {
567
	surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
568
	goto BAIL;
569
    }
570
 
571
    png_set_read_fn (png, png_closure, stream_read_func);
572
 
573
    status = CAIRO_STATUS_SUCCESS;
574
#ifdef PNG_SETJMP_SUPPORTED
575
    if (setjmp (png_jmpbuf (png))) {
576
	surface = _cairo_surface_create_in_error (status);
577
	goto BAIL;
578
    }
579
#endif
580
 
581
    png_read_info (png, info);
582
 
583
    png_get_IHDR (png, info,
584
                  &png_width, &png_height, &depth,
585
                  &color_type, &interlace, NULL, NULL);
586
    if (unlikely (status)) { /* catch any early warnings */
587
	surface = _cairo_surface_create_in_error (status);
588
	goto BAIL;
589
    }
590
 
591
    /* convert palette/gray image to rgb */
592
    if (color_type == PNG_COLOR_TYPE_PALETTE)
593
        png_set_palette_to_rgb (png);
594
 
595
    /* expand gray bit depth if needed */
596
    if (color_type == PNG_COLOR_TYPE_GRAY) {
597
#if PNG_LIBPNG_VER >= 10209
598
        png_set_expand_gray_1_2_4_to_8 (png);
599
#else
600
        png_set_gray_1_2_4_to_8 (png);
601
#endif
602
    }
603
 
604
    /* transform transparency to alpha */
605
    if (png_get_valid (png, info, PNG_INFO_tRNS))
606
        png_set_tRNS_to_alpha (png);
607
 
608
    if (depth == 16)
609
        png_set_strip_16 (png);
610
 
611
    if (depth < 8)
612
        png_set_packing (png);
613
 
614
    /* convert grayscale to RGB */
615
    if (color_type == PNG_COLOR_TYPE_GRAY ||
616
	color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
617
    {
618
	png_set_gray_to_rgb (png);
619
    }
620
 
621
    if (interlace != PNG_INTERLACE_NONE)
622
        png_set_interlace_handling (png);
623
 
624
    png_set_filler (png, 0xff, PNG_FILLER_AFTER);
625
 
626
    /* recheck header after setting EXPAND options */
627
    png_read_update_info (png, info);
628
    png_get_IHDR (png, info,
629
                  &png_width, &png_height, &depth,
630
                  &color_type, &interlace, NULL, NULL);
631
    if (depth != 8 ||
632
	! (color_type == PNG_COLOR_TYPE_RGB ||
633
	   color_type == PNG_COLOR_TYPE_RGB_ALPHA))
634
    {
635
	surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_READ_ERROR));
636
	goto BAIL;
637
    }
638
 
639
    switch (color_type) {
640
	default:
641
	    ASSERT_NOT_REACHED;
642
	    /* fall-through just in case ;-) */
643
 
644
	case PNG_COLOR_TYPE_RGB_ALPHA:
645
	    format = CAIRO_FORMAT_ARGB32;
646
	    png_set_read_user_transform_fn (png, premultiply_data);
647
	    break;
648
 
649
	case PNG_COLOR_TYPE_RGB:
650
	    format = CAIRO_FORMAT_RGB24;
651
	    png_set_read_user_transform_fn (png, convert_bytes_to_data);
652
	    break;
653
    }
654
 
655
    stride = cairo_format_stride_for_width (format, png_width);
656
    if (stride < 0) {
657
	surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_STRIDE));
658
	goto BAIL;
659
    }
660
 
661
    data = _cairo_malloc_ab (png_height, stride);
662
    if (unlikely (data == NULL)) {
663
	surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
664
	goto BAIL;
665
    }
666
 
667
    row_pointers = _cairo_malloc_ab (png_height, sizeof (char *));
668
    if (unlikely (row_pointers == NULL)) {
669
	surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
670
	goto BAIL;
671
    }
672
 
673
    for (i = 0; i < png_height; i++)
674
        row_pointers[i] = &data[i * stride];
675
 
676
    png_read_image (png, row_pointers);
677
    png_read_end (png, info);
678
 
679
    if (unlikely (status)) { /* catch any late warnings - probably hit an error already */
680
	surface = _cairo_surface_create_in_error (status);
681
	goto BAIL;
682
    }
683
 
684
    surface = cairo_image_surface_create_for_data (data, format,
685
						   png_width, png_height,
686
						   stride);
687
    if (surface->status)
688
	goto BAIL;
689
 
690
    _cairo_image_surface_assume_ownership_of_data ((cairo_image_surface_t*)surface);
691
    data = NULL;
692
 
693
    _cairo_debug_check_image_surface_is_defined (surface);
694
 
695
    status = _cairo_memory_stream_destroy (png_closure->png_data,
696
					   &mime_data,
697
					   &mime_data_length);
698
    png_closure->png_data = NULL;
699
    if (unlikely (status)) {
700
	cairo_surface_destroy (surface);
701
	surface = _cairo_surface_create_in_error (status);
702
	goto BAIL;
703
    }
704
 
705
    status = cairo_surface_set_mime_data (surface,
706
					  CAIRO_MIME_TYPE_PNG,
707
					  mime_data,
708
					  mime_data_length,
709
					  free,
710
					  mime_data);
711
    if (unlikely (status)) {
712
	free (mime_data);
713
	cairo_surface_destroy (surface);
714
	surface = _cairo_surface_create_in_error (status);
715
	goto BAIL;
716
    }
717
 
718
 BAIL:
719
    free (row_pointers);
720
    free (data);
721
    if (png != NULL)
722
	png_destroy_read_struct (&png, &info, NULL);
723
    if (png_closure->png_data != NULL) {
724
	cairo_status_t status_ignored;
725
 
726
	status_ignored = _cairo_output_stream_destroy (png_closure->png_data);
727
    }
728
 
729
    return surface;
730
}
731
 
732
/**
733
 * cairo_image_surface_create_from_png:
734
 * @filename: name of PNG file to load
735
 *
736
 * Creates a new image surface and initializes the contents to the
737
 * given PNG file.
738
 *
739
 * Return value: a new #cairo_surface_t initialized with the contents
740
 * of the PNG file, or a "nil" surface if any error occurred. A nil
741
 * surface can be checked for with cairo_surface_status(surface) which
742
 * may return one of the following values:
743
 *
744
 *	%CAIRO_STATUS_NO_MEMORY
745
 *	%CAIRO_STATUS_FILE_NOT_FOUND
746
 *	%CAIRO_STATUS_READ_ERROR
747
 *
748
 * Alternatively, you can allow errors to propagate through the drawing
749
 * operations and check the status on the context upon completion
750
 * using cairo_status().
751
 *
752
 * Since: 1.0
753
 **/
754
cairo_surface_t *
755
cairo_image_surface_create_from_png (const char *filename)
756
{
757
    struct png_read_closure_t png_closure;
758
    cairo_surface_t *surface;
759
 
760
    png_closure.closure = fopen (filename, "rb");
761
    if (png_closure.closure == NULL) {
762
	cairo_status_t status;
763
	switch (errno) {
764
	case ENOMEM:
765
	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
766
	    break;
767
	case ENOENT:
768
	    status = _cairo_error (CAIRO_STATUS_FILE_NOT_FOUND);
769
	    break;
770
	default:
771
	    status = _cairo_error (CAIRO_STATUS_READ_ERROR);
772
	    break;
773
	}
774
	return _cairo_surface_create_in_error (status);
775
    }
776
 
777
    png_closure.read_func = stdio_read_func;
778
 
779
    surface = read_png (&png_closure);
780
 
781
    fclose (png_closure.closure);
782
 
783
    return surface;
784
}
785
 
786
/**
787
 * cairo_image_surface_create_from_png_stream:
788
 * @read_func: function called to read the data of the file
789
 * @closure: data to pass to @read_func.
790
 *
791
 * Creates a new image surface from PNG data read incrementally
792
 * via the @read_func function.
793
 *
794
 * Return value: a new #cairo_surface_t initialized with the contents
795
 * of the PNG file or a "nil" surface if the data read is not a valid PNG image
796
 * or memory could not be allocated for the operation.  A nil
797
 * surface can be checked for with cairo_surface_status(surface) which
798
 * may return one of the following values:
799
 *
800
 *	%CAIRO_STATUS_NO_MEMORY
801
 *	%CAIRO_STATUS_READ_ERROR
802
 *
803
 * Alternatively, you can allow errors to propagate through the drawing
804
 * operations and check the status on the context upon completion
805
 * using cairo_status().
806
 *
807
 * Since: 1.0
808
 **/
809
cairo_surface_t *
810
cairo_image_surface_create_from_png_stream (cairo_read_func_t	read_func,
811
					    void		*closure)
812
{
813
    struct png_read_closure_t png_closure;
814
 
815
    png_closure.read_func = read_func;
816
    png_closure.closure = closure;
817
 
818
    return read_png (&png_closure);
819
}