test/imagediff.c

Add new testsvg script and accompanying imagediff program, (for interim SVG-based test suites while we wait for the standard cairo test suite to mature).
Split buffer_diff out into its own file for the purpose of imagediff.
This commit is contained in:
Carl Worth 2005-01-25 14:45:31 +00:00
parent e5e0880d67
commit 2a7a9d00cc
13 changed files with 340 additions and 116 deletions

View file

@ -2,6 +2,7 @@
.libs
Makefile
Makefile.in
imagediff
fill_rule
leaky_polygon
line_width

View file

@ -42,6 +42,8 @@ INCLUDES = -D_GNU_SOURCE -I$(srcdir) $(CAIRO_CFLAGS) -I$(srcdir)/../src
AM_LDFLAGS = $(CAIRO_LIBS) ../src/libcairo.la
cairo_test_lib =\
buffer_diff.c \
buffer_diff.h \
cairo_test.c \
cairo_test.h \
read_png.c \
@ -61,4 +63,7 @@ move_to_show_surface_SOURCES = move_to_show_surface.c $(cairo_test_lib)
text_cache_crash_SOURCES = text_cache_crash.c $(cairo_test_lib)
text_rotate_SOURCES = text_rotate.c $(cairo_test_lib)
noinst_PROGRAMS = imagediff
imagediff_SOURCES = imagediff.c $(cairo_test_lib)
CLEANFILES = *-out.png *-diff.png

73
test/buffer-diff.c Normal file
View file

@ -0,0 +1,73 @@
/* imagediff - Compare two images
*
* Copyright © 2004 Richard D. Worth
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without
* fee, provided that the above copyright notice appear in all copies
* and that both that copyright notice and this permission notice
* appear in supporting documentation, and that the name of Richard Worth
* not be used in advertising or publicity pertaining to distribution
* of the software without specific, written prior permission.
* Richard Worth makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without express
* or implied warranty.
*
* RICHARD WORTH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
* NO EVENT SHALL RICHARD WORTH BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Author: Richard D. Worth <richard@theworths.org> */
#include "buffer_diff.h"
/* Image comparison code courttesy of Richard Worth.
* Returns number of pixels changed.
* Also fills out a "diff" image intended to visually show where the
* images differ.
*/
int
buffer_diff (char *buf_a, char *buf_b, char *buf_diff,
int width, int height, int stride)
{
int x, y;
int total_pixels_changed = 0;
unsigned char *row_a, *row_b, *row;
for (y = 0; y < height; y++)
{
row_a = buf_a + y * stride;
row_b = buf_b + y * stride;
row = buf_diff + y * stride;
for (x = 0; x < width; x++)
{
int channel;
unsigned char value_a, value_b;
int pixel_changed = 0;
for (channel = 0; channel < 4; channel++)
{
double diff;
value_a = row_a[x * 4 + channel];
value_b = row_b[x * 4 + channel];
if (value_a != value_b)
pixel_changed = 1;
diff = value_a - value_b;
row[x * 4 + channel] = 128 + diff / 3.0;
}
if (pixel_changed) {
total_pixels_changed++;
} else {
row[x*4+0] = 0;
row[x*4+1] = 0;
row[x*4+2] = 0;
}
row[x * 4 + 3] = 0xff; /* Set ALPHA to 100% (opaque) */
}
}
return total_pixels_changed;
}

38
test/buffer-diff.h Normal file
View file

@ -0,0 +1,38 @@
/* imagediff - Compare two images
*
* Copyright © 2004 Richard D. Worth
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without
* fee, provided that the above copyright notice appear in all copies
* and that both that copyright notice and this permission notice
* appear in supporting documentation, and that the name of Richard Worth
* not be used in advertising or publicity pertaining to distribution
* of the software without specific, written prior permission.
* Richard Worth makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without express
* or implied warranty.
*
* RICHARD WORTH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
* NO EVENT SHALL RICHARD WORTH BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Author: Richard D. Worth <richard@theworths.org> */
#ifndef BUFFER_DIFF_H
#define BUFFER_DIFF_H
/* Image comparison code courttesy of Richard Worth.
* Returns number of pixels changed.
* Also fills out a "diff" image intended to visually show where the
* images differ.
*/
int
buffer_diff (char *buf_a, char *buf_b, char *buf_diff,
int width, int height, int stride);
#endif

73
test/buffer_diff.c Normal file
View file

@ -0,0 +1,73 @@
/* imagediff - Compare two images
*
* Copyright © 2004 Richard D. Worth
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without
* fee, provided that the above copyright notice appear in all copies
* and that both that copyright notice and this permission notice
* appear in supporting documentation, and that the name of Richard Worth
* not be used in advertising or publicity pertaining to distribution
* of the software without specific, written prior permission.
* Richard Worth makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without express
* or implied warranty.
*
* RICHARD WORTH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
* NO EVENT SHALL RICHARD WORTH BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Author: Richard D. Worth <richard@theworths.org> */
#include "buffer_diff.h"
/* Image comparison code courttesy of Richard Worth.
* Returns number of pixels changed.
* Also fills out a "diff" image intended to visually show where the
* images differ.
*/
int
buffer_diff (char *buf_a, char *buf_b, char *buf_diff,
int width, int height, int stride)
{
int x, y;
int total_pixels_changed = 0;
unsigned char *row_a, *row_b, *row;
for (y = 0; y < height; y++)
{
row_a = buf_a + y * stride;
row_b = buf_b + y * stride;
row = buf_diff + y * stride;
for (x = 0; x < width; x++)
{
int channel;
unsigned char value_a, value_b;
int pixel_changed = 0;
for (channel = 0; channel < 4; channel++)
{
double diff;
value_a = row_a[x * 4 + channel];
value_b = row_b[x * 4 + channel];
if (value_a != value_b)
pixel_changed = 1;
diff = value_a - value_b;
row[x * 4 + channel] = 128 + diff / 3.0;
}
if (pixel_changed) {
total_pixels_changed++;
} else {
row[x*4+0] = 0;
row[x*4+1] = 0;
row[x*4+2] = 0;
}
row[x * 4 + 3] = 0xff; /* Set ALPHA to 100% (opaque) */
}
}
return total_pixels_changed;
}

38
test/buffer_diff.h Normal file
View file

@ -0,0 +1,38 @@
/* imagediff - Compare two images
*
* Copyright © 2004 Richard D. Worth
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without
* fee, provided that the above copyright notice appear in all copies
* and that both that copyright notice and this permission notice
* appear in supporting documentation, and that the name of Richard Worth
* not be used in advertising or publicity pertaining to distribution
* of the software without specific, written prior permission.
* Richard Worth makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without express
* or implied warranty.
*
* RICHARD WORTH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
* NO EVENT SHALL RICHARD WORTH BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Author: Richard D. Worth <richard@theworths.org> */
#ifndef BUFFER_DIFF_H
#define BUFFER_DIFF_H
/* Image comparison code courttesy of Richard Worth.
* Returns number of pixels changed.
* Also fills out a "diff" image intended to visually show where the
* images differ.
*/
int
buffer_diff (char *buf_a, char *buf_b, char *buf_diff,
int width, int height, int stride);
#endif

View file

@ -32,6 +32,7 @@
#include "cairo_test.h"
#include "buffer_diff.h"
#include "read_png.h"
#include "write_png.h"
#include "xmalloc.h"
@ -56,53 +57,6 @@ xasprintf (char **strp, const char *fmt, ...)
}
}
/* Image comparison code courttesy of Richard Worth.
* Returns number of pixels changed.
* Also fills out a "diff" image intended to visually show where the
* images differ.
*/
static int
image_diff (char *buf_a, char *buf_b, char *buf_diff,
int width, int height, int stride)
{
int x, y;
int total_pixels_changed = 0;
unsigned char *row_a, *row_b, *row;
for (y = 0; y < height; y++)
{
row_a = buf_a + y * stride;
row_b = buf_b + y * stride;
row = buf_diff + y * stride;
for (x = 0; x < width; x++)
{
int channel;
unsigned char value_a, value_b;
int pixel_changed = 0;
for (channel = 0; channel < 4; channel++)
{
double diff;
value_a = row_a[x * 4 + channel];
value_b = row_b[x * 4 + channel];
if (value_a != value_b)
pixel_changed = 1;
diff = value_a - value_b;
row[x * 4 + channel] = 128 + diff / 3.0;
}
if (pixel_changed) {
total_pixels_changed++;
} else {
row[x*4+0] = 0;
row[x*4+1] = 0;
row[x*4+2] = 0;
}
row[x * 4 + 3] = 0xff; /* Set ALPHA to 100% (opaque) */
}
}
return total_pixels_changed;
}
cairo_test_status_t
cairo_test (cairo_test_t *test, cairo_test_draw_function_t draw)
{
@ -115,6 +69,7 @@ cairo_test (cairo_test_t *test, cairo_test_draw_function_t draw)
int ref_width, ref_height, ref_stride;
read_png_status_t png_status;
cairo_test_status_t ret;
FILE *png_file;
/* The cairo part of the test is the easiest part */
cr = cairo_create ();
@ -146,7 +101,9 @@ cairo_test (cairo_test_t *test, cairo_test_draw_function_t draw)
xasprintf (&ref_name, "%s/%s%s", srcdir, test->name, CAIRO_TEST_REF_SUFFIX);
xasprintf (&diff_name, "%s%s", test->name, CAIRO_TEST_DIFF_SUFFIX);
write_png_argb32 (png_buf, png_name, test->width, test->height, stride);
png_file = fopen (png_name, "w");
write_png_argb32 (png_buf, png_file, test->width, test->height, stride);
fclose (png_file);
ref_buf = NULL;
png_status = (read_png_argb32 (ref_name, &ref_buf, &ref_width, &ref_height, &ref_stride));
@ -178,12 +135,14 @@ cairo_test (cairo_test_t *test, cairo_test_draw_function_t draw)
goto BAIL;
}
pixels_changed = image_diff (png_buf, ref_buf, diff_buf,
test->width, test->height, stride);
pixels_changed = buffer_diff (png_buf, ref_buf, diff_buf,
test->width, test->height, stride);
if (pixels_changed) {
fprintf (stderr, " Error: %d pixels differ from reference image %s\n",
pixels_changed, ref_name);
write_png_argb32 (diff_buf, diff_name, test->width, test->height, stride);
png_file = fopen (diff_name, "w");
write_png_argb32 (diff_buf, png_file, test->width, test->height, stride);
fclose (png_file);
ret = CAIRO_TEST_FAILURE;
goto BAIL;
} else {

View file

@ -32,6 +32,7 @@
#include "cairo_test.h"
#include "buffer_diff.h"
#include "read_png.h"
#include "write_png.h"
#include "xmalloc.h"
@ -56,53 +57,6 @@ xasprintf (char **strp, const char *fmt, ...)
}
}
/* Image comparison code courttesy of Richard Worth.
* Returns number of pixels changed.
* Also fills out a "diff" image intended to visually show where the
* images differ.
*/
static int
image_diff (char *buf_a, char *buf_b, char *buf_diff,
int width, int height, int stride)
{
int x, y;
int total_pixels_changed = 0;
unsigned char *row_a, *row_b, *row;
for (y = 0; y < height; y++)
{
row_a = buf_a + y * stride;
row_b = buf_b + y * stride;
row = buf_diff + y * stride;
for (x = 0; x < width; x++)
{
int channel;
unsigned char value_a, value_b;
int pixel_changed = 0;
for (channel = 0; channel < 4; channel++)
{
double diff;
value_a = row_a[x * 4 + channel];
value_b = row_b[x * 4 + channel];
if (value_a != value_b)
pixel_changed = 1;
diff = value_a - value_b;
row[x * 4 + channel] = 128 + diff / 3.0;
}
if (pixel_changed) {
total_pixels_changed++;
} else {
row[x*4+0] = 0;
row[x*4+1] = 0;
row[x*4+2] = 0;
}
row[x * 4 + 3] = 0xff; /* Set ALPHA to 100% (opaque) */
}
}
return total_pixels_changed;
}
cairo_test_status_t
cairo_test (cairo_test_t *test, cairo_test_draw_function_t draw)
{
@ -115,6 +69,7 @@ cairo_test (cairo_test_t *test, cairo_test_draw_function_t draw)
int ref_width, ref_height, ref_stride;
read_png_status_t png_status;
cairo_test_status_t ret;
FILE *png_file;
/* The cairo part of the test is the easiest part */
cr = cairo_create ();
@ -146,7 +101,9 @@ cairo_test (cairo_test_t *test, cairo_test_draw_function_t draw)
xasprintf (&ref_name, "%s/%s%s", srcdir, test->name, CAIRO_TEST_REF_SUFFIX);
xasprintf (&diff_name, "%s%s", test->name, CAIRO_TEST_DIFF_SUFFIX);
write_png_argb32 (png_buf, png_name, test->width, test->height, stride);
png_file = fopen (png_name, "w");
write_png_argb32 (png_buf, png_file, test->width, test->height, stride);
fclose (png_file);
ref_buf = NULL;
png_status = (read_png_argb32 (ref_name, &ref_buf, &ref_width, &ref_height, &ref_stride));
@ -178,12 +135,14 @@ cairo_test (cairo_test_t *test, cairo_test_draw_function_t draw)
goto BAIL;
}
pixels_changed = image_diff (png_buf, ref_buf, diff_buf,
test->width, test->height, stride);
pixels_changed = buffer_diff (png_buf, ref_buf, diff_buf,
test->width, test->height, stride);
if (pixels_changed) {
fprintf (stderr, " Error: %d pixels differ from reference image %s\n",
pixels_changed, ref_name);
write_png_argb32 (diff_buf, diff_name, test->width, test->height, stride);
png_file = fopen (diff_name, "w");
write_png_argb32 (diff_buf, png_file, test->width, test->height, stride);
fclose (png_file);
ret = CAIRO_TEST_FAILURE;
goto BAIL;
} else {

84
test/imagediff.c Normal file
View file

@ -0,0 +1,84 @@
/* imagediff - Compare two images
*
* Copyright © 2004 Richard D. Worth
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without
* fee, provided that the above copyright notice appear in all copies
* and that both that copyright notice and this permission notice
* appear in supporting documentation, and that the name of Richard Worth
* not be used in advertising or publicity pertaining to distribution
* of the software without specific, written prior permission.
* Richard Worth makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without express
* or implied warranty.
*
* RICHARD WORTH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
* NO EVENT SHALL RICHARD WORTH BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Author: Richard D. Worth <richard@theworths.org> */
#include <stdio.h>
#include <stdlib.h>
#include "buffer_diff.h"
#include "read_png.h"
#include "write_png.h"
#include "xmalloc.h"
int
main (int argc, char *argv[])
{
unsigned char *buffer_a;
unsigned int width_a, height_a, stride_a;
unsigned char *buffer_b;
unsigned int width_b, height_b, stride_b;
unsigned char *buffer;
unsigned int width, height, stride;
int buffer_size, total_pixels_changed;
if (argc < 2) {
fprintf (stderr, "Usage: %s image1.png image2.png\n", argv[0]);
fprintf (stderr, "Computes an output image designed to present a \"visual diff\" such that even\n");
fprintf (stderr, "small errors in single pixels are readily apparent in the output.\n");
fprintf (stderr, "The output image is written on stdout.\n");
exit (1);
}
read_png_argb32 (argv[1], &buffer_a, &width_a, &height_a, &stride_a);
read_png_argb32 (argv[2], &buffer_b, &width_b, &height_b, &stride_b);
if ((width_a == width_b) && (height_a == height_b) && (stride_a == stride_b))
{
width = width_a;
height = height_a;
stride = stride_a;
} else {
fprintf (stderr, "Error. Both images must be the same size\n");
return 1;
}
buffer_size = stride * height;
buffer = xmalloc (buffer_size);
total_pixels_changed = buffer_diff (buffer_a, buffer_b, buffer,
width_a, height_a, stride_a);
if (total_pixels_changed)
fprintf (stderr, "Total pixels changed: %d\n", total_pixels_changed);
write_png_argb32 (buffer, stdout, width, height, stride);
free (buffer);
return 0;
}

View file

@ -55,17 +55,15 @@ unpremultiply_data (png_structp png, png_row_infop row_info, png_bytep data)
}
void
write_png_argb32 (char *buffer, char *filename,
write_png_argb32 (char *buffer, FILE *file,
int width, int height, int stride)
{
FILE *f;
int i;
png_struct *png;
png_info *info;
png_byte **rows;
png_color_16 white;
f = fopen (filename, "w");
rows = malloc (height * sizeof(png_byte*));
for (i = 0; i < height; i++) {
@ -75,7 +73,7 @@ write_png_argb32 (char *buffer, char *filename,
png = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
info = png_create_info_struct (png);
png_init_io (png, f);
png_init_io (png, file);
png_set_IHDR (png, info,
width, height, 8,
PNG_COLOR_TYPE_RGB_ALPHA,
@ -98,5 +96,4 @@ write_png_argb32 (char *buffer, char *filename,
png_destroy_write_struct (&png, &info);
free (rows);
fclose (f);
}

View file

@ -1,5 +1,5 @@
/*
* Copyright © 2003 USC, Information Sciences Institute
* Copyright © 2003 USC, Information Sciences Institute
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without
@ -29,7 +29,7 @@
#define WRITE_PNG_H
void
write_png_argb32 (char *buffer, char *filename,
write_png_argb32 (char *buffer, FILE * file,
int width, int height, int stride);
#endif

View file

@ -55,17 +55,15 @@ unpremultiply_data (png_structp png, png_row_infop row_info, png_bytep data)
}
void
write_png_argb32 (char *buffer, char *filename,
write_png_argb32 (char *buffer, FILE *file,
int width, int height, int stride)
{
FILE *f;
int i;
png_struct *png;
png_info *info;
png_byte **rows;
png_color_16 white;
f = fopen (filename, "w");
rows = malloc (height * sizeof(png_byte*));
for (i = 0; i < height; i++) {
@ -75,7 +73,7 @@ write_png_argb32 (char *buffer, char *filename,
png = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
info = png_create_info_struct (png);
png_init_io (png, f);
png_init_io (png, file);
png_set_IHDR (png, info,
width, height, 8,
PNG_COLOR_TYPE_RGB_ALPHA,
@ -98,5 +96,4 @@ write_png_argb32 (char *buffer, char *filename,
png_destroy_write_struct (&png, &info);
free (rows);
fclose (f);
}

View file

@ -1,5 +1,5 @@
/*
* Copyright © 2003 USC, Information Sciences Institute
* Copyright © 2003 USC, Information Sciences Institute
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without
@ -29,7 +29,7 @@
#define WRITE_PNG_H
void
write_png_argb32 (char *buffer, char *filename,
write_png_argb32 (char *buffer, FILE * file,
int width, int height, int stride);
#endif