5
static const cairo_surface_backend_t cairo_png_surface_backend;
7
static cairo_int_status_t
8
_cairo_png_surface_copy_page (void *abstract_surface);
11
cairo_set_target_png (cairo_t *cr,
13
cairo_format_t format,
17
cairo_surface_t *surface;
19
surface = cairo_png_surface_create (file, format,
22
if (surface == NULL) {
23
cr->status = CAIRO_STATUS_NO_MEMORY;
27
cairo_set_target_surface (cr, surface);
29
/* cairo_set_target_surface takes a reference, so we must destroy ours */
30
cairo_surface_destroy (surface);
33
typedef struct cairo_png_surface {
36
/* PNG-specific fields */
37
cairo_image_surface_t *image;
41
cairo_format_t format;
43
} cairo_png_surface_t;
47
_cairo_png_surface_erase (cairo_png_surface_t *surface);
50
cairo_png_surface_create (FILE *file,
51
cairo_format_t format,
55
cairo_png_surface_t *surface;
57
surface = malloc (sizeof (cairo_png_surface_t));
61
_cairo_surface_init (&surface->base, &cairo_png_surface_backend);
63
surface->image = (cairo_image_surface_t *)
64
cairo_image_surface_create (format, width, height);
66
if (surface->image == NULL) {
71
_cairo_png_surface_erase (surface);
76
surface->format = format;
78
return &surface->base;
82
static cairo_surface_t *
83
_cairo_png_surface_create_similar (void *abstract_src,
84
cairo_format_t format,
92
unpremultiply_data (png_structp png, png_row_infop row_info, png_bytep data)
96
for (i = 0; i < row_info->rowbytes; i += 4) {
97
unsigned char *b = &data[i];
101
memcpy (&pixel, b, sizeof (unsigned int));
102
alpha = (pixel & 0xff000000) >> 24;
104
b[0] = b[1] = b[2] = b[3] = 0;
106
b[0] = (((pixel & 0x0000ff) >> 0) * 255) / alpha;
107
b[1] = (((pixel & 0x00ff00) >> 8) * 255) / alpha;
108
b[2] = (((pixel & 0xff0000) >> 16) * 255) / alpha;
115
_cairo_png_surface_destroy (void *abstract_surface)
117
cairo_png_surface_t *surface = abstract_surface;
119
if (! surface->copied)
120
_cairo_png_surface_copy_page (surface);
122
cairo_surface_destroy (&surface->image->base);
128
_cairo_png_surface_erase (cairo_png_surface_t *surface)
130
cairo_color_t transparent;
132
_cairo_color_init (&transparent);
133
_cairo_color_set_rgb (&transparent, 0., 0., 0.);
134
_cairo_color_set_alpha (&transparent, 0.);
135
_cairo_surface_fill_rectangle (&surface->image->base,
139
surface->image->width,
140
surface->image->height);
144
_cairo_png_surface_pixels_per_inch (void *abstract_surface)
149
static cairo_image_surface_t *
150
_cairo_png_surface_get_image (void *abstract_surface)
152
cairo_png_surface_t *surface = abstract_surface;
154
cairo_surface_reference (&surface->image->base);
156
return surface->image;
159
static cairo_status_t
160
_cairo_png_surface_set_image (void *abstract_surface,
161
cairo_image_surface_t *image)
163
cairo_png_surface_t *surface = abstract_surface;
165
if (image == surface->image)
166
return CAIRO_STATUS_SUCCESS;
168
/* XXX: Need to call _cairo_image_surface_set_image here, but it's
169
not implemented yet. */
171
return CAIRO_INT_STATUS_UNSUPPORTED;
174
static cairo_status_t
175
_cairo_png_surface_set_matrix (void *abstract_surface,
176
cairo_matrix_t *matrix)
178
cairo_png_surface_t *surface = abstract_surface;
180
return _cairo_image_surface_set_matrix (surface->image, matrix);
183
static cairo_status_t
184
_cairo_png_surface_set_filter (void *abstract_surface,
185
cairo_filter_t filter)
187
cairo_png_surface_t *surface = abstract_surface;
189
return _cairo_image_surface_set_filter (surface->image, filter);
192
static cairo_status_t
193
_cairo_png_surface_set_repeat (void *abstract_surface,
196
cairo_png_surface_t *surface = abstract_surface;
198
return _cairo_image_surface_set_repeat (surface->image, repeat);
201
static cairo_int_status_t
202
_cairo_png_surface_composite (cairo_operator_t operator,
203
cairo_surface_t *generic_src,
204
cairo_surface_t *generic_mask,
215
return CAIRO_INT_STATUS_UNSUPPORTED;
218
static cairo_int_status_t
219
_cairo_png_surface_fill_rectangles (void *abstract_surface,
220
cairo_operator_t operator,
221
const cairo_color_t *color,
222
cairo_rectangle_t *rects,
225
return CAIRO_INT_STATUS_UNSUPPORTED;
228
static cairo_int_status_t
229
_cairo_png_surface_composite_trapezoids (cairo_operator_t operator,
230
cairo_surface_t *generic_src,
234
cairo_trapezoid_t *traps,
237
return CAIRO_INT_STATUS_UNSUPPORTED;
240
static cairo_int_status_t
241
_cairo_png_surface_copy_page (void *abstract_surface)
244
cairo_status_t status = CAIRO_STATUS_SUCCESS;
245
cairo_png_surface_t *surface = abstract_surface;
253
rows = malloc (surface->image->height * sizeof(png_byte*));
255
return CAIRO_STATUS_NO_MEMORY;
257
for (i = 0; i < surface->image->height; i++)
258
rows[i] = surface->image->data + i * surface->image->stride;
260
png = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
262
return CAIRO_STATUS_NO_MEMORY;
264
info = png_create_info_struct (png);
266
png_destroy_write_struct (&png, NULL);
267
return CAIRO_STATUS_NO_MEMORY;
270
if (setjmp (png_jmpbuf (png))) {
271
status = CAIRO_STATUS_NO_MEMORY;
275
png_init_io (png, surface->file);
277
switch (surface->format) {
278
case CAIRO_FORMAT_ARGB32:
280
png_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
282
case CAIRO_FORMAT_RGB24:
284
png_color_type = PNG_COLOR_TYPE_RGB;
286
case CAIRO_FORMAT_A8:
288
png_color_type = PNG_COLOR_TYPE_GRAY;
290
case CAIRO_FORMAT_A1:
292
png_color_type = PNG_COLOR_TYPE_GRAY;
296
png_set_IHDR (png, info,
297
surface->image->width,
298
surface->image->height, depth,
301
PNG_COMPRESSION_TYPE_DEFAULT,
302
PNG_FILTER_TYPE_DEFAULT);
307
png_set_bKGD (png, info, &white);
309
/* XXX: Setting the time is interfereing with the image comparison
310
png_convert_from_time_t (&png_time, time (NULL));
311
png_set_tIME (png, info, &png_time);
314
png_set_write_user_transform_fn (png, unpremultiply_data);
315
if (surface->format == CAIRO_FORMAT_ARGB32 || surface->format == CAIRO_FORMAT_RGB24)
317
if (surface->format == CAIRO_FORMAT_RGB24)
318
png_set_filler (png, 0, PNG_FILLER_AFTER);
320
png_write_info (png, info);
321
png_write_image (png, rows);
322
png_write_end (png, info);
327
png_destroy_write_struct (&png, &info);
334
static cairo_int_status_t
335
_cairo_png_surface_show_page (void *abstract_surface)
337
cairo_int_status_t status;
338
cairo_png_surface_t *surface = abstract_surface;
340
status = _cairo_png_surface_copy_page (surface);
344
_cairo_png_surface_erase (surface);
346
return CAIRO_STATUS_SUCCESS;
349
static cairo_int_status_t
350
_cairo_png_surface_set_clip_region (void *abstract_surface,
351
pixman_region16_t *region)
353
cairo_png_surface_t *surface = abstract_surface;
355
return _cairo_image_surface_set_clip_region (surface->image, region);
358
static cairo_int_status_t
359
_cairo_png_surface_create_pattern (void *abstract_surface,
360
cairo_pattern_t *pattern,
361
cairo_box_t *extents)
363
return CAIRO_INT_STATUS_UNSUPPORTED;
366
static const cairo_surface_backend_t cairo_png_surface_backend = {
367
_cairo_png_surface_create_similar,
368
_cairo_png_surface_destroy,
369
_cairo_png_surface_pixels_per_inch,
370
_cairo_png_surface_get_image,
371
_cairo_png_surface_set_image,
372
_cairo_png_surface_set_matrix,
373
_cairo_png_surface_set_filter,
374
_cairo_png_surface_set_repeat,
375
_cairo_png_surface_composite,
376
_cairo_png_surface_fill_rectangles,
377
_cairo_png_surface_composite_trapezoids,
378
_cairo_png_surface_copy_page,
379
_cairo_png_surface_show_page,
380
_cairo_png_surface_set_clip_region,
381
_cairo_png_surface_create_pattern