Subversion Repositories Scribus

Rev

Rev 14952 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
14952 fschmid 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
18122 mrdocs 15
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
14952 fschmid 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 <cworth@cworth.org>
35
 *      Kristian Høgsberg <krh@redhat.com>
36
 *      Chris Wilson <chris@chris-wilson.co.uk>
37
 */
38
 
39
#include "cairoint.h"
40
#include "cairo-output-stream-private.h"
41
 
42
#include <stdio.h>
43
#include <errno.h>
44
#include <png.h>
45
 
46
struct png_read_closure_t {
47
    cairo_read_func_t            read_func;
48
    void                        *closure;
49
    cairo_output_stream_t       *png_data;
50
};
51
 
52
 
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)
56
{
57
    unsigned int i;
58
 
59
    for (i = 0; i < row_info->rowbytes; i += 4) {
60
        uint8_t *b = &data[i];
61
        uint32_t pixel;
62
        uint8_t  alpha;
63
 
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;
73
        }
74
    }
75
}
76
 
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)
80
{
81
    unsigned int i;
82
 
83
    for (i = 0; i < row_info->rowbytes; i += 4) {
84
        uint8_t *b = &data[i];
85
        uint32_t pixel;
86
 
87
        memcpy (&pixel, b, sizeof (uint32_t));
88
 
89
        b[0] = (pixel & 0xff0000) >> 16;
90
        b[1] = (pixel & 0x00ff00) >>  8;
91
        b[2] = (pixel & 0x0000ff) >>  0;
92
        b[3] = 0;
93
    }
94
}
95
 
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.
99
 */
100
static void
101
png_simple_error_callback (png_structp png,
102
                           png_const_charp error_msg)
103
{
104
    cairo_status_t *error = png_get_error_ptr (png);
105
 
106
    /* default to the most likely error */
107
    if (*error == CAIRO_STATUS_SUCCESS)
108
        *error = _cairo_error (CAIRO_STATUS_NO_MEMORY);
109
 
110
#ifdef PNG_SETJMP_SUPPORTED
111
    longjmp (png_jmpbuf (png), 1);
112
#endif
113
 
114
    /* if we get here, then we have to choice but to abort ... */
115
}
116
 
117
static void
118
png_simple_warning_callback (png_structp png,
119
                             png_const_charp error_msg)
120
{
121
    cairo_status_t *error = png_get_error_ptr (png);
122
 
123
    /* default to the most likely error */
124
    if (*error == CAIRO_STATUS_SUCCESS)
125
        *error = _cairo_error (CAIRO_STATUS_NO_MEMORY);
126
 
127
    /* png does not expect to abort and will try to tidy up after a warning */
128
}
129
 
130
 
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)
135
{
136
}
137
 
138
static cairo_status_t
139
write_png (cairo_surface_t      *surface,
140
           png_rw_ptr           write_func,
141
           void                 *closure)
142
{
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;
154
 
155
    status = _cairo_surface_acquire_source_image (surface,
156
                                                  &image,
157
                                                  &image_extra);
158
 
159
    if (status == CAIRO_INT_STATUS_UNSUPPORTED)
160
        return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
161
    else if (unlikely (status))
162
        return status;
163
 
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;
168
    }
169
 
170
    /* Handle the various fallback formats (e.g. low bit-depth XServers)
171
     * by coercing them to a simpler format using pixman.
172
     */
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;
181
 
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;
186
    }
187
 
188
    for (i = 0; i < clone->height; i++)
189
        rows[i] = (png_byte *) clone->data + i * clone->stride;
190
 
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;
197
    }
198
 
199
    info = png_create_info_struct (png);
200
    if (unlikely (info == NULL)) {
201
        status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
202
        goto BAIL4;
203
    }
204
 
205
#ifdef PNG_SETJMP_SUPPORTED
206
    if (setjmp (png_jmpbuf (png)))
207
        goto BAIL4;
208
#endif
209
 
210
    png_set_write_fn (png, closure, write_func, png_simple_output_flush_fn);
211
 
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;
238
    }
239
 
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);
247
 
248
    white.gray = (1 << depth) - 1;
249
    white.red = white.blue = white.green = white.gray;
250
    png_set_bKGD (png, info, &white);
251
 
252
    if (0) { /* XXX extract meta-data from surface (i.e. creation date) */
253
        png_time pt;
254
 
255
        png_convert_from_time_t (&pt, time (NULL));
256
        png_set_tIME (png, info, &pt);
257
    }
258
 
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.
262
     */
263
    png_write_info (png, info);
264
 
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);
270
    }
271
 
272
    png_write_image (png, rows);
273
    png_write_end (png, info);
274
 
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);
284
 
285
    return status;
286
}
287
 
288
static void
289
stdio_write_func (png_structp png, png_bytep data, png_size_t size)
290
{
291
    FILE *fp;
292
 
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);
303
        }
304
    }
305
}
306
 
307
/**
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
311
 *
312
 * Writes the contents of @surface to a new file @filename as a PNG
313
 * image.
314
 *
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.
321
 **/
322
cairo_status_t
323
cairo_surface_write_to_png (cairo_surface_t     *surface,
324
                            const char          *filename)
325
{
326
    FILE *fp;
327
    cairo_status_t status;
328
 
329
    if (surface->status)
330
        return surface->status;
331
 
332
    if (surface->finished)
333
        return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED);
334
 
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);
342
        }
343
    }
344
 
345
    status = write_png (surface, stdio_write_func, fp);
346
 
347
    if (fclose (fp) && status == CAIRO_STATUS_SUCCESS)
348
        status = _cairo_error (CAIRO_STATUS_WRITE_ERROR);
349
 
350
    return status;
351
}
352
 
353
struct png_write_closure_t {
354
    cairo_write_func_t           write_func;
355
    void                        *closure;
356
};
357
 
358
static void
359
stream_write_func (png_structp png, png_bytep data, png_size_t size)
360
{
361
    cairo_status_t status;
362
    struct png_write_closure_t *png_closure;
363
 
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);
371
    }
372
}
373
 
374
/**
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
379
 *
380
 * Writes the image surface to the write function.
381
 *
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.
387
 **/
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)
392
{
393
    struct png_write_closure_t png_closure;
394
 
395
    if (surface->status)
396
        return surface->status;
397
 
398
    if (surface->finished)
399
        return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED);
400
 
401
    png_closure.write_func = write_func;
402
    png_closure.closure = closure;
403
 
404
    return write_png (surface, stream_write_func, &png_closure);
405
}
406
slim_hidden_def (cairo_surface_write_to_png_stream);
407
 
408
static inline int
409
multiply_alpha (int alpha, int color)
410
{
411
    int temp = (alpha * color) + 0x80;
412
    return ((temp + (temp >> 8)) >> 8);
413
}
414
 
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)
420
{
421
    unsigned int i;
422
 
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;
427
 
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];
434
 
435
            if (alpha != 0xff) {
436
                red   = multiply_alpha (alpha, red);
437
                green = multiply_alpha (alpha, green);
438
                blue  = multiply_alpha (alpha, blue);
439
            }
440
            p = (alpha << 24) | (red << 16) | (green << 8) | (blue << 0);
441
        }
442
        memcpy (base, &p, sizeof (uint32_t));
443
    }
444
}
445
 
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)
449
{
450
    unsigned int i;
451
 
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;
458
 
459
        pixel = (0xff << 24) | (red << 16) | (green << 8) | (blue << 0);
460
        memcpy (base, &pixel, sizeof (uint32_t));
461
    }
462
}
463
 
464
static cairo_status_t
465
stdio_read_func (void *closure, unsigned char *data, unsigned int size)
466
{
467
    FILE *file = closure;
468
 
469
    while (size) {
470
        size_t ret;
471
 
472
        ret = fread (data, 1, size, file);
473
        size -= ret;
474
        data += ret;
475
 
476
        if (size && (feof (file) || ferror (file)))
477
            return _cairo_error (CAIRO_STATUS_READ_ERROR);
478
    }
479
 
480
    return CAIRO_STATUS_SUCCESS;
481
}
482
 
483
static void
484
stream_read_func (png_structp png, png_bytep data, png_size_t size)
485
{
486
    cairo_status_t status;
487
    struct png_read_closure_t *png_closure;
488
 
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);
496
    }
497
 
498
    _cairo_output_stream_write (png_closure->png_data, data, size);
499
}
500
 
501
static cairo_surface_t *
502
read_png (struct png_read_closure_t *png_closure)
503
{
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;
516
 
517
    png_closure->png_data = _cairo_memory_stream_create ();
518
 
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;
527
    }
528
 
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;
533
    }
534
 
535
    png_set_read_fn (png, png_closure, stream_read_func);
536
 
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;
542
    }
543
#endif
544
 
545
    png_read_info (png, info);
546
 
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;
553
    }
554
 
555
    /* convert palette/gray image to rgb */
556
    if (color_type == PNG_COLOR_TYPE_PALETTE)
557
        png_set_palette_to_rgb (png);
558
 
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
566
    }
567
 
568
    /* transform transparency to alpha */
569
    if (png_get_valid (png, info, PNG_INFO_tRNS))
570
        png_set_tRNS_to_alpha (png);
571
 
572
    if (depth == 16)
573
        png_set_strip_16 (png);
574
 
575
    if (depth < 8)
576
        png_set_packing (png);
577
 
578
    /* convert grayscale to RGB */
579
    if (color_type == PNG_COLOR_TYPE_GRAY ||
580
        color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
581
    {
582
        png_set_gray_to_rgb (png);
583
    }
584
 
585
    if (interlace != PNG_INTERLACE_NONE)
586
        png_set_interlace_handling (png);
587
 
588
    png_set_filler (png, 0xff, PNG_FILLER_AFTER);
589
 
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))
598
    {
599
        surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_READ_ERROR));
600
        goto BAIL;
601
    }
602
 
603
    switch (color_type) {
604
        default:
605
            ASSERT_NOT_REACHED;
606
            /* fall-through just in case ;-) */
607
 
608
        case PNG_COLOR_TYPE_RGB_ALPHA:
609
            format = CAIRO_FORMAT_ARGB32;
610
            png_set_read_user_transform_fn (png, premultiply_data);
611
            break;
612
 
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;
617
    }
618
 
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;
623
    }
624
 
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;
629
    }
630
 
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;
635
    }
636
 
637
    for (i = 0; i < png_height; i++)
638
        row_pointers[i] = &data[i * stride];
639
 
640
    png_read_image (png, row_pointers);
641
    png_read_end (png, info);
642
 
643
    if (unlikely (status)) { /* catch any late warnings - probably hit an error already */
644
        surface = _cairo_surface_create_in_error (status);
645
        goto BAIL;
646
    }
647
 
648
    surface = cairo_image_surface_create_for_data (data, format,
649
                                                   png_width, png_height,
650
                                                   stride);
651
    if (surface->status)
652
        goto BAIL;
653
 
654
    _cairo_image_surface_assume_ownership_of_data ((cairo_image_surface_t*)surface);
655
    data = NULL;
656
 
657
    _cairo_debug_check_image_surface_is_defined (surface);
658
 
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;
667
    }
668
 
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;
680
    }
681
 
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;
691
 
692
        status_ignored = _cairo_output_stream_destroy (png_closure->png_data);
693
    }
694
 
695
    return surface;
696
}
697
 
698
/**
699
 * cairo_image_surface_create_from_png:
700
 * @filename: name of PNG file to load
701
 *
702
 * Creates a new image surface and initializes the contents to the
703
 * given PNG file.
704
 *
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:
709
 *
710
 *      %CAIRO_STATUS_NO_MEMORY
711
 *      %CAIRO_STATUS_FILE_NOT_FOUND
712
 *      %CAIRO_STATUS_READ_ERROR
713
 *
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().
717
 **/
718
cairo_surface_t *
719
cairo_image_surface_create_from_png (const char *filename)
720
{
721
    struct png_read_closure_t png_closure;
722
    cairo_surface_t *surface;
723
 
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;
737
        }
738
        return _cairo_surface_create_in_error (status);
739
    }
740
 
741
    png_closure.read_func = stdio_read_func;
742
 
743
    surface = read_png (&png_closure);
744
 
745
    fclose (png_closure.closure);
746
 
747
    return surface;
748
}
749
 
750
/**
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.
754
 *
755
 * Creates a new image surface from PNG data read incrementally
756
 * via the @read_func function.
757
 *
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:
763
 *
764
 *      %CAIRO_STATUS_NO_MEMORY
765
 *      %CAIRO_STATUS_READ_ERROR
766
 *
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().
770
 **/
771
cairo_surface_t *
772
cairo_image_surface_create_from_png_stream (cairo_read_func_t   read_func,
773
                                            void                *closure)
774
{
775
    struct png_read_closure_t png_closure;
776
 
777
    png_closure.read_func = read_func;
778
    png_closure.closure = closure;
779
 
780
    return read_png (&png_closure);
781
}