24
24
* Author: Richard D. Worth <richard@theworths.org> */
27
31
#include <stdlib.h>
29
37
#include "buffer-diff.h"
40
_xunlink (const char *pathname)
42
if (unlink (pathname) < 0 && errno != ENOENT) {
43
fprintf (stderr, " Error: Cannot remove %s: %s\n",
44
pathname, strerror (errno));
49
/* Flatten an ARGB surface by blending it over white. The resulting
50
* surface, (still in ARGB32 format, but with only alpha==1.0
51
* everywhere) is returned in the same surface pointer.
53
* The original surface will be destroyed.
55
* The (x,y) value specify an origin of interest for the original
56
* image. The flattened image will be generated only from the box
57
* extending from (x,y) to (width,height).
60
flatten_surface (cairo_surface_t **surface, int x, int y)
62
cairo_surface_t *flat;
65
flat = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
66
cairo_image_surface_get_width (*surface) - x,
67
cairo_image_surface_get_height (*surface) - y);
68
cairo_surface_set_device_offset (flat, -x, -y);
70
cr = cairo_create (flat);
71
cairo_surface_destroy (flat);
73
cairo_set_source_rgb (cr, 1, 1, 1);
76
cairo_set_source_surface (cr, *surface, 0, 0);
77
cairo_surface_destroy (*surface);
80
*surface = cairo_surface_reference (cairo_get_target (cr));
84
/* Given an image surface, create a new surface that has the same
85
* contents as the sub-surface with its origin at x,y.
87
* The original surface will be destroyed.
90
extract_sub_surface (cairo_surface_t **surface, int x, int y)
95
sub = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
96
cairo_image_surface_get_width (*surface) - x,
97
cairo_image_surface_get_height (*surface) - y);
99
/* We don't use a device offset like flatten_surface. That's not
100
* for any important reason, (the results should be
101
* identical). This style just seemed more natural to me this
102
* time, so I'm leaving both here so I can look at both to see
103
* which I like better. */
104
cr = cairo_create (sub);
105
cairo_surface_destroy (sub);
107
cairo_set_source_surface (cr, *surface, -x, -y);
108
cairo_surface_destroy (*surface);
109
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
112
*surface = cairo_surface_reference (cairo_get_target (cr));
116
static cairo_status_t
117
stdio_write_func (void *closure, const unsigned char *data, unsigned int length)
119
FILE *file = closure;
121
if (fwrite (data, 1, length, file) != length)
122
return CAIRO_STATUS_WRITE_ERROR;
124
return CAIRO_STATUS_SUCCESS;
127
static cairo_status_t
128
write_png (cairo_surface_t *surface, const char *filename)
130
cairo_status_t status;
133
if (filename != NULL) {
134
png_file = fopen (filename, "wb");
135
if (png_file == NULL) {
138
return CAIRO_STATUS_NO_MEMORY;
140
return CAIRO_STATUS_WRITE_ERROR;
146
status = cairo_surface_write_to_png_stream (surface,
150
if (png_file != stdout)
156
static cairo_status_t
157
png_diff (const char *filename_a,
158
const char *filename_b,
159
const char *filename_diff,
164
buffer_diff_result_t *result)
166
cairo_surface_t *surface_a;
167
cairo_surface_t *surface_b;
168
cairo_surface_t *surface_diff;
169
cairo_status_t status;
171
surface_a = cairo_image_surface_create_from_png (filename_a);
172
status = cairo_surface_status (surface_a);
174
fprintf (stderr, "Error: Failed to create surface from %s: %s\n",
175
filename_a, cairo_status_to_string (status));
179
surface_b = cairo_image_surface_create_from_png (filename_b);
180
status = cairo_surface_status (surface_b);
182
fprintf (stderr, "Error: Failed to create surface from %s: %s\n",
183
filename_b, cairo_status_to_string (status));
184
cairo_surface_destroy (surface_a);
189
extract_sub_surface (&surface_a, ax, ay);
194
extract_sub_surface (&surface_b, bx, by);
198
status = cairo_surface_status (surface_a);
200
fprintf (stderr, "Error: Failed to extract surface from %s: %s\n",
201
filename_a, cairo_status_to_string (status));
202
cairo_surface_destroy (surface_a);
203
cairo_surface_destroy (surface_b);
206
status = cairo_surface_status (surface_b);
208
fprintf (stderr, "Error: Failed to extract surface from %s: %s\n",
209
filename_b, cairo_status_to_string (status));
210
cairo_surface_destroy (surface_a);
211
cairo_surface_destroy (surface_b);
215
surface_diff = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
216
cairo_image_surface_get_width (surface_a),
217
cairo_image_surface_get_height (surface_a));
218
status = cairo_surface_status (surface_diff);
221
"Error: Failed to allocate surface to hold differences\n");
222
cairo_surface_destroy (surface_a);
223
cairo_surface_destroy (surface_b);
224
return CAIRO_STATUS_NO_MEMORY;
227
status = image_diff (NULL,
228
surface_a, surface_b, surface_diff,
231
cairo_surface_destroy (surface_a);
232
cairo_surface_destroy (surface_b);
233
cairo_surface_destroy (surface_diff);
235
_xunlink (filename_diff);
236
if (status == CAIRO_STATUS_SUCCESS &&
237
result->pixels_changed)
239
status = write_png (surface_diff, filename_diff);
33
247
main (int argc, char *argv[])