1
/* imagediff - Compare two images
2
 *
3
 * Copyright © 2004 Richard D. Worth
4
 *
5
 * Permission to use, copy, modify, distribute, and sell this software
6
 * and its documentation for any purpose is hereby granted without
7
 * fee, provided that the above copyright notice appear in all copies
8
 * and that both that copyright notice and this permission notice
9
 * appear in supporting documentation, and that the name of Richard Worth
10
 * not be used in advertising or publicity pertaining to distribution
11
 * of the software without specific, written prior permission.
12
 * Richard Worth makes no representations about the suitability of this
13
 * software for any purpose.  It is provided "as is" without express
14
 * or implied warranty.
15
 *
16
 * RICHARD WORTH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
18
 * NO EVENT SHALL RICHARD WORTH BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
20
 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
21
 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
22
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23
 *
24
 * Author: Richard D. Worth <richard@theworths.org> */
25

            
26
#include "config.h"
27

            
28
#include <assert.h>
29
#include <stdio.h>
30
#include <stdlib.h>
31
#ifdef HAVE_UNISTD_H
32
#include <unistd.h>
33
#endif
34
#include <errno.h>
35
#include <string.h>
36
#include <pixman.h>
37

            
38
#include "cairo-test.h"
39

            
40
#include "pdiff.h"
41
#include "buffer-diff.h"
42

            
43
/* Don't allow any differences greater than this value, even if pdiff
44
 * claims that the images are identical */
45
#define PERCEPTUAL_DIFF_THRESHOLD 25
46

            
47
/* Compare two buffers, returning the number of pixels that are
48
 * different and the maximum difference of any single color channel in
49
 * result_ret.
50
 *
51
 * This function should be rewritten to compare all formats supported by
52
 * cairo_format_t.
53
 */
54
static void
55
1779
buffer_diff_core (const unsigned char *_buf_a, int stride_a, cairo_format_t format_a,
56
		  const unsigned char *_buf_b, int stride_b, cairo_format_t format_b,
57
		  unsigned char *_buf_diff, int stride_diff, cairo_format_t format_diff,
58
		  int		width,
59
		  int		height,
60
		  buffer_diff_result_t *result_ret)
61
{
62
1779
    const uint32_t *buf_a = (const uint32_t*) _buf_a;
63
1779
    const uint32_t *buf_b = (const uint32_t*) _buf_b;
64
1779
    uint32_t *buf_diff = (uint32_t*) _buf_diff;
65
    int x, y;
66
1779
    buffer_diff_result_t result = {0, 0};
67

            
68
1779
    assert (format_a == CAIRO_FORMAT_RGB24 || format_a == CAIRO_FORMAT_ARGB32);
69
1779
    assert (format_b == CAIRO_FORMAT_RGB24 || format_b == CAIRO_FORMAT_ARGB32);
70
1779
    assert (format_diff == CAIRO_FORMAT_RGB24 || format_diff == CAIRO_FORMAT_ARGB32);
71

            
72
1779
    stride_a /= sizeof (uint32_t);
73
1779
    stride_b /= sizeof (uint32_t);
74
1779
    stride_diff /= sizeof (uint32_t);
75
253156
    for (y = 0; y < height; y++) {
76
251377
	const uint32_t *row_a = buf_a + y * stride_a;
77
251377
	const uint32_t *row_b = buf_b + y * stride_b;
78
251377
	uint32_t *row = buf_diff + y * stride_diff;
79

            
80
104713718
	for (x = 0; x < width; x++) {
81
104462341
	    uint32_t pixel_a = row_a[x];
82
104462341
	    uint32_t pixel_b = row_b[x];
83
	    /* convert pixel data to ARGB32 if necessary */
84
104462341
	    if (format_a == CAIRO_FORMAT_RGB24)
85
78228193
		pixel_a |= 0xff000000;
86
104462341
	    if (format_b == CAIRO_FORMAT_RGB24)
87
91524569
		pixel_b |= 0xff000000;
88

            
89
	    /* check if the pixels are the same */
90
104462341
	    if (pixel_a != pixel_b) {
91
		int channel;
92
15283043
		uint32_t diff_pixel = 0;
93

            
94
		/* calculate a difference value for all 4 channels */
95
76415215
		for (channel = 0; channel < 4; channel++) {
96
61132172
		    int value_a = (pixel_a >> (channel*8)) & 0xff;
97
61132172
		    int value_b = (pixel_b >> (channel*8)) & 0xff;
98
		    unsigned int diff;
99
61132172
		    diff = abs (value_a - value_b);
100
61132172
		    if (diff > result.max_diff)
101
4028
			result.max_diff = diff;
102
61132172
		    diff *= 4;  /* emphasize */
103
61132172
		    if (diff)
104
34881771
			diff += 128; /* make sure it's visible */
105
61132172
		    if (diff > 255)
106
2666439
			diff = 255;
107
61132172
		    diff_pixel |= diff << (channel*8);
108
		}
109

            
110
15283043
		result.pixels_changed++;
111
15283043
		if ((diff_pixel & 0x00ffffff) == 0) {
112
		    /* alpha only difference, convert to luminance */
113
2014733
		    uint8_t alpha = diff_pixel >> 24;
114
2014733
		    diff_pixel = alpha * 0x010101;
115
		}
116
15283043
		row[x] = diff_pixel;
117
	    } else {
118
89179298
		row[x] = 0;
119
	    }
120
104462341
	    row[x] |= 0xff000000; /* Set ALPHA to 100% (opaque) */
121
	}
122
    }
123

            
124
1779
    *result_ret = result;
125
1779
}
126

            
127
/* Compares two image surfaces
128
 *
129
 * Provides number of pixels changed and maximum single-channel
130
 * difference in result.
131
 *
132
 * Also fills in a "diff" surface intended to visually show where the
133
 * images differ.
134
 */
135
static void
136
1779
compare_surfaces (const cairo_test_context_t  *ctx,
137
	          cairo_surface_t	*surface_a,
138
		  cairo_surface_t	*surface_b,
139
		  cairo_surface_t	*surface_diff,
140
		  buffer_diff_result_t	*result)
141
{
142
    /* These default values were taken straight from the
143
     * perceptualdiff program. We'll probably want to tune these as
144
     * necessary. */
145
1779
    double gamma = 2.2;
146
1779
    double luminance = 100.0;
147
1779
    double field_of_view = 45.0;
148
    int discernible_pixels_changed;
149

            
150
    /* First, we run cairo's old buffer_diff algorithm which looks for
151
     * pixel-perfect images, (we do this first since the test suite
152
     * runs about 3x slower if we run pdiff_compare first).
153
     */
154
3558
    buffer_diff_core (cairo_image_surface_get_data (surface_a),
155
		      cairo_image_surface_get_stride (surface_a),
156
		      cairo_image_surface_get_format (surface_a),
157
1779
		      cairo_image_surface_get_data (surface_b),
158
		      cairo_image_surface_get_stride (surface_b),
159
		      cairo_image_surface_get_format (surface_b),
160
		      cairo_image_surface_get_data (surface_diff),
161
		      cairo_image_surface_get_stride (surface_diff),
162
		      cairo_image_surface_get_format (surface_diff),
163
		      cairo_image_surface_get_width (surface_a),
164
		      cairo_image_surface_get_height (surface_a),
165
		      result);
166
1779
    if (result->pixels_changed == 0)
167
663
	return;
168

            
169
1116
    cairo_test_log (ctx,
170
	            "%d pixels differ (with maximum difference of %d) from reference image\n",
171
		    result->pixels_changed, result->max_diff);
172

            
173
    /* Then, if there are any different pixels, we give the pdiff code
174
     * a crack at the images. If it decides that there are no visually
175
     * discernible differences in any pixels, then we accept this
176
     * result as good enough.
177
     *
178
     * Only let pdiff have a crack at the comparison if the max difference
179
     * is lower than a threshold, otherwise some problems could be masked.
180
     */
181
1116
    if (result->max_diff < PERCEPTUAL_DIFF_THRESHOLD) {
182
755
        discernible_pixels_changed = pdiff_compare (surface_a, surface_b,
183
                                                    gamma, luminance, field_of_view);
184
755
        if (discernible_pixels_changed == 0) {
185
337
            result->pixels_changed = 0;
186
337
            cairo_test_log (ctx,
187
		            "But perceptual diff finds no visually discernible difference.\n"
188
                            "Accepting result.\n");
189
        }
190
    }
191
}
192

            
193
void
194
buffer_diff_noalpha (const unsigned char *buf_a,
195
		     const unsigned char *buf_b,
196
		     unsigned char *buf_diff,
197
		     int	   width,
198
		     int	   height,
199
		     int	   stride,
200
		     buffer_diff_result_t *result)
201
{
202
    buffer_diff_core(buf_a, stride, CAIRO_FORMAT_RGB24,
203
		     buf_b, stride, CAIRO_FORMAT_RGB24,
204
		     buf_diff, stride, CAIRO_FORMAT_RGB24,
205
		     width, height,
206
		     result);
207
}
208

            
209
static cairo_bool_t
210
3558
same_size (cairo_surface_t *a, cairo_surface_t *b)
211
{
212
    unsigned int width_a, height_a;
213
    unsigned int width_b, height_b;
214

            
215
3558
    width_a = cairo_image_surface_get_width (a);
216
3558
    height_a = cairo_image_surface_get_height (a);
217

            
218
3558
    width_b = cairo_image_surface_get_width (b);
219
3558
    height_b = cairo_image_surface_get_height (b);
220

            
221
3558
    return width_a == width_b && height_a == height_b;
222
}
223

            
224
/* Image comparison code courtesy of Richard Worth <richard@theworths.org>
225
 * Returns number of pixels changed, (or -1 on error).
226
 * Also saves a "diff" image intended to visually show where the
227
 * images differ.
228
 *
229
 * The return value simply indicates whether a check was successfully
230
 * made, (as opposed to a file-not-found condition or similar). It
231
 * does not indicate anything about how much the images differ. For
232
 * that, see result.
233
 *
234
 * One failure mode is if the two images provided do not have the same
235
 * dimensions. In this case, this function will return
236
 * CAIRO_STATUS_SURFACE_TYPE_MISMATCH (which is a bit of an abuse, but
237
 * oh well).
238
 */
239
cairo_status_t
240
1779
image_diff (const cairo_test_context_t *ctx,
241
	    cairo_surface_t *surface_a,
242
	    cairo_surface_t *surface_b,
243
	    cairo_surface_t *surface_diff,
244
	    buffer_diff_result_t *result)
245
{
246
1779
    if (cairo_surface_status (surface_a))
247
	return cairo_surface_status (surface_a);
248

            
249
1779
    if (cairo_surface_status (surface_b))
250
	return cairo_surface_status (surface_b);
251

            
252
1779
    if (cairo_surface_status (surface_diff))
253
	return cairo_surface_status (surface_diff);
254

            
255
3558
    if (! same_size (surface_a, surface_b) ||
256
1779
	! same_size (surface_a, surface_diff))
257
    {
258
	cairo_test_log (ctx, "Error: Image size mismatch\n");
259
	return CAIRO_STATUS_SURFACE_TYPE_MISMATCH;
260
    }
261

            
262
1779
    compare_surfaces (ctx, surface_a, surface_b, surface_diff, result);
263

            
264
1779
    return CAIRO_STATUS_SUCCESS;
265
}
266

            
267
cairo_bool_t
268
1779
image_diff_is_failure (const buffer_diff_result_t *result,
269
                       unsigned int                tolerance)
270
{
271
2558
  return result->pixels_changed &&
272
779
         result->max_diff > tolerance;
273
}