Coverage Report

Created: 2025-11-16 09:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/workdir/UnpackedTarball/cairo/src/cairo-png.c
Line
Count
Source
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 <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
41
#include "cairo-error-private.h"
42
#include "cairo-image-surface-private.h"
43
#include "cairo-output-stream-private.h"
44
45
#include <stdio.h>
46
#include <errno.h>
47
#include <png.h>
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
0
{
88
0
    unsigned int i;
89
90
0
    for (i = 0; i < row_info->rowbytes; i += 4) {
91
0
        uint8_t *b = &data[i];
92
0
        uint32_t pixel;
93
0
        uint8_t  alpha;
94
95
0
  memcpy (&pixel, b, sizeof (uint32_t));
96
0
  alpha = (pixel & 0xff000000) >> 24;
97
0
        if (alpha == 0) {
98
0
      b[0] = b[1] = b[2] = b[3] = 0;
99
0
  } else {
100
0
            b[0] = (((pixel & 0xff0000) >> 16) * 255 + alpha / 2) / alpha;
101
0
            b[1] = (((pixel & 0x00ff00) >>  8) * 255 + alpha / 2) / alpha;
102
0
            b[2] = (((pixel & 0x0000ff) >>  0) * 255 + alpha / 2) / alpha;
103
0
      b[3] = alpha;
104
0
  }
105
0
    }
106
0
}
107
108
static uint16_t f_to_u16(float val)
109
0
{
110
0
    if (val < 0)
111
0
  return 0;
112
0
    else if (val > 1)
113
0
  return 65535;
114
0
    else
115
0
  return (uint16_t)(val * 65535.f);
116
0
}
117
118
static void
119
unpremultiply_float (float *f, uint16_t *d16, unsigned width)
120
0
{
121
0
    unsigned int i;
122
123
0
    for (i = 0; i < width; i++) {
124
0
  float r, g, b, a;
125
126
0
  r = *f++;
127
0
  g = *f++;
128
0
  b = *f++;
129
0
  a = *f++;
130
131
0
  if (a > 0) {
132
0
      *d16++ = f_to_u16(r / a);
133
0
      *d16++ = f_to_u16(g / a);
134
0
      *d16++ = f_to_u16(b / a);
135
0
      *d16++ = f_to_u16(a);
136
0
  } else {
137
0
      *d16++ = 0;
138
0
      *d16++ = 0;
139
0
      *d16++ = 0;
140
0
      *d16++ = 0;
141
0
  }
142
0
    }
143
0
}
144
145
static void
146
premultiply_float (float *f, const uint16_t *d16, unsigned int width)
147
0
{
148
0
    unsigned int i = width;
149
150
    /* Convert d16 in place back to float */
151
0
    while (i--) {
152
0
  float a = d16[i * 4 + 3] / 65535.f;
153
154
0
  f[i * 4 + 3] = a;
155
0
  f[i * 4 + 2] = (float)d16[i * 4 + 2] / 65535.f * a;
156
0
  f[i * 4 + 1] = (float)d16[i * 4 + 1] / 65535.f * a;
157
0
  f[i * 4] = (float)d16[i * 4] / 65535.f * a;
158
0
    }
159
0
}
160
161
static void convert_u16_to_float (float *f, const uint16_t *d16, unsigned int width)
162
0
{
163
    /* Convert d16 in place back to float */
164
0
    unsigned int i = width;
165
166
0
    while (i--) {
167
0
  f[i * 3 + 2] = (float)d16[i * 4 + 2] / 65535.f;
168
0
  f[i * 3 + 1] = (float)d16[i * 4 + 1] / 65535.f;
169
0
  f[i * 3] = (float)d16[i * 4] / 65535.f;
170
0
    }
171
0
}
172
173
static void
174
convert_float_to_u16 (float *f, uint16_t *d16, unsigned int width)
175
0
{
176
0
    unsigned int i;
177
178
0
    for (i = 0; i < width; i++) {
179
0
  *d16++ = f_to_u16(*f++);
180
0
  *d16++ = f_to_u16(*f++);
181
0
  *d16++ = f_to_u16(*f++);
182
0
  *d16++ = 0;
183
0
    }
184
0
}
185
186
/* Converts native endian xRGB => RGBx bytes */
187
static void
188
convert_data_to_bytes (png_structp png, png_row_infop row_info, png_bytep data)
189
0
{
190
0
    unsigned int i;
191
192
0
    for (i = 0; i < row_info->rowbytes; i += 4) {
193
0
        uint8_t *b = &data[i];
194
0
        uint32_t pixel;
195
196
0
  memcpy (&pixel, b, sizeof (uint32_t));
197
198
0
  b[0] = (pixel & 0xff0000) >> 16;
199
0
  b[1] = (pixel & 0x00ff00) >>  8;
200
0
  b[2] = (pixel & 0x0000ff) >>  0;
201
0
  b[3] = 0;
202
0
    }
203
0
}
204
205
/* Use a couple of simple error callbacks that do not print anything to
206
 * stderr and rely on the user to check for errors via the #cairo_status_t
207
 * return.
208
 */
209
static void
210
png_simple_error_callback (png_structp png,
211
                     png_const_charp error_msg)
212
0
{
213
0
    cairo_status_t *error = png_get_error_ptr (png);
214
215
    /* default to the most likely error */
216
0
    if (*error == CAIRO_STATUS_SUCCESS)
217
0
  *error = _cairo_error (CAIRO_STATUS_PNG_ERROR);
218
219
0
#ifdef PNG_SETJMP_SUPPORTED
220
0
    longjmp (png_jmpbuf (png), 1);
221
0
#endif
222
223
    /* if we get here, then we have to choice but to abort ... */
224
0
}
225
226
static void
227
png_simple_warning_callback (png_structp png,
228
                       png_const_charp error_msg)
229
0
{
230
    /* png does not expect to abort and will try to tidy up and continue
231
     * loading the image after a warning. So we also want to return the
232
     * (incorrect?) surface.
233
     *
234
     * We use our own warning callback to squelch any attempts by libpng
235
     * to write to stderr as we may not be in control of that output.
236
     */
237
0
}
238
239
240
/* Starting with libpng-1.2.30, we must explicitly specify an output_flush_fn.
241
 * Otherwise, we will segfault if we are writing to a stream. */
242
static void
243
png_simple_output_flush_fn (png_structp png_ptr)
244
0
{
245
0
}
246
247
static cairo_status_t
248
write_png (cairo_surface_t  *surface,
249
     png_rw_ptr   write_func,
250
     void     *closure)
251
0
{
252
0
    int i;
253
0
    cairo_int_status_t status;
254
0
    cairo_image_surface_t *image;
255
0
    cairo_image_surface_t * volatile clone;
256
0
    void *image_extra;
257
0
    png_struct *png;
258
0
    png_info *info;
259
0
    png_byte **volatile rows = NULL;
260
0
    png_color_16 white;
261
0
    int png_color_type;
262
0
    int bpc;
263
0
    unsigned char *volatile u16_copy = NULL;
264
265
0
    status = _cairo_surface_acquire_source_image (surface,
266
0
              &image,
267
0
              &image_extra);
268
269
0
    if (status == CAIRO_INT_STATUS_UNSUPPORTED)
270
0
  return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
271
0
    else if (unlikely (status))
272
0
        return status;
273
274
    /* PNG complains about "Image width or height is zero in IHDR" */
275
0
    if (image->width == 0 || image->height == 0) {
276
0
  status = _cairo_error (CAIRO_STATUS_WRITE_ERROR);
277
0
  goto BAIL1;
278
0
    }
279
280
    /* Don't coerce to a lower resolution format */
281
0
    if (image->format == CAIRO_FORMAT_RGB96F ||
282
0
        image->format == CAIRO_FORMAT_RGBA128F) {
283
0
  u16_copy = _cairo_malloc_ab (image->width * 8, image->height);
284
0
  if (!u16_copy) {
285
0
      status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
286
0
      goto BAIL1;
287
0
  }
288
0
  clone = (cairo_image_surface_t *)cairo_surface_reference (&image->base);
289
0
    } else {
290
    /* Handle the various fallback formats (e.g. low bit-depth XServers)
291
    * by coercing them to a simpler format using pixman.
292
    */
293
0
    clone = _cairo_image_surface_coerce (image);
294
0
    status = clone->base.status;
295
0
    }
296
0
    if (unlikely (status))
297
0
        goto BAIL1;
298
299
0
    rows = _cairo_malloc_ab (clone->height, sizeof (png_byte*));
300
0
    if (unlikely (rows == NULL)) {
301
0
  status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
302
0
  goto BAIL2;
303
0
    }
304
305
0
    if (!u16_copy) {
306
0
  for (i = 0; i < clone->height; i++)
307
0
      rows[i] = (png_byte *)clone->data + i * clone->stride;
308
0
    } else {
309
0
  for (i = 0; i < clone->height; i++) {
310
0
      float *float_line = (float *)&clone->data[i * clone->stride];
311
0
      uint16_t *u16_line = (uint16_t *)&u16_copy[i * clone->width * 8];
312
313
0
      if (image->format == CAIRO_FORMAT_RGBA128F)
314
0
    unpremultiply_float (float_line, u16_line, clone->width);
315
0
      else
316
0
    convert_float_to_u16 (float_line, u16_line, clone->width);
317
318
0
      rows[i] = (png_byte *)u16_line;
319
0
  }
320
0
    }
321
322
0
    png = png_create_write_struct (PNG_LIBPNG_VER_STRING, &status,
323
0
                             png_simple_error_callback,
324
0
                             png_simple_warning_callback);
325
0
    if (unlikely (png == NULL)) {
326
0
  status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
327
0
  goto BAIL3;
328
0
    }
329
330
0
    info = png_create_info_struct (png);
331
0
    if (unlikely (info == NULL)) {
332
0
  status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
333
0
  goto BAIL4;
334
0
    }
335
336
0
#ifdef PNG_SETJMP_SUPPORTED
337
0
    if (setjmp (png_jmpbuf (png)))
338
0
  goto BAIL4;
339
0
#endif
340
341
0
    png_set_write_fn (png, closure, write_func, png_simple_output_flush_fn);
342
343
0
    switch (clone->format) {
344
0
    case CAIRO_FORMAT_ARGB32:
345
0
  bpc = 8;
346
0
  if (_cairo_image_analyze_transparency (clone) == CAIRO_IMAGE_IS_OPAQUE)
347
0
      png_color_type = PNG_COLOR_TYPE_RGB;
348
0
  else
349
0
      png_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
350
0
  break;
351
0
    case CAIRO_FORMAT_RGB30:
352
0
  bpc = 10;
353
0
  png_color_type = PNG_COLOR_TYPE_RGB;
354
0
  break;
355
0
    case CAIRO_FORMAT_RGB24:
356
0
  bpc = 8;
357
0
  png_color_type = PNG_COLOR_TYPE_RGB;
358
0
  break;
359
0
    case CAIRO_FORMAT_A8:
360
0
  bpc = 8;
361
0
  png_color_type = PNG_COLOR_TYPE_GRAY;
362
0
  break;
363
0
    case CAIRO_FORMAT_A1:
364
0
  bpc = 1;
365
0
  png_color_type = PNG_COLOR_TYPE_GRAY;
366
0
#ifndef WORDS_BIGENDIAN
367
0
  png_set_packswap (png);
368
0
#endif
369
0
  break;
370
0
    case CAIRO_FORMAT_RGB96F:
371
0
  bpc = 16;
372
0
  png_color_type = PNG_COLOR_TYPE_RGB;
373
0
  break;
374
0
    case CAIRO_FORMAT_RGBA128F:
375
0
  bpc = 16;
376
0
  png_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
377
0
  break;
378
0
    case CAIRO_FORMAT_INVALID:
379
0
    case CAIRO_FORMAT_RGB16_565:
380
0
    default:
381
0
  status = _cairo_error (CAIRO_STATUS_INVALID_FORMAT);
382
0
  goto BAIL4;
383
0
    }
384
385
0
    png_set_IHDR (png, info,
386
0
      clone->width,
387
0
      clone->height, bpc,
388
0
      png_color_type,
389
0
      PNG_INTERLACE_NONE,
390
0
      PNG_COMPRESSION_TYPE_DEFAULT,
391
0
      PNG_FILTER_TYPE_DEFAULT);
392
393
0
    white.gray = (1 << bpc) - 1;
394
0
    white.red = white.blue = white.green = white.gray;
395
0
    png_set_bKGD (png, info, &white);
396
397
0
    if (0) { /* XXX extract meta-data from surface (i.e. creation date) */
398
0
  png_time pt;
399
400
0
  png_convert_from_time_t (&pt, time (NULL));
401
0
  png_set_tIME (png, info, &pt);
402
0
    }
403
404
    /* We have to call png_write_info() before setting up the write
405
     * transformation, since it stores data internally in 'png'
406
     * that is needed for the write transformation functions to work.
407
     */
408
0
    png_write_info (png, info);
409
410
0
#ifndef WORDS_BIGENDIAN
411
    /* libpng treats 16-bit data as big-endian by default. Swapping the
412
     * byte-order on little endian ensures the native-endian data can be
413
     * provided to png_write_image. This does not affect 8-bit data.
414
     */
415
0
    png_set_swap (png);
416
0
#endif
417
418
0
    if (png_color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
419
0
  if (clone->format != CAIRO_FORMAT_RGBA128F)
420
0
      png_set_write_user_transform_fn (png, unpremultiply_data);
421
0
    } else if (png_color_type == PNG_COLOR_TYPE_RGB) {
422
0
  if (clone->format != CAIRO_FORMAT_RGB96F)
423
0
      png_set_write_user_transform_fn (png, convert_data_to_bytes);
424
0
  png_set_filler (png, 0, PNG_FILLER_AFTER);
425
0
    }
426
427
0
    png_write_image (png, rows);
428
0
    png_write_end (png, info);
429
430
0
BAIL4:
431
0
    png_destroy_write_struct (&png, &info);
432
0
BAIL3:
433
0
    free (rows);
434
0
BAIL2:
435
0
    cairo_surface_destroy (&clone->base);
436
0
    free (u16_copy);
437
0
BAIL1:
438
0
    _cairo_surface_release_source_image (surface, image, image_extra);
439
440
0
    return status;
441
0
}
442
443
static void
444
stdio_write_func (png_structp png, png_bytep data, png_size_t size)
445
0
{
446
0
    FILE *fp;
447
448
0
    fp = png_get_io_ptr (png);
449
0
    while (size) {
450
0
  size_t ret = fwrite (data, 1, size, fp);
451
0
  size -= ret;
452
0
  data += ret;
453
0
  if (size && ferror (fp)) {
454
0
      cairo_status_t *error = png_get_error_ptr (png);
455
0
      if (*error == CAIRO_STATUS_SUCCESS)
456
0
    *error = _cairo_error (CAIRO_STATUS_WRITE_ERROR);
457
0
      png_error (png, NULL);
458
0
  }
459
0
    }
460
0
}
461
462
/**
463
 * cairo_surface_write_to_png:
464
 * @surface: a #cairo_surface_t with pixel contents
465
 * @filename: the name of a file to write to; on Windows this filename
466
 *   is encoded in UTF-8.
467
 *
468
 * Writes the contents of @surface to a new file @filename as a PNG
469
 * image.
470
 *
471
 * Return value: %CAIRO_STATUS_SUCCESS if the PNG file was written
472
 * successfully. Otherwise, %CAIRO_STATUS_NO_MEMORY if memory could not
473
 * be allocated for the operation or
474
 * %CAIRO_STATUS_SURFACE_TYPE_MISMATCH if the surface does not have
475
 * pixel contents, or %CAIRO_STATUS_WRITE_ERROR if an I/O error occurs
476
 * while attempting to write the file, or %CAIRO_STATUS_PNG_ERROR if libpng
477
 * returned an error.
478
 *
479
 * Since: 1.0
480
 **/
481
cairo_status_t
482
cairo_surface_write_to_png (cairo_surface_t *surface,
483
          const char    *filename)
484
0
{
485
0
    FILE *fp;
486
0
    cairo_status_t status;
487
488
0
    if (surface->status)
489
0
  return surface->status;
490
491
0
    if (surface->finished)
492
0
  return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED);
493
494
0
    status = _cairo_fopen (filename, "wb", &fp);
495
496
0
    if (status != CAIRO_STATUS_SUCCESS)
497
0
  return _cairo_error (status);
498
499
0
    if (fp == NULL) {
500
0
  switch (errno) {
501
0
  case ENOMEM:
502
0
      return _cairo_error (CAIRO_STATUS_NO_MEMORY);
503
0
  default:
504
0
      return _cairo_error (CAIRO_STATUS_WRITE_ERROR);
505
0
  }
506
0
    }
507
508
0
    status = write_png (surface, stdio_write_func, fp);
509
510
0
    if (fclose (fp) && status == CAIRO_STATUS_SUCCESS)
511
0
  status = _cairo_error (CAIRO_STATUS_WRITE_ERROR);
512
513
0
    return status;
514
0
}
515
516
struct png_write_closure_t {
517
    cairo_write_func_t     write_func;
518
    void      *closure;
519
};
520
521
static void
522
stream_write_func (png_structp png, png_bytep data, png_size_t size)
523
0
{
524
0
    cairo_status_t status;
525
0
    struct png_write_closure_t *png_closure;
526
527
0
    png_closure = png_get_io_ptr (png);
528
0
    status = png_closure->write_func (png_closure->closure, data, size);
529
0
    if (unlikely (status)) {
530
0
  cairo_status_t *error = png_get_error_ptr (png);
531
0
  if (*error == CAIRO_STATUS_SUCCESS)
532
0
      *error = status;
533
0
  png_error (png, NULL);
534
0
    }
535
0
}
536
537
/**
538
 * cairo_surface_write_to_png_stream:
539
 * @surface: a #cairo_surface_t with pixel contents
540
 * @write_func: a #cairo_write_func_t
541
 * @closure: closure data for the write function
542
 *
543
 * Writes the image surface to the write function.
544
 *
545
 * Return value: %CAIRO_STATUS_SUCCESS if the PNG file was written
546
 * successfully.  Otherwise, %CAIRO_STATUS_NO_MEMORY is returned if
547
 * memory could not be allocated for the operation,
548
 * %CAIRO_STATUS_SURFACE_TYPE_MISMATCH if the surface does not have
549
 * pixel contents, or %CAIRO_STATUS_PNG_ERROR if libpng
550
 * returned an error.
551
 *
552
 * Since: 1.0
553
 **/
554
cairo_status_t
555
cairo_surface_write_to_png_stream (cairo_surface_t  *surface,
556
           cairo_write_func_t write_func,
557
           void     *closure)
558
0
{
559
0
    struct png_write_closure_t png_closure;
560
561
0
    if (surface->status)
562
0
  return surface->status;
563
564
0
    if (surface->finished)
565
0
  return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED);
566
567
0
    png_closure.write_func = write_func;
568
0
    png_closure.closure = closure;
569
570
0
    return write_png (surface, stream_write_func, &png_closure);
571
0
}
572
573
static inline int
574
multiply_alpha (int alpha, int color)
575
0
{
576
0
    int temp = (alpha * color) + 0x80;
577
0
    return ((temp + (temp >> 8)) >> 8);
578
0
}
579
580
/* Premultiplies data and converts RGBA bytes => native endian */
581
static void
582
premultiply_data (png_structp   png,
583
                  png_row_infop row_info,
584
                  png_bytep     data)
585
0
{
586
0
    unsigned int i;
587
588
0
    for (i = 0; i < row_info->rowbytes; i += 4) {
589
0
  uint8_t *base  = &data[i];
590
0
  uint8_t  alpha = base[3];
591
0
  uint32_t p;
592
593
0
  if (alpha == 0) {
594
0
      p = 0;
595
0
  } else {
596
0
      uint8_t  red   = base[0];
597
0
      uint8_t  green = base[1];
598
0
      uint8_t  blue  = base[2];
599
600
0
      if (alpha != 0xff) {
601
0
    red   = multiply_alpha (alpha, red);
602
0
    green = multiply_alpha (alpha, green);
603
0
    blue  = multiply_alpha (alpha, blue);
604
0
      }
605
0
      p = ((uint32_t)alpha << 24) | (red << 16) | (green << 8) | (blue << 0);
606
0
  }
607
0
  memcpy (base, &p, sizeof (uint32_t));
608
0
    }
609
0
}
610
611
/* Converts RGBx bytes to native endian xRGB */
612
static void
613
convert_bytes_to_data (png_structp png, png_row_infop row_info, png_bytep data)
614
0
{
615
0
    unsigned int i;
616
617
0
    for (i = 0; i < row_info->rowbytes; i += 4) {
618
0
  uint8_t *base  = &data[i];
619
0
  uint8_t  red   = base[0];
620
0
  uint8_t  green = base[1];
621
0
  uint8_t  blue  = base[2];
622
0
  uint32_t pixel;
623
624
0
  pixel = (0xffu << 24) | (red << 16) | (green << 8) | (blue << 0);
625
0
  memcpy (base, &pixel, sizeof (uint32_t));
626
0
    }
627
0
}
628
629
static cairo_status_t
630
stdio_read_func (void *closure, unsigned char *data, unsigned int size)
631
0
{
632
0
    FILE *file = closure;
633
634
0
    while (size) {
635
0
  size_t ret;
636
637
0
  ret = fread (data, 1, size, file);
638
0
  size -= ret;
639
0
  data += ret;
640
641
0
  if (size && (feof (file) || ferror (file)))
642
0
      return _cairo_error (CAIRO_STATUS_READ_ERROR);
643
0
    }
644
645
0
    return CAIRO_STATUS_SUCCESS;
646
0
}
647
648
static void
649
stream_read_func (png_structp png, png_bytep data, png_size_t size)
650
0
{
651
0
    cairo_status_t status;
652
0
    struct png_read_closure_t *png_closure;
653
654
0
    png_closure = png_get_io_ptr (png);
655
0
    status = png_closure->read_func (png_closure->closure, data, size);
656
0
    if (unlikely (status)) {
657
0
  cairo_status_t *error = png_get_error_ptr (png);
658
0
  if (*error == CAIRO_STATUS_SUCCESS)
659
0
      *error = status;
660
0
  png_error (png, NULL);
661
0
    }
662
663
0
    _cairo_output_stream_write (png_closure->png_data, data, size);
664
0
}
665
666
static cairo_surface_t *
667
read_png (struct png_read_closure_t *png_closure)
668
0
{
669
0
    cairo_surface_t * volatile surface;
670
0
    png_struct *png = NULL;
671
0
    png_info *info;
672
0
    png_byte * volatile data = NULL;
673
0
    png_byte ** volatile row_pointers = NULL;
674
0
    png_uint_32 png_width, png_height;
675
0
    int depth, color_type, interlace, stride;
676
0
    unsigned int i;
677
0
    cairo_format_t format;
678
0
    cairo_status_t status;
679
0
    unsigned char *mime_data;
680
0
    unsigned long mime_data_length;
681
682
0
    png_closure->png_data = _cairo_memory_stream_create ();
683
684
    /* XXX: Perhaps we'll want some other error handlers? */
685
0
    png = png_create_read_struct (PNG_LIBPNG_VER_STRING,
686
0
                                  &status,
687
0
                            png_simple_error_callback,
688
0
                            png_simple_warning_callback);
689
0
    if (unlikely (png == NULL)) {
690
0
  surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
691
0
  goto BAIL;
692
0
    }
693
694
0
    info = png_create_info_struct (png);
695
0
    if (unlikely (info == NULL)) {
696
0
  surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
697
0
  goto BAIL;
698
0
    }
699
700
0
    png_set_read_fn (png, png_closure, stream_read_func);
701
702
0
    status = CAIRO_STATUS_SUCCESS;
703
0
#ifdef PNG_SETJMP_SUPPORTED
704
0
    if (setjmp (png_jmpbuf (png))) {
705
0
  surface = _cairo_surface_create_in_error (status);
706
0
  goto BAIL;
707
0
    }
708
0
#endif
709
710
0
    png_read_info (png, info);
711
712
0
#ifndef WORDS_BIGENDIAN
713
    /* libpng treats 16-bit data as big-endian by default. Swapping the
714
     * byte-order on little endian ensures the native-endian data can be
715
     * provided to png_read_image. This does not affect 8-bit data.
716
     */
717
0
    png_set_swap (png);
718
0
#endif
719
720
0
    png_get_IHDR (png, info,
721
0
                  &png_width, &png_height, &depth,
722
0
                  &color_type, &interlace, NULL, NULL);
723
0
    if (unlikely (status)) { /* catch any early warnings */
724
0
  surface = _cairo_surface_create_in_error (status);
725
0
  goto BAIL;
726
0
    }
727
728
    /* convert palette/gray image to rgb */
729
0
    if (color_type == PNG_COLOR_TYPE_PALETTE)
730
0
        png_set_palette_to_rgb (png);
731
732
    /* expand gray bit depth if needed */
733
0
    if (color_type == PNG_COLOR_TYPE_GRAY)
734
0
        png_set_expand_gray_1_2_4_to_8 (png);
735
736
    /* transform transparency to alpha */
737
0
    if (png_get_valid (png, info, PNG_INFO_tRNS))
738
0
        png_set_tRNS_to_alpha (png);
739
740
0
    if (depth < 8)
741
0
        png_set_packing (png);
742
743
    /* convert grayscale to RGB */
744
0
    if (color_type == PNG_COLOR_TYPE_GRAY ||
745
0
  color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
746
0
    {
747
0
  png_set_gray_to_rgb (png);
748
0
    }
749
750
0
    if (interlace != PNG_INTERLACE_NONE)
751
0
        png_set_interlace_handling (png);
752
753
0
    png_set_filler (png, 0xff, PNG_FILLER_AFTER);
754
755
    /* recheck header after setting EXPAND options */
756
0
    png_read_update_info (png, info);
757
0
    png_get_IHDR (png, info,
758
0
                  &png_width, &png_height, &depth,
759
0
                  &color_type, &interlace, NULL, NULL);
760
0
    if ((depth != 8 && depth != 16) ||
761
0
  ! (color_type == PNG_COLOR_TYPE_RGB ||
762
0
     color_type == PNG_COLOR_TYPE_RGB_ALPHA))
763
0
    {
764
0
  surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_READ_ERROR));
765
0
  goto BAIL;
766
0
    }
767
768
0
    switch (color_type) {
769
0
  default:
770
0
      ASSERT_NOT_REACHED;
771
      /* fall-through just in case ;-) */
772
773
0
  case PNG_COLOR_TYPE_RGB_ALPHA:
774
0
      if (depth == 8) {
775
0
    format = CAIRO_FORMAT_ARGB32;
776
0
    png_set_read_user_transform_fn (png, premultiply_data);
777
0
      } else {
778
0
    format = CAIRO_FORMAT_RGBA128F;
779
0
      }
780
0
      break;
781
782
0
  case PNG_COLOR_TYPE_RGB:
783
0
      if (depth == 8) {
784
0
    format = CAIRO_FORMAT_RGB24;
785
0
    png_set_read_user_transform_fn (png, convert_bytes_to_data);
786
0
      } else {
787
0
    format = CAIRO_FORMAT_RGB96F;
788
0
      }
789
0
      break;
790
0
    }
791
792
0
    stride = cairo_format_stride_for_width (format, png_width);
793
0
    if (stride < 0) {
794
0
  surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_STRIDE));
795
0
  goto BAIL;
796
0
    }
797
798
0
    data = _cairo_malloc_ab (png_height, stride);
799
0
    if (unlikely (data == NULL)) {
800
0
  surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
801
0
  goto BAIL;
802
0
    }
803
804
0
    row_pointers = _cairo_malloc_ab (png_height, sizeof (char *));
805
0
    if (unlikely (row_pointers == NULL)) {
806
0
  surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
807
0
  goto BAIL;
808
0
    }
809
810
0
    for (i = 0; i < png_height; i++)
811
0
        row_pointers[i] = &data[i * (ptrdiff_t)stride];
812
813
0
    png_read_image (png, row_pointers);
814
0
    png_read_end (png, info);
815
816
0
    if (unlikely (status)) { /* catch any late warnings - probably hit an error already */
817
0
  surface = _cairo_surface_create_in_error (status);
818
0
  goto BAIL;
819
0
    }
820
821
0
    if (format == CAIRO_FORMAT_RGBA128F) {
822
0
  i = png_height;
823
824
0
  while (i--) {
825
0
      float *float_line = (float *)row_pointers[i];
826
0
      uint16_t *u16_line = (uint16_t *)row_pointers[i];
827
828
0
      premultiply_float (float_line, u16_line, png_width);
829
0
  }
830
0
    } else if (format == CAIRO_FORMAT_RGB96F) {
831
0
  i = png_height;
832
833
0
  while (i--) {
834
0
      float *float_line = (float *)row_pointers[i];
835
0
      uint16_t *u16_line = (uint16_t *)row_pointers[i];
836
837
0
      convert_u16_to_float (float_line, u16_line, png_width);
838
0
  }
839
0
    }
840
841
0
    surface = cairo_image_surface_create_for_data (data, format,
842
0
               png_width, png_height,
843
0
               stride);
844
0
    if (surface->status)
845
0
  goto BAIL;
846
847
0
    _cairo_image_surface_assume_ownership_of_data ((cairo_image_surface_t*)surface);
848
0
    data = NULL;
849
850
0
    _cairo_debug_check_image_surface_is_defined (surface);
851
852
0
    status = _cairo_memory_stream_destroy (png_closure->png_data,
853
0
             &mime_data,
854
0
             &mime_data_length);
855
0
    png_closure->png_data = NULL;
856
0
    if (unlikely (status)) {
857
0
  cairo_surface_destroy (surface);
858
0
  surface = _cairo_surface_create_in_error (status);
859
0
  goto BAIL;
860
0
    }
861
862
0
    status = cairo_surface_set_mime_data (surface,
863
0
            CAIRO_MIME_TYPE_PNG,
864
0
            mime_data,
865
0
            mime_data_length,
866
0
            free,
867
0
            mime_data);
868
0
    if (unlikely (status)) {
869
0
  free (mime_data);
870
0
  cairo_surface_destroy (surface);
871
0
  surface = _cairo_surface_create_in_error (status);
872
0
  goto BAIL;
873
0
    }
874
875
0
 BAIL:
876
0
    free (row_pointers);
877
0
    free (data);
878
0
    if (png != NULL)
879
0
  png_destroy_read_struct (&png, &info, NULL);
880
0
    if (png_closure->png_data != NULL) {
881
0
  cairo_status_t status_ignored;
882
883
0
  status_ignored = _cairo_output_stream_destroy (png_closure->png_data);
884
0
    }
885
886
0
    return surface;
887
0
}
888
889
/**
890
 * cairo_image_surface_create_from_png:
891
 * @filename: name of PNG file to load. On Windows this filename
892
 *   is encoded in UTF-8.
893
 *
894
 * Creates a new image surface and initializes the contents to the
895
 * given PNG file.
896
 *
897
 * Return value: a new #cairo_surface_t initialized with the contents
898
 * of the PNG file, or a "nil" surface if any error occurred. A nil
899
 * surface can be checked for with cairo_surface_status(surface) which
900
 * may return one of the following values:
901
 *
902
 *  %CAIRO_STATUS_NO_MEMORY
903
 *  %CAIRO_STATUS_FILE_NOT_FOUND
904
 *  %CAIRO_STATUS_READ_ERROR
905
 *  %CAIRO_STATUS_PNG_ERROR
906
 *
907
 * Alternatively, you can allow errors to propagate through the drawing
908
 * operations and check the status on the context upon completion
909
 * using cairo_status().
910
 *
911
 * Since: 1.0
912
 **/
913
cairo_surface_t *
914
cairo_image_surface_create_from_png (const char *filename)
915
0
{
916
0
    struct png_read_closure_t png_closure;
917
0
    cairo_surface_t *surface;
918
0
    cairo_status_t status;
919
920
0
    status = _cairo_fopen (filename, "rb", (FILE **) &png_closure.closure);
921
922
0
    if (status != CAIRO_STATUS_SUCCESS)
923
0
  return _cairo_surface_create_in_error (status);
924
925
0
    if (png_closure.closure == NULL) {
926
0
  switch (errno) {
927
0
  case ENOMEM:
928
0
      status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
929
0
      break;
930
0
  case ENOENT:
931
0
      status = _cairo_error (CAIRO_STATUS_FILE_NOT_FOUND);
932
0
      break;
933
0
  default:
934
0
      status = _cairo_error (CAIRO_STATUS_READ_ERROR);
935
0
      break;
936
0
  }
937
0
  return _cairo_surface_create_in_error (status);
938
0
    }
939
940
0
    png_closure.read_func = stdio_read_func;
941
942
0
    surface = read_png (&png_closure);
943
944
0
    fclose (png_closure.closure);
945
946
0
    return surface;
947
0
}
948
949
/**
950
 * cairo_image_surface_create_from_png_stream:
951
 * @read_func: function called to read the data of the file
952
 * @closure: data to pass to @read_func.
953
 *
954
 * Creates a new image surface from PNG data read incrementally
955
 * via the @read_func function.
956
 *
957
 * Return value: a new #cairo_surface_t initialized with the contents
958
 * of the PNG file or a "nil" surface if the data read is not a valid PNG image
959
 * or memory could not be allocated for the operation.  A nil
960
 * surface can be checked for with cairo_surface_status(surface) which
961
 * may return one of the following values:
962
 *
963
 *  %CAIRO_STATUS_NO_MEMORY
964
 *  %CAIRO_STATUS_READ_ERROR
965
 *  %CAIRO_STATUS_PNG_ERROR
966
 *
967
 * Alternatively, you can allow errors to propagate through the drawing
968
 * operations and check the status on the context upon completion
969
 * using cairo_status().
970
 *
971
 * Since: 1.0
972
 **/
973
cairo_surface_t *
974
cairo_image_surface_create_from_png_stream (cairo_read_func_t read_func,
975
              void    *closure)
976
0
{
977
0
    struct png_read_closure_t png_closure;
978
979
0
    png_closure.read_func = read_func;
980
0
    png_closure.closure = closure;
981
982
0
    return read_png (&png_closure);
983
0
}