~ubuntu-branches/ubuntu/breezy/libcairo/breezy-security

« back to all changes in this revision

Viewing changes to src/cairo_png_surface.c

  • Committer: Bazaar Package Importer
  • Author(s): Dave Beckett
  • Date: 2004-05-29 21:10:58 UTC
  • Revision ID: james.westby@ubuntu.com-20040529211058-h596wztdkmpvul0k
Tags: upstream-0.1.23
ImportĀ upstreamĀ versionĀ 0.1.23

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include <png.h>
 
2
 
 
3
#include "cairoint.h"
 
4
 
 
5
static const cairo_surface_backend_t cairo_png_surface_backend;
 
6
 
 
7
static cairo_int_status_t
 
8
_cairo_png_surface_copy_page (void *abstract_surface);
 
9
 
 
10
void
 
11
cairo_set_target_png (cairo_t   *cr,
 
12
                      FILE      *file,
 
13
                      cairo_format_t    format,
 
14
                      int               width,
 
15
                      int               height)
 
16
{
 
17
    cairo_surface_t *surface;
 
18
 
 
19
    surface = cairo_png_surface_create (file, format, 
 
20
                                        width, height);
 
21
 
 
22
    if (surface == NULL) {
 
23
        cr->status = CAIRO_STATUS_NO_MEMORY;
 
24
        return;
 
25
    }
 
26
 
 
27
    cairo_set_target_surface (cr, surface);
 
28
 
 
29
    /* cairo_set_target_surface takes a reference, so we must destroy ours */
 
30
    cairo_surface_destroy (surface);
 
31
}
 
32
 
 
33
typedef struct cairo_png_surface {
 
34
    cairo_surface_t base;
 
35
 
 
36
    /* PNG-specific fields */
 
37
    cairo_image_surface_t *image;
 
38
    FILE *file;
 
39
    int copied;
 
40
 
 
41
    cairo_format_t format;
 
42
 
 
43
} cairo_png_surface_t;
 
44
 
 
45
 
 
46
static void
 
47
_cairo_png_surface_erase (cairo_png_surface_t *surface);
 
48
 
 
49
cairo_surface_t *
 
50
cairo_png_surface_create (FILE                  *file,
 
51
                          cairo_format_t        format,
 
52
                          int                   width,
 
53
                          int                   height)
 
54
{
 
55
    cairo_png_surface_t *surface;
 
56
 
 
57
    surface = malloc (sizeof (cairo_png_surface_t));
 
58
    if (surface == NULL)
 
59
        return NULL;
 
60
 
 
61
    _cairo_surface_init (&surface->base, &cairo_png_surface_backend);
 
62
 
 
63
    surface->image = (cairo_image_surface_t *)
 
64
        cairo_image_surface_create (format, width, height);
 
65
 
 
66
    if (surface->image == NULL) {
 
67
        free (surface);
 
68
        return NULL;
 
69
    }
 
70
 
 
71
    _cairo_png_surface_erase (surface);
 
72
 
 
73
    surface->file = file;
 
74
    surface->copied = 0;
 
75
 
 
76
    surface->format = format;
 
77
 
 
78
    return &surface->base;
 
79
}
 
80
 
 
81
 
 
82
static cairo_surface_t *
 
83
_cairo_png_surface_create_similar (void         *abstract_src,
 
84
                                   cairo_format_t       format,
 
85
                                   int          width,
 
86
                                   int          height)
 
87
{
 
88
    return NULL;
 
89
}
 
90
 
 
91
static void
 
92
unpremultiply_data (png_structp png, png_row_infop row_info, png_bytep data)
 
93
{
 
94
    int i;
 
95
 
 
96
    for (i = 0; i < row_info->rowbytes; i += 4) {
 
97
        unsigned char *b = &data[i];
 
98
        unsigned int pixel;
 
99
        unsigned char alpha;
 
100
 
 
101
        memcpy (&pixel, b, sizeof (unsigned int));
 
102
        alpha = (pixel & 0xff000000) >> 24;
 
103
        if (alpha == 0) {
 
104
            b[0] = b[1] = b[2] = b[3] = 0;
 
105
        } else {
 
106
            b[0] = (((pixel & 0x0000ff) >>  0) * 255) / alpha;
 
107
            b[1] = (((pixel & 0x00ff00) >>  8) * 255) / alpha;
 
108
            b[2] = (((pixel & 0xff0000) >> 16) * 255) / alpha;
 
109
            b[3] = alpha;
 
110
        }
 
111
    }
 
112
}
 
113
 
 
114
static void
 
115
_cairo_png_surface_destroy (void *abstract_surface)
 
116
{
 
117
    cairo_png_surface_t *surface = abstract_surface;
 
118
 
 
119
    if (! surface->copied)
 
120
        _cairo_png_surface_copy_page (surface);
 
121
 
 
122
    cairo_surface_destroy (&surface->image->base);
 
123
 
 
124
    free (surface);
 
125
}
 
126
 
 
127
static void
 
128
_cairo_png_surface_erase (cairo_png_surface_t *surface)
 
129
{
 
130
    cairo_color_t transparent;
 
131
 
 
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,
 
136
                                   CAIRO_OPERATOR_SRC,
 
137
                                   &transparent,
 
138
                                   0, 0,
 
139
                                   surface->image->width,
 
140
                                   surface->image->height);
 
141
}
 
142
 
 
143
static double
 
144
_cairo_png_surface_pixels_per_inch (void *abstract_surface)
 
145
{
 
146
    return 96.0;
 
147
}
 
148
 
 
149
static cairo_image_surface_t *
 
150
_cairo_png_surface_get_image (void *abstract_surface)
 
151
{
 
152
    cairo_png_surface_t *surface = abstract_surface;
 
153
 
 
154
    cairo_surface_reference (&surface->image->base);
 
155
 
 
156
    return surface->image;
 
157
}
 
158
 
 
159
static cairo_status_t
 
160
_cairo_png_surface_set_image (void                      *abstract_surface,
 
161
                              cairo_image_surface_t     *image)
 
162
{
 
163
    cairo_png_surface_t *surface = abstract_surface;
 
164
 
 
165
    if (image == surface->image)
 
166
        return CAIRO_STATUS_SUCCESS;
 
167
 
 
168
    /* XXX: Need to call _cairo_image_surface_set_image here, but it's
 
169
       not implemented yet. */
 
170
 
 
171
    return CAIRO_INT_STATUS_UNSUPPORTED;
 
172
}
 
173
 
 
174
static cairo_status_t
 
175
_cairo_png_surface_set_matrix (void             *abstract_surface,
 
176
                               cairo_matrix_t   *matrix)
 
177
{
 
178
    cairo_png_surface_t *surface = abstract_surface;
 
179
 
 
180
    return _cairo_image_surface_set_matrix (surface->image, matrix);
 
181
}
 
182
 
 
183
static cairo_status_t
 
184
_cairo_png_surface_set_filter (void             *abstract_surface,
 
185
                               cairo_filter_t   filter)
 
186
{
 
187
    cairo_png_surface_t *surface = abstract_surface;
 
188
 
 
189
    return _cairo_image_surface_set_filter (surface->image, filter);
 
190
}
 
191
 
 
192
static cairo_status_t
 
193
_cairo_png_surface_set_repeat (void             *abstract_surface,
 
194
                               int              repeat)
 
195
{
 
196
    cairo_png_surface_t *surface = abstract_surface;
 
197
 
 
198
    return _cairo_image_surface_set_repeat (surface->image, repeat);
 
199
}
 
200
 
 
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,
 
205
                              void              *abstract_dst,
 
206
                              int               src_x,
 
207
                              int               src_y,
 
208
                              int               mask_x,
 
209
                              int               mask_y,
 
210
                              int               dst_x,
 
211
                              int               dst_y,
 
212
                              unsigned int      width,
 
213
                              unsigned int      height)
 
214
{
 
215
    return CAIRO_INT_STATUS_UNSUPPORTED;
 
216
}
 
217
 
 
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,
 
223
                                    int                 num_rects)
 
224
{
 
225
    return CAIRO_INT_STATUS_UNSUPPORTED;
 
226
}
 
227
 
 
228
static cairo_int_status_t
 
229
_cairo_png_surface_composite_trapezoids (cairo_operator_t       operator,
 
230
                                         cairo_surface_t                *generic_src,
 
231
                                         void                   *abstract_dst,
 
232
                                         int                    x_src,
 
233
                                         int                    y_src,
 
234
                                         cairo_trapezoid_t      *traps,
 
235
                                         int                    num_traps)
 
236
{
 
237
    return CAIRO_INT_STATUS_UNSUPPORTED;
 
238
}
 
239
 
 
240
static cairo_int_status_t
 
241
_cairo_png_surface_copy_page (void *abstract_surface)
 
242
{
 
243
    int i;
 
244
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
 
245
    cairo_png_surface_t *surface = abstract_surface;
 
246
    png_struct *png;
 
247
    png_info *info;
 
248
    png_byte **rows;
 
249
    png_color_16 white;
 
250
    int png_color_type;
 
251
    int depth;
 
252
 
 
253
    rows = malloc (surface->image->height * sizeof(png_byte*));
 
254
    if (rows == NULL)
 
255
        return CAIRO_STATUS_NO_MEMORY;
 
256
 
 
257
    for (i = 0; i < surface->image->height; i++)
 
258
        rows[i] = surface->image->data + i * surface->image->stride;
 
259
 
 
260
    png = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
 
261
    if (png == NULL)
 
262
        return CAIRO_STATUS_NO_MEMORY;
 
263
 
 
264
    info = png_create_info_struct (png);
 
265
    if (info == NULL) {
 
266
        png_destroy_write_struct (&png, NULL);
 
267
        return CAIRO_STATUS_NO_MEMORY;
 
268
    }
 
269
 
 
270
    if (setjmp (png_jmpbuf (png))) {
 
271
        status = CAIRO_STATUS_NO_MEMORY;
 
272
        goto BAIL;
 
273
    }
 
274
    
 
275
    png_init_io (png, surface->file);
 
276
 
 
277
    switch (surface->format) {
 
278
    case CAIRO_FORMAT_ARGB32:
 
279
        depth = 8;
 
280
        png_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
 
281
        break;
 
282
    case CAIRO_FORMAT_RGB24:
 
283
        depth = 8;
 
284
        png_color_type = PNG_COLOR_TYPE_RGB;
 
285
        break;
 
286
    case CAIRO_FORMAT_A8:
 
287
        depth = 8;
 
288
        png_color_type = PNG_COLOR_TYPE_GRAY;
 
289
        break;
 
290
    case CAIRO_FORMAT_A1:
 
291
        depth = 1;
 
292
        png_color_type = PNG_COLOR_TYPE_GRAY;
 
293
        break;
 
294
    }
 
295
 
 
296
    png_set_IHDR (png, info,
 
297
                  surface->image->width,
 
298
                  surface->image->height, depth,
 
299
                  png_color_type,
 
300
                  PNG_INTERLACE_NONE,
 
301
                  PNG_COMPRESSION_TYPE_DEFAULT,
 
302
                  PNG_FILTER_TYPE_DEFAULT);
 
303
 
 
304
    white.red = 0xff;
 
305
    white.blue = 0xff;
 
306
    white.green = 0xff;
 
307
    png_set_bKGD (png, info, &white);
 
308
 
 
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);
 
312
*/
 
313
 
 
314
    png_set_write_user_transform_fn (png, unpremultiply_data);
 
315
    if (surface->format == CAIRO_FORMAT_ARGB32 || surface->format == CAIRO_FORMAT_RGB24)
 
316
        png_set_bgr (png);
 
317
    if (surface->format == CAIRO_FORMAT_RGB24)
 
318
        png_set_filler (png, 0, PNG_FILLER_AFTER);
 
319
 
 
320
    png_write_info (png, info);
 
321
    png_write_image (png, rows);
 
322
    png_write_end (png, info);
 
323
 
 
324
    surface->copied = 1;
 
325
 
 
326
BAIL:
 
327
    png_destroy_write_struct (&png, &info);
 
328
 
 
329
    free (rows);
 
330
 
 
331
    return status;
 
332
}
 
333
 
 
334
static cairo_int_status_t
 
335
_cairo_png_surface_show_page (void *abstract_surface)
 
336
{
 
337
    cairo_int_status_t status;
 
338
    cairo_png_surface_t *surface = abstract_surface;
 
339
 
 
340
    status = _cairo_png_surface_copy_page (surface);
 
341
    if (status)
 
342
        return status;
 
343
 
 
344
    _cairo_png_surface_erase (surface);
 
345
 
 
346
    return CAIRO_STATUS_SUCCESS;
 
347
}
 
348
 
 
349
static cairo_int_status_t
 
350
_cairo_png_surface_set_clip_region (void *abstract_surface,
 
351
                                    pixman_region16_t *region)
 
352
{
 
353
    cairo_png_surface_t *surface = abstract_surface;
 
354
 
 
355
    return _cairo_image_surface_set_clip_region (surface->image, region);
 
356
}
 
357
 
 
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)
 
362
{
 
363
    return CAIRO_INT_STATUS_UNSUPPORTED;
 
364
}
 
365
 
 
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
 
382
};