Commit ecea71eb authored by Martin Guy's avatar Martin Guy Committed by Bastien Nocera
Browse files

tests: Add rudimentary correctness tests for scaler

The scaler's testsuite has no checks for correctness of the scaled image.

This add some rudimentary ones, scaling a checkerboard to 1/2 size and
seeing if it's all gray and checking the "dest" and "offset" parameters.

https://bugzilla.gnome.org/show_bug.cgi?id=80925
parent c7b58acd
......@@ -169,9 +169,282 @@ test_rotate (gconstpointer data)
g_object_unref (ref);
}
/* Test images creation functions */
/* Checkerboard of black and white pxels (actually (1,1,1) and (255,255,255)
* so they average to (128,128,128)) */
static GdkPixbuf *
make_checkerboard (int width, int height)
{
GdkPixbuf *checkerboard;
guint x, y;
guchar *row; /* Pointer to start of row of pixels within the image */
guchar *pixel; /* Pointer to current pixel data in row */
checkerboard = gdk_pixbuf_new (GDK_COLORSPACE_RGB, 0, 8, width, height);
g_assert_nonnull (checkerboard);
for (y = 0, row = gdk_pixbuf_get_pixels (checkerboard);
y < height;
y++, row += gdk_pixbuf_get_rowstride (checkerboard))
{
for (x = 0, pixel = row;
x < width;
x++, pixel += gdk_pixbuf_get_n_channels (checkerboard))
{
pixel[0] = pixel[1] = pixel[2] = (x ^ y) & 1 ? 1 : 255;
}
}
return checkerboard;
}
/* Image where all the pixels have different colours */
static GdkPixbuf *
make_rg (int width, int height)
{
GdkPixbuf *pixbuf;
guint x, y;
guchar *row; /* Pointer to start of row of pixels within the image */
guchar *pixel; /* Pointer to current pixel data in row */
/* Make a source image whose pixels are all of different colors */
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, 0, 8, width, height);
g_assert_nonnull (pixbuf);
for (y = 0, row = gdk_pixbuf_get_pixels (pixbuf);
y < height;
y++, row += gdk_pixbuf_get_rowstride (pixbuf))
{
for (x = 0, pixel = row;
x < width;
x++, pixel += gdk_pixbuf_get_n_channels (pixbuf))
{
pixel[0] = x & 255; pixel[1] = y & 255;
/* If image > 256 pixels wide/high put the extra bits in the last pixel */
pixel[2] = ((x >> 8) & 15) | ((( y >> 8) & 15) << 4);
}
}
return pixbuf;
}
/* Create a 256x256 checkerboard of (1,1,1) and (255,255,255) pixels,
* scale it to exactly half size and check that all pixels are (128,128,128). */
static void
test_halve_checkerboard (gconstpointer data)
{
GdkInterpType interp_type = *(GdkInterpType *) data;
const GdkPixbuf *source; /* Source image */
gint width = 256, height = 256; /* Size of source image */
GdkPixbuf *scaled; /* Scaled version */
guchar *row; /* Pointer to start of row of pixels within the image */
guchar *pixel; /* Pointer to current pixel data in row */
guint x, y;
guchar expected; /* Expected color of all pixels */
expected = (interp_type == GDK_INTERP_NEAREST) ? 255 : 128;
source = make_checkerboard (width, height);
scaled = gdk_pixbuf_scale_simple (source, width / 2, height / 2, interp_type);
/* Check that the result is all gray (or all white in the case of NEAREST) */
for (y = 0, row = gdk_pixbuf_get_pixels (scaled);
y < gdk_pixbuf_get_height (scaled);
y++, row += gdk_pixbuf_get_rowstride (scaled))
{
for (x = 0, pixel = row;
x < gdk_pixbuf_get_width (scaled);
x++, pixel += gdk_pixbuf_get_n_channels (scaled))
{
if (!(pixel[0] == expected && pixel[1] == expected && pixel[2] == expected))
{
/* Expected failure: HYPER has a different opinion about the color
* of the corner pixels: (126,126,126) and (130,130,130) */
if (interp_type == GDK_INTERP_HYPER &&
(x == 0 || x == gdk_pixbuf_get_width (scaled) - 1) &&
(y == 0 || y == gdk_pixbuf_get_height (scaled) - 1))
{
continue;
}
g_test_fail ();
}
}
}
g_object_unref (G_OBJECT (scaled));
g_object_unref (G_OBJECT (source));
}
/* Crop a region out of a source image using subpixbuf() and using the scaler,
* and check that the results are the same */
static void
crop_n_compare (const GdkPixbuf *source,
gint offset_x,
gint offset_y,
guint width,
guint height,
GdkInterpType interp_type)
{
GdkPixbuf *cropped, *scaled;
guchar *crow, *srow; /* Pointer to current row in image data */
guchar *cpixel, *spixel; /* Pointer to current pixel in row */
guint x, y;
cropped = gdk_pixbuf_new_subpixbuf ((GdkPixbuf *)source, offset_x, offset_y, width, height);
g_assert_nonnull (cropped);
scaled = gdk_pixbuf_new (GDK_COLORSPACE_RGB, 0, 8, width, height);
g_assert_nonnull (scaled);
gdk_pixbuf_scale (source, scaled,
0, 0, /* dest_[xy] */
width, height, /* dest_width/height */
-1.0 * offset_x, -1.0 * offset_y, /* offset_[xy] */
1.0, 1.0, /* scale_[xy] */
interp_type);
for (y = 0, crow = gdk_pixbuf_get_pixels (cropped),
srow = gdk_pixbuf_get_pixels (scaled);
y < gdk_pixbuf_get_height (scaled);
y++, crow += gdk_pixbuf_get_rowstride (cropped),
srow += gdk_pixbuf_get_rowstride (scaled))
{
for (x = 0, cpixel = crow, spixel = srow;
x < gdk_pixbuf_get_width (scaled);
x++, cpixel += gdk_pixbuf_get_n_channels (cropped),
spixel += gdk_pixbuf_get_n_channels (scaled))
{
if (!(spixel[0] == cpixel[0] &&
spixel[1] == cpixel[1] &&
spixel[2] == cpixel[2]))
{
/* Expected failure: HYPER has a different opinion about the
* colors of the edge pixels */
if (interp_type == GDK_INTERP_HYPER &&
((x == 0 || x == gdk_pixbuf_get_width (scaled) - 1) ||
(y == 0 || y == gdk_pixbuf_get_height (scaled) - 1)))
{
continue;
}
g_test_fail();
}
}
}
g_object_unref (G_OBJECT (cropped));
g_object_unref (G_OBJECT (scaled));
}
/* Check that offsets work.
* We should be able to copy a region of an image using the scaler using
* negative offsets. */
static void
test_offset (gconstpointer data)
{
GdkInterpType interp_type = *(GdkInterpType *) data;
gint width = 256, height = 256;
const GdkPixbuf *source; /* Source image */
source = make_rg (width, height);
/* Check that the scaler correctly crops out an image half the size of the
* original from each corner and from the middle */
crop_n_compare (source, 0, 0, width / 2, height / 2, interp_type);
crop_n_compare (source, width / 2, 0, width / 2, height / 2, interp_type);
crop_n_compare (source, 0, height / 2, width / 2, height / 2, interp_type);
crop_n_compare (source, width / 2, height / 2, width / 2, height / 2, interp_type);
crop_n_compare (source, width / 4, height / 4, width / 2, height / 2, interp_type);
g_object_unref (G_OBJECT (source));
}
/* Test the dest_x and dest_y fields by making a copy of an image by
* scaling 1:1 and using dest to copy the four quadrants separately.
*
* When scaled, images are:
* 1) scaled by the scale factors with respect to the top-left corner
* 2) translated by the offsets (negative to shift the image left/up in its
* frame)
* 3) a region of size dest_width x dest-height starting at (dest_x,dest_y)
* in the scaled-and-offset image is copied to (dest_x,dest_y) in the
* destination image. See the illustration at
* https://developer.gnome.org/gdk-pixbuf/2.22/gdk-pixbuf-scaling.html#gdk-pixbuf-composite */
static void
test_dest (gconstpointer data)
{
GdkInterpType interp_type = *(GdkInterpType *) data;
gint width = 256, height = 256;
const GdkPixbuf *source; /* Source image */
GdkPixbuf *copy; /* Destination image */
gint x, y;
guchar *srow, *crow; /* Pointer to current row in source and copy data */
guchar *spixel, *cpixel; /* Pointer to current pixel in row */
source = make_rg (width, height);
copy = gdk_pixbuf_new (GDK_COLORSPACE_RGB, 0, 8, width, height);
g_assert_nonnull (copy);
/* Copy the four quadrants with a no-op scale */
gdk_pixbuf_scale ((const GdkPixbuf *)source, copy,
0, 0, /* dest_[xy] */
width / 2, height / 2, /* dest_width/height */
0.0, 0.0, /* offset_[xy] */
1.0, 1.0, /* scale_[xy] */
interp_type);
gdk_pixbuf_scale ((const GdkPixbuf *)source, copy,
width / 2, 0, /* dest_[xy] */
width / 2, height / 2, /* dest_width/height */
0.0, 0.0, /* offset_[xy] */
1.0, 1.0, /* scale_[xy] */
interp_type);
gdk_pixbuf_scale ((const GdkPixbuf *)source, copy,
0, height / 2, /* dest_[xy] */
width / 2, height / 2, /* dest_width/height */
0.0, 0.0, /* offset_[xy] */
1.0, 1.0, /* scale_[xy] */
interp_type);
gdk_pixbuf_scale ((const GdkPixbuf *)source, copy,
width / 2, height / 2, /* dest_[xy] */
width / 2, height / 2, /* dest_width/height */
0.0, 0.0, /* offset_[xy] */
1.0, 1.0, /* scale_[xy] */
interp_type);
/* Compare the original and the copy */
for (y = 0, srow = gdk_pixbuf_get_pixels (source),
crow = gdk_pixbuf_get_pixels (copy);
y < gdk_pixbuf_get_height (source);
y++, srow += gdk_pixbuf_get_rowstride (source),
crow += gdk_pixbuf_get_rowstride (copy))
{
for (x = 0, spixel = srow, cpixel = crow;
x < gdk_pixbuf_get_width (source);
x++, spixel += gdk_pixbuf_get_n_channels (source),
cpixel += gdk_pixbuf_get_n_channels (copy))
{
if (!(spixel[0] == cpixel[0] &&
spixel[1] == cpixel[1] &&
spixel[2] == cpixel[2]))
{
g_test_fail();
}
}
}
g_object_unref (G_OBJECT (source));
g_object_unref (G_OBJECT (copy));
}
int
main (int argc, char **argv)
{
GdkInterpType nearest = GDK_INTERP_NEAREST;
GdkInterpType tiles = GDK_INTERP_TILES;
GdkInterpType bilinear = GDK_INTERP_BILINEAR;
GdkInterpType hyper = GDK_INTERP_HYPER;
g_test_init (&argc, &argv, NULL);
g_test_add_data_func ("/pixbuf/scale/png", "test-images/randomly-modified/valid.1.png", test_scale);
......@@ -189,5 +462,20 @@ main (int argc, char **argv)
g_test_add_data_func ("/pixbuf/rotate/large", "large.png", test_rotate);
}
g_test_add_data_func ("/pixbuf/scale/halve-checkerboard/nearest", &nearest, test_halve_checkerboard);
g_test_add_data_func ("/pixbuf/scale/halve-checkerboard/tiles", &tiles, test_halve_checkerboard);
g_test_add_data_func ("/pixbuf/scale/halve-checkerboard/bilinear", &bilinear, test_halve_checkerboard);
g_test_add_data_func ("/pixbuf/scale/halve-checkerboard/hyper", &hyper, test_halve_checkerboard);
g_test_add_data_func ("/pixbuf/scale/offset/nearest", &nearest, test_offset);
g_test_add_data_func ("/pixbuf/scale/offset/tiles", &tiles, test_offset);
g_test_add_data_func ("/pixbuf/scale/offset/bilinear", &bilinear, test_offset);
g_test_add_data_func ("/pixbuf/scale/offset/hyper", &hyper, test_offset);
g_test_add_data_func ("/pixbuf/scale/dest/nearest", &nearest, test_dest);
g_test_add_data_func ("/pixbuf/scale/dest/tiles", &tiles, test_dest);
g_test_add_data_func ("/pixbuf/scale/dest/bilinear", &bilinear, test_dest);
/* Don't bother with hyper as it changes the edge pixels */
return g_test_run ();
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment