[cairo-commit] 24 commits - test/buffer-diff.c test/buffer-diff.h test/cairo-test.c test/caps-joins-ps-argb32-ref.png test/caps-sub-paths-ps-argb32-ref.png test/close-path-ps-argb32-ref.png test/dash-offset-negative-ps-argb32-ref.png test/fill-and-stroke-alpha-svg-ref.png test/glyph-cache-pressure-ps-argb32-ref.png test/glyph-cache-pressure-svg-ref.png test/infinite-join-ps-argb32-ref.png test/leaky-polygon-ps-argb32-ref.png test/line-width-ps-argb32-ref.png test/Makefile.am test/mask-ctm-svg-rgb24-ref.png test/mask-surface-ctm-svg-rgb24-ref.png test/pdiff test/push-group-svg-rgb24-ref.png test/select-font-face-ps-argb32-ref.png test/select-font-face-svg-ref.png test/set-source-svg-rgb24-ref.png test/show-text-current-point-ps-argb32-ref.png test/show-text-current-point-svg-ref.png test/transforms-ps-argb32-ref.png test/trap-clip-svg-rgb24-ref.png

Carl Worth cworth at kemper.freedesktop.org
Thu Dec 14 07:59:17 PST 2006


 dev/null                                       |binary
 test/Makefile.am                               |    4 
 test/buffer-diff.c                             |   58 ++--
 test/buffer-diff.h                             |   15 -
 test/cairo-test.c                              |   12 
 test/caps-joins-ps-argb32-ref.png              |    0 
 test/caps-sub-paths-ps-argb32-ref.png          |    0 
 test/close-path-ps-argb32-ref.png              |    0 
 test/dash-offset-negative-ps-argb32-ref.png    |    0 
 test/fill-and-stroke-alpha-svg-ref.png         |    0 
 test/glyph-cache-pressure-ps-argb32-ref.png    |    0 
 test/glyph-cache-pressure-svg-ref.png          |    0 
 test/infinite-join-ps-argb32-ref.png           |    0 
 test/leaky-polygon-ps-argb32-ref.png           |    0 
 test/line-width-ps-argb32-ref.png              |    0 
 test/mask-ctm-svg-rgb24-ref.png                |    0 
 test/mask-surface-ctm-svg-rgb24-ref.png        |    0 
 test/pdiff/.gitignore                          |    1 
 test/pdiff/CompareArgs.cpp                     |  136 ---------
 test/pdiff/CompareArgs.h                       |   44 ---
 test/pdiff/LPyramid.cpp                        |   87 ------
 test/pdiff/LPyramid.h                          |   38 --
 test/pdiff/Makefile.am                         |   22 -
 test/pdiff/Metric.cpp                          |  348 ------------------------
 test/pdiff/Metric.h                            |   26 -
 test/pdiff/PerceptualDiff.cpp                  |   45 ---
 test/pdiff/README.txt                          |    4 
 test/pdiff/RGBAImage.cpp                       |  144 ---------
 test/pdiff/RGBAImage.h                         |   57 ---
 test/pdiff/args.c                              |  119 ++++++++
 test/pdiff/args.h                              |   46 +++
 test/pdiff/lpyramid.c                          |  111 +++++++
 test/pdiff/lpyramid.h                          |   32 ++
 test/pdiff/pdiff.c                             |  361 +++++++++++++++++++++++++
 test/pdiff/pdiff.h                             |   40 ++
 test/pdiff/perceptualdiff.c                    |  101 ++++++
 test/push-group-svg-rgb24-ref.png              |    0 
 test/select-font-face-ps-argb32-ref.png        |    0 
 test/select-font-face-svg-ref.png              |    0 
 test/set-source-svg-rgb24-ref.png              |    0 
 test/show-text-current-point-ps-argb32-ref.png |    0 
 test/show-text-current-point-svg-ref.png       |    0 
 test/transforms-ps-argb32-ref.png              |    0 
 test/trap-clip-svg-rgb24-ref.png               |    0 
 44 files changed, 882 insertions(+), 969 deletions(-)

New commits:
diff-tree 4888a02666972e9c09d9ffd9854538191cf59d77 (from 5e0818d79d13f5942485b411a04a4eebd56d36f8)
Author: Carl Worth <cworth at cworth.org>
Date:   Thu Dec 14 04:56:19 2006 -0800

    test: Remove ps-specific reference images no longer needed thanks to pdiff

diff --git a/test/caps-joins-ps-argb32-ref.png b/test/caps-joins-ps-argb32-ref.png
deleted file mode 100644
index c126d34..0000000
Binary files a/test/caps-joins-ps-argb32-ref.png and /dev/null differ
diff --git a/test/caps-sub-paths-ps-argb32-ref.png b/test/caps-sub-paths-ps-argb32-ref.png
deleted file mode 100644
index a53aad8..0000000
Binary files a/test/caps-sub-paths-ps-argb32-ref.png and /dev/null differ
diff --git a/test/close-path-ps-argb32-ref.png b/test/close-path-ps-argb32-ref.png
deleted file mode 100644
index 1f5790c..0000000
Binary files a/test/close-path-ps-argb32-ref.png and /dev/null differ
diff --git a/test/dash-offset-negative-ps-argb32-ref.png b/test/dash-offset-negative-ps-argb32-ref.png
deleted file mode 100644
index f1d56fe..0000000
Binary files a/test/dash-offset-negative-ps-argb32-ref.png and /dev/null differ
diff --git a/test/glyph-cache-pressure-ps-argb32-ref.png b/test/glyph-cache-pressure-ps-argb32-ref.png
deleted file mode 100644
index e51bca7..0000000
Binary files a/test/glyph-cache-pressure-ps-argb32-ref.png and /dev/null differ
diff --git a/test/infinite-join-ps-argb32-ref.png b/test/infinite-join-ps-argb32-ref.png
deleted file mode 100644
index 1db6622..0000000
Binary files a/test/infinite-join-ps-argb32-ref.png and /dev/null differ
diff --git a/test/leaky-polygon-ps-argb32-ref.png b/test/leaky-polygon-ps-argb32-ref.png
deleted file mode 100644
index a8ba771..0000000
Binary files a/test/leaky-polygon-ps-argb32-ref.png and /dev/null differ
diff --git a/test/line-width-ps-argb32-ref.png b/test/line-width-ps-argb32-ref.png
deleted file mode 100644
index 4c64e6c..0000000
Binary files a/test/line-width-ps-argb32-ref.png and /dev/null differ
diff --git a/test/select-font-face-ps-argb32-ref.png b/test/select-font-face-ps-argb32-ref.png
deleted file mode 100644
index d8d84a5..0000000
Binary files a/test/select-font-face-ps-argb32-ref.png and /dev/null differ
diff --git a/test/show-text-current-point-ps-argb32-ref.png b/test/show-text-current-point-ps-argb32-ref.png
deleted file mode 100644
index e3f7e7f..0000000
Binary files a/test/show-text-current-point-ps-argb32-ref.png and /dev/null differ
diff --git a/test/transforms-ps-argb32-ref.png b/test/transforms-ps-argb32-ref.png
deleted file mode 100644
index 5d5cfa9..0000000
Binary files a/test/transforms-ps-argb32-ref.png and /dev/null differ
diff-tree 5e0818d79d13f5942485b411a04a4eebd56d36f8 (from c426e71141d75dbfd39730bf9c4847309fcd9d9e)
Author: Carl Worth <cworth at cworth.org>
Date:   Thu Dec 14 04:33:08 2006 -0800

    test: Remove svg-specific reference images no longer needed thanks to pdiff
    
    This doesn't get rid of all the SVG reference images, but it
    does clean up quite a few.

diff --git a/test/fill-and-stroke-alpha-svg-ref.png b/test/fill-and-stroke-alpha-svg-ref.png
deleted file mode 100644
index 812c897..0000000
Binary files a/test/fill-and-stroke-alpha-svg-ref.png and /dev/null differ
diff --git a/test/glyph-cache-pressure-svg-ref.png b/test/glyph-cache-pressure-svg-ref.png
deleted file mode 100644
index 6f40d60..0000000
Binary files a/test/glyph-cache-pressure-svg-ref.png and /dev/null differ
diff --git a/test/mask-ctm-svg-rgb24-ref.png b/test/mask-ctm-svg-rgb24-ref.png
deleted file mode 100644
index 90628a6..0000000
Binary files a/test/mask-ctm-svg-rgb24-ref.png and /dev/null differ
diff --git a/test/mask-surface-ctm-svg-rgb24-ref.png b/test/mask-surface-ctm-svg-rgb24-ref.png
deleted file mode 100644
index 90628a6..0000000
Binary files a/test/mask-surface-ctm-svg-rgb24-ref.png and /dev/null differ
diff --git a/test/push-group-svg-rgb24-ref.png b/test/push-group-svg-rgb24-ref.png
deleted file mode 100644
index 5a0a59c..0000000
Binary files a/test/push-group-svg-rgb24-ref.png and /dev/null differ
diff --git a/test/select-font-face-svg-ref.png b/test/select-font-face-svg-ref.png
deleted file mode 100644
index e2e93b5..0000000
Binary files a/test/select-font-face-svg-ref.png and /dev/null differ
diff --git a/test/set-source-svg-rgb24-ref.png b/test/set-source-svg-rgb24-ref.png
deleted file mode 100644
index 802147f..0000000
Binary files a/test/set-source-svg-rgb24-ref.png and /dev/null differ
diff --git a/test/show-text-current-point-svg-ref.png b/test/show-text-current-point-svg-ref.png
deleted file mode 100644
index 2c4bcd7..0000000
Binary files a/test/show-text-current-point-svg-ref.png and /dev/null differ
diff --git a/test/trap-clip-svg-rgb24-ref.png b/test/trap-clip-svg-rgb24-ref.png
deleted file mode 100644
index 46a9200..0000000
Binary files a/test/trap-clip-svg-rgb24-ref.png and /dev/null differ
diff-tree c426e71141d75dbfd39730bf9c4847309fcd9d9e (from 305cbd8e71a2d21a2c71ed2c382daa5bfcec3992)
Author: Carl Worth <cworth at cworth.org>
Date:   Thu Dec 14 04:17:07 2006 -0800

    Hook up pdiff to the test suite now that its written in C

diff --git a/test/Makefile.am b/test/Makefile.am
index 26f28b5..11d414b 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -392,6 +392,7 @@ SUPPORT_PROGS =
 INCLUDES =					\
 	-D_GNU_SOURCE				\
 	-I$(srcdir)				\
+	-I$(srcdir)/pdiff			\
 	-I$(top_srcdir)/boilerplate		\
 	-I$(top_srcdir)/pixman/src		\
 	-I$(top_srcdir)/src			\
@@ -407,6 +408,7 @@ libcairotest_la_SOURCES =\
 	cairo-test.h
 
 LDADD = libcairotest.la \
+	$(top_builddir)/test/pdiff/libpdiff.la \
         $(top_builddir)/boilerplate/libcairoboilerplate.la \
 	$(top_builddir)/src/libcairo.la
 
diff --git a/test/buffer-diff.c b/test/buffer-diff.c
index 99501bc..e4324ff 100644
--- a/test/buffer-diff.c
+++ b/test/buffer-diff.c
@@ -38,6 +38,7 @@
 
 #include "cairo-test.h"
 
+#include "pdiff.h"
 #include "buffer-diff.h"
 #include "xmalloc.h"
 
@@ -122,6 +123,18 @@ compare_surfaces (cairo_surface_t	*surfa
 		  cairo_surface_t	*surface_diff,
 		  buffer_diff_result_t	*result)
 {
+    /* These default values were taken straight from the
+     * perceptualdiff program. We'll probably want to tune these as
+     * necessary. */
+    double gamma = 2.2;
+    double luminance = 100.0;
+    double field_of_view = 45.0;
+    int discernible_pixels_changed;
+
+    /* First, we run cairo's old buffer_diff algorithm which looks for
+     * pixel-perfect images, (we do this first since the test suite
+     * runs about 3x slower if we run pdiff_compare first).
+     */
     buffer_diff_core (cairo_image_surface_get_data (surface_a),
 		      cairo_image_surface_get_data (surface_b),
 		      cairo_image_surface_get_data (surface_diff),
@@ -130,6 +143,23 @@ compare_surfaces (cairo_surface_t	*surfa
 		      cairo_image_surface_get_stride (surface_a),
 		      0xffffffff,
 		      result);
+    if (result->pixels_changed == 0)
+	return;
+
+    cairo_test_log ("%d pixels differ (with maximum difference of %d) from reference image\n",
+		    result->pixels_changed, result->max_diff);
+
+    /* Then, if there are any different pixels, we give the pdiff code
+     * a crack at the images. If it decides that there are no visually
+     * discernible differences in any pixels, then we accept this
+     * result as good enough. */
+    discernible_pixels_changed = pdiff_compare (surface_a, surface_b,
+						gamma, luminance, field_of_view);
+    if (discernible_pixels_changed == 0) {
+	result->pixels_changed = 0;
+	cairo_test_log ("But perceptual diff finds no visually discernible difference.\n"
+			"Accepting result.\n");
+    }
 }
 
 void
diff --git a/test/cairo-test.c b/test/cairo-test.c
index ea8f2ac..498eb8e 100755
--- a/test/cairo-test.c
+++ b/test/cairo-test.c
@@ -313,6 +313,8 @@ cairo_test_for_target (cairo_test_t			 *
 	    goto UNWIND_CAIRO;
 	}
 
+	cairo_test_log ("Comparing result against reference image: %s\n", ref_name);
+
 	if (target->content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED) {
 	    diff_status= image_diff_flattened (png_name, ref_name, diff_name,
 					       dev_offset, dev_offset, 0, 0, &result);
@@ -326,13 +328,9 @@ cairo_test_for_target (cairo_test_t			 *
 	    ret = CAIRO_TEST_FAILURE;
 	    goto UNWIND_CAIRO;
 	}
-	if (result.pixels_changed) {
-	    cairo_test_log ("%d pixels differ (with maximum difference of %d) from reference image %s\n",
-			    result.pixels_changed, result.max_diff, ref_name);
-	    if (result.max_diff > target->error_tolerance) {
-		ret = CAIRO_TEST_FAILURE;
-		goto UNWIND_CAIRO;
-	    }
+	if (result.pixels_changed && result.max_diff > target->error_tolerance) {
+	    ret = CAIRO_TEST_FAILURE;
+	    goto UNWIND_CAIRO;
 	}
     }
 
diff-tree 305cbd8e71a2d21a2c71ed2c382daa5bfcec3992 (from f175b23559f3ba759d222538fd28922c1cbe2196)
Author: Carl Worth <cworth at cworth.org>
Date:   Thu Dec 14 04:14:24 2006 -0800

    pdiff: Remove casts since we're out of the land of X++ where void* is stupidly broken

diff --git a/test/pdiff/lpyramid.c b/test/pdiff/lpyramid.c
index 92915ab..de72d8e 100644
--- a/test/pdiff/lpyramid.c
+++ b/test/pdiff/lpyramid.c
@@ -65,8 +65,7 @@ lpyramid_create (float *image, int width
     lpyramid_t *pyramid;
     int i;
 
-    /* XXX: Remove stupid cast after finishing port to C */
-    pyramid = (lpyramid_t *) malloc (sizeof (lpyramid_t));
+    pyramid = malloc (sizeof (lpyramid_t));
     if (pyramid == NULL) {
 	fprintf (stderr, "Out of memory.\n");
 	exit (1);
@@ -77,8 +76,7 @@ lpyramid_create (float *image, int width
     /* Make the Laplacian pyramid by successively
      * copying the earlier levels and blurring them */
     for (i=0; i<MAX_PYR_LEVELS; i++) {
-	/* XXX: Remove stupid cast after finishing port to C */
-	pyramid->levels[i] = (float *) malloc (width * height * sizeof (float));
+	pyramid->levels[i] = malloc (width * height * sizeof (float));
 	if (pyramid->levels[i] == NULL) {
 	    fprintf (stderr, "Out of memory.\n");
 	    exit (1);
diff-tree f175b23559f3ba759d222538fd28922c1cbe2196 (from 18a4fa448fcdb6a72f427e997ee2b234f96a56f7)
Author: Carl Worth <cworth at cworth.org>
Date:   Thu Dec 14 03:49:31 2006 -0800

    pdiff: Rename everything to .c and fix an last littele C++ isms.
    
    The only things we had missed were a few new/delete pairs, and some
    obvious header file fixups, (like not doing <string>).

diff --git a/test/pdiff/CompareArgs.cpp b/test/pdiff/CompareArgs.cpp
deleted file mode 100644
index 3b58ff7..0000000
--- a/test/pdiff/CompareArgs.cpp
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
-  Comapre Args
-  Copyright (C) 2006 Yangli Hector Yee
-
-  This program is free software; you can redistribute it and/or modify it under the terms of the
-  GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
-  or (at your option) any later version.
-
-  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
-  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-  See the GNU General Public License for more details.
-
-  You should have received a copy of the GNU General Public License along with this program;
-  if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "CompareArgs.h"
-#include <stdio.h>
-
-static const char* copyright =
-"PerceptualDiff version 1.0, Copyright (C) 2006 Yangli Hector Yee\n\
-PerceptualDiff comes with ABSOLUTELY NO WARRANTY;\n\
-This is free software, and you are welcome\n\
-to redistribute it under certain conditions;\n\
-See the GPL page for details: http://www.gnu.org/copyleft/gpl.html\n\n";
-
-static const char *usage =
-"PeceptualDiff image1.tif image2.tif\n\n\
-   Compares image1.tif and image2.tif using a perceptually based image metric\n\
-   Options:\n\
-\t-verbose       : Turns on verbose mode\n\
-\t-fov deg       : Field of view in degrees (0.1 to 89.9)\n\
-\t-threshold p	 : #pixels p below which differences are ignored\n\
-\t-gamma g       : Value to convert rgb into linear space (default 2.2)\n\
-\t-luminance l   : White luminance (default 100.0 cdm^-2)\n\
-\n\
-\n Note: Input files can also be in the PNG format\
-\n";
-
-CompareArgs::CompareArgs()
-{
-    surface_a = NULL;
-    surface_b = NULL;
-    Verbose = false;
-    FieldOfView = 45.0f;
-    Gamma = 2.2f;
-    ThresholdPixels = 100;
-    Luminance = 100.0f;
-}
-
-CompareArgs::~CompareArgs()
-{
-    cairo_surface_destroy (surface_a);
-    cairo_surface_destroy (surface_b);
-}
-
-bool CompareArgs::Parse_Args(int argc, char **argv)
-{
-    int i;
-
-    if (argc < 3) {
-	fprintf (stderr, "%s", copyright);
-	fprintf (stderr, "%s", usage);
-	return false;
-    }
-    for (i = 0; i < argc; i++) {
-	if (i == 1) {
-	    surface_a = cairo_image_surface_create_from_png (argv[1]);
-	    if (cairo_surface_status (surface_a))
-	    {
-		fprintf (stderr, "FAIL: Cannot open %s: %s\n",
-			 argv[1], cairo_status_to_string (cairo_surface_status (surface_a)));
-		return false;
-	    }
-	} else if (i == 2) {
-	    surface_b = cairo_image_surface_create_from_png (argv[2]);
-	    if (cairo_surface_status (surface_b))
-	    {
-		fprintf (stderr, "FAIL: Cannot open %s: %s\n",
-			 argv[2], cairo_status_to_string (cairo_surface_status (surface_b)));
-		return false;
-	    }
-	} else {
-	    if (strstr(argv[i], "-fov")) {
-		if (i + 1 < argc) {
-		    FieldOfView = (float) atof(argv[i + 1]);
-		}
-	    } else if (strstr(argv[i], "-verbose")) {
-		Verbose = true;
-	    } else 	if (strstr(argv[i], "-threshold")) {
-		if (i + 1 < argc) {
-		    ThresholdPixels = atoi(argv[i + 1]);
-		}
-	    } else 	if (strstr(argv[i], "-gamma")) {
-		if (i + 1 < argc) {
-		    Gamma = (float) atof(argv[i + 1]);
-		}
-	    }else 	if (strstr(argv[i], "-luminance")) {
-		if (i + 1 < argc) {
-		    Luminance = (float) atof(argv[i + 1]);
-		}
-	    }
-	}
-    } /* i */
-    return true;
-}
-
-void CompareArgs::Print_Args()
-{
-    printf("Field of view is %f degrees\n", FieldOfView);
-    printf("Threshold pixels is %d pixels\n", ThresholdPixels);
-    printf("The Gamma is %f\n", Gamma);
-    printf("The Display's luminance is %f candela per meter squared\n", Luminance);
-}
diff --git a/test/pdiff/Makefile.am b/test/pdiff/Makefile.am
index f53c8d2..d72b273 100644
--- a/test/pdiff/Makefile.am
+++ b/test/pdiff/Makefile.am
@@ -5,12 +5,12 @@ libpdiff_la_SOURCES = 		\
 	pdiff.h			\
 	lpyramid.c		\
 	lpyramid.h		\
-	pdiff.cpp
+	pdiff.c
 
 perceptualdiff_SOURCES =	\
-	args.cpp		\
+	args.c			\
 	args.h			\
-	PerceptualDiff.cpp
+	perceptualdiff.c
 
 INCLUDES = -I$(top_srcdir)/src
 LDADD = libpdiff.la $(top_builddir)/src/libcairo.la
diff --git a/test/pdiff/PerceptualDiff.cpp b/test/pdiff/PerceptualDiff.cpp
deleted file mode 100644
index 1df3614..0000000
--- a/test/pdiff/PerceptualDiff.cpp
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
-  PerceptualDiff - a program that compares two images using a perceptual metric
-  based on the paper :
-  A perceptual metric for production testing. Journal of graphics tools, 9(4):33-40, 2004, Hector Yee
-  Copyright (C) 2006 Yangli Hector Yee
-
-  This program is free software; you can redistribute it and/or modify it under the terms of the
-  GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
-  or (at your option) any later version.
-
-  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
-  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-  See the GNU General Public License for more details.
-
-  You should have received a copy of the GNU General Public License along with this program;
-  if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include <stdio.h>
-#include <string.h>
-#include <math.h>
-#include <string>
-#include "lpyramid.h"
-#include "args.h"
-#include "pdiff.h"
-
-static bool Yee_Compare(args_t *args)
-{
-    int width_a, height_a, stride_a;
-    unsigned char *data_a, *row_a;
-    uint32_t *pixel_a;
-    int width_b, height_b, stride_b;
-    unsigned char *data_b, *row_b;
-    uint32_t *pixel_b;
-    unsigned int x, y, dim, pixels_failed;
-    bool identical = true;
-
-    width_a = cairo_image_surface_get_width (args->surface_a);
-    height_a = cairo_image_surface_get_height (args->surface_a);
-    stride_a = cairo_image_surface_get_stride (args->surface_a);
-    data_a = cairo_image_surface_get_data (args->surface_a);
-
-    width_b = cairo_image_surface_get_width (args->surface_b);
-    height_b = cairo_image_surface_get_height (args->surface_b);
-    stride_b = cairo_image_surface_get_stride (args->surface_b);
-    data_b = cairo_image_surface_get_data (args->surface_b);
-
-    if ((width_a != width_b) || (height_a != height_b)) {
-	printf ("FAIL: Image dimensions do not match\n");
-	return false;
-    }
-
-    identical = true;
-
-    for (y = 0; y < height_a; y++) {
-	row_a = data_a + y * stride_a;
-	row_b = data_b + y * stride_b;
-	pixel_a = (uint32_t *) row_a;
-	pixel_b = (uint32_t *) row_b;
-	for (x = 0; x < width_a; x++) {
-	    if (*pixel_a != *pixel_b) {
-		identical = false;
-	    }
-	    pixel_a++;
-	    pixel_b++;
-	}
-    }
-    if (identical) {
-	printf ("PASS: Images are binary identical\n");
-	return true;
-    }
-
-    pixels_failed = pdiff_compare (args->surface_a, args->surface_b,
-				   args->Gamma, args->Luminance,
-				   args->FieldOfView);
-
-    if (pixels_failed < args->ThresholdPixels) {
-	printf ("PASS: Images are perceptually indistinguishable\n");
-	return true;
-    }
-
-    printf("FAIL: Images are visibly different\n"
-	   "%d pixels are different\n", pixels_failed);
-
-    return false;
-}
-
-int main(int argc, char **argv)
-{
-    args_t args;
-
-    args_init (&args);
-
-    if (!args_parse (&args, argc, argv)) {
-	return -1;
-    } else {
-	if (args.Verbose)
-	    args_print (&args);
-    }
-    return ! Yee_Compare(&args);
-}
diff --git a/test/pdiff/args.c b/test/pdiff/args.c
new file mode 100644
index 0000000..0dfbea5
--- /dev/null
+++ b/test/pdiff/args.c
@@ -0,0 +1,119 @@
+/*
+  Comapre Args
+  Copyright (C) 2006 Yangli Hector Yee
+
+  This program is free software; you can redistribute it and/or modify it under the terms of the
+  GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License along with this program;
+  if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "args.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static const char* copyright =
+"PerceptualDiff version 1.0, Copyright (C) 2006 Yangli Hector Yee\n\
+PerceptualDiff comes with ABSOLUTELY NO WARRANTY;\n\
+This is free software, and you are welcome\n\
+to redistribute it under certain conditions;\n\
+See the GPL page for details: http://www.gnu.org/copyleft/gpl.html\n\n";
+
+static const char *usage =
+"PeceptualDiff image1.tif image2.tif\n\n\
+   Compares image1.tif and image2.tif using a perceptually based image metric\n\
+   Options:\n\
+\t-verbose       : Turns on verbose mode\n\
+\t-fov deg       : Field of view in degrees (0.1 to 89.9)\n\
+\t-threshold p	 : #pixels p below which differences are ignored\n\
+\t-gamma g       : Value to convert rgb into linear space (default 2.2)\n\
+\t-luminance l   : White luminance (default 100.0 cdm^-2)\n\
+\n\
+\n Note: Input files can also be in the PNG format\
+\n";
+
+void
+args_init (args_t *args)
+{
+    args->surface_a = NULL;
+    args->surface_b = NULL;
+    args->Verbose = false;
+    args->FieldOfView = 45.0f;
+    args->Gamma = 2.2f;
+    args->ThresholdPixels = 100;
+    args->Luminance = 100.0f;
+}
+
+void
+args_fini (args_t *args)
+{
+    cairo_surface_destroy (args->surface_a);
+    cairo_surface_destroy (args->surface_b);
+}
+
+bool
+args_parse (args_t *args, int argc, char **argv)
+{
+    int i;
+    if (argc < 3) {
+	fprintf (stderr, "%s", copyright);
+	fprintf (stderr, "%s", usage);
+	return false;
+    }
+    for (i = 0; i < argc; i++) {
+	if (i == 1) {
+	    args->surface_a = cairo_image_surface_create_from_png (argv[1]);
+	    if (cairo_surface_status (args->surface_a))
+	    {
+		fprintf (stderr, "FAIL: Cannot open %s: %s\n",
+			 argv[1], cairo_status_to_string (cairo_surface_status (args->surface_a)));
+		return false;
+	    }
+	} else if (i == 2) {
+	    args->surface_b = cairo_image_surface_create_from_png (argv[2]);
+	    if (cairo_surface_status (args->surface_b))
+	    {
+		fprintf (stderr, "FAIL: Cannot open %s: %s\n",
+			 argv[2], cairo_status_to_string (cairo_surface_status (args->surface_b)));
+		return false;
+	    }
+	} else {
+	    if (strstr(argv[i], "-fov")) {
+		if (i + 1 < argc) {
+		    args->FieldOfView = (float) atof(argv[i + 1]);
+		}
+	    } else if (strstr(argv[i], "-verbose")) {
+		args->Verbose = true;
+	    } else 	if (strstr(argv[i], "-threshold")) {
+		if (i + 1 < argc) {
+		    args->ThresholdPixels = atoi(argv[i + 1]);
+		}
+	    } else 	if (strstr(argv[i], "-gamma")) {
+		if (i + 1 < argc) {
+		    args->Gamma = (float) atof(argv[i + 1]);
+		}
+	    }else 	if (strstr(argv[i], "-luminance")) {
+		if (i + 1 < argc) {
+		    args->Luminance = (float) atof(argv[i + 1]);
+		}
+	    }
+	}
+    } /* i */
+    return true;
+}
+
+void
+args_print (args_t *args)
+{
+    printf("Field of view is %f degrees\n", args->FieldOfView);
+    printf("Threshold pixels is %d pixels\n", args->ThresholdPixels);
+    printf("The Gamma is %f\n", args->Gamma);
+    printf("The Display's luminance is %f candela per meter squared\n", args->Luminance);
+}
diff --git a/test/pdiff/args.cpp b/test/pdiff/args.cpp
deleted file mode 100644
index 9fbe23e..0000000
--- a/test/pdiff/args.cpp
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
-  Comapre Args
-  Copyright (C) 2006 Yangli Hector Yee
-
-  This program is free software; you can redistribute it and/or modify it under the terms of the
-  GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
-  or (at your option) any later version.
-
-  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
-  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-  See the GNU General Public License for more details.
-
-  You should have received a copy of the GNU General Public License along with this program;
-  if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "args.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-static const char* copyright =
-"PerceptualDiff version 1.0, Copyright (C) 2006 Yangli Hector Yee\n\
-PerceptualDiff comes with ABSOLUTELY NO WARRANTY;\n\
-This is free software, and you are welcome\n\
-to redistribute it under certain conditions;\n\
-See the GPL page for details: http://www.gnu.org/copyleft/gpl.html\n\n";
-
-static const char *usage =
-"PeceptualDiff image1.tif image2.tif\n\n\
-   Compares image1.tif and image2.tif using a perceptually based image metric\n\
-   Options:\n\
-\t-verbose       : Turns on verbose mode\n\
-\t-fov deg       : Field of view in degrees (0.1 to 89.9)\n\
-\t-threshold p	 : #pixels p below which differences are ignored\n\
-\t-gamma g       : Value to convert rgb into linear space (default 2.2)\n\
-\t-luminance l   : White luminance (default 100.0 cdm^-2)\n\
-\n\
-\n Note: Input files can also be in the PNG format\
-\n";
-
-void
-args_init (args_t *args)
-{
-    args->surface_a = NULL;
-    args->surface_b = NULL;
-    args->Verbose = false;
-    args->FieldOfView = 45.0f;
-    args->Gamma = 2.2f;
-    args->ThresholdPixels = 100;
-    args->Luminance = 100.0f;
-}
-
-void
-args_fini (args_t *args)
-{
-    cairo_surface_destroy (args->surface_a);
-    cairo_surface_destroy (args->surface_b);
-}
-
-bool
-args_parse (args_t *args, int argc, char **argv)
-{
-    if (argc < 3) {
-	fprintf (stderr, "%s", copyright);
-	fprintf (stderr, "%s", usage);
-	return false;
-    }
-    for (int i = 0; i < argc; i++) {
-	if (i == 1) {
-	    args->surface_a = cairo_image_surface_create_from_png (argv[1]);
-	    if (cairo_surface_status (args->surface_a))
-	    {
-		fprintf (stderr, "FAIL: Cannot open %s: %s\n",
-			 argv[1], cairo_status_to_string (cairo_surface_status (args->surface_a)));
-		return false;
-	    }
-	} else if (i == 2) {
-	    args->surface_b = cairo_image_surface_create_from_png (argv[2]);
-	    if (cairo_surface_status (args->surface_b))
-	    {
-		fprintf (stderr, "FAIL: Cannot open %s: %s\n",
-			 argv[2], cairo_status_to_string (cairo_surface_status (args->surface_b)));
-		return false;
-	    }
-	} else {
-	    if (strstr(argv[i], "-fov")) {
-		if (i + 1 < argc) {
-		    args->FieldOfView = (float) atof(argv[i + 1]);
-		}
-	    } else if (strstr(argv[i], "-verbose")) {
-		args->Verbose = true;
-	    } else 	if (strstr(argv[i], "-threshold")) {
-		if (i + 1 < argc) {
-		    args->ThresholdPixels = atoi(argv[i + 1]);
-		}
-	    } else 	if (strstr(argv[i], "-gamma")) {
-		if (i + 1 < argc) {
-		    args->Gamma = (float) atof(argv[i + 1]);
-		}
-	    }else 	if (strstr(argv[i], "-luminance")) {
-		if (i + 1 < argc) {
-		    args->Luminance = (float) atof(argv[i + 1]);
-		}
-	    }
-	}
-    } /* i */
-    return true;
-}
-
-void
-args_print (args_t *args)
-{
-    printf("Field of view is %f degrees\n", args->FieldOfView);
-    printf("Threshold pixels is %d pixels\n", args->ThresholdPixels);
-    printf("The Gamma is %f\n", args->Gamma);
-    printf("The Display's luminance is %f candela per meter squared\n", args->Luminance);
-}
diff --git a/test/pdiff/args.h b/test/pdiff/args.h
index 0197c90..aa6cf29 100644
--- a/test/pdiff/args.h
+++ b/test/pdiff/args.h
@@ -17,7 +17,7 @@
 #ifndef _ARGS_H
 #define _ARGS_H
 
-#include <cairo.h>
+#include "pdiff.h"
 
 /* Args to pass into the comparison function */
 typedef struct _args
diff --git a/test/pdiff/lpyramid.c b/test/pdiff/lpyramid.c
new file mode 100644
index 0000000..92915ab
--- /dev/null
+++ b/test/pdiff/lpyramid.c
@@ -0,0 +1,113 @@
+/*
+  Laplacian Pyramid
+  Copyright (C) 2006 Yangli Hector Yee
+
+  This program is free software; you can redistribute it and/or modify it under the terms of the
+  GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License along with this program;
+  if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "lpyramid.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct _lpyramid {
+    /* Succesively blurred versions of the original image */
+    float *levels[MAX_PYR_LEVELS];
+
+    int width;
+    int height;
+};
+
+static void
+convolve (lpyramid_t *pyramid, float *a, float *b)
+/* convolves image b with the filter kernel and stores it in a */
+{
+    int y,x,i,j,nx,ny;
+    const float Kernel[] = {0.05f, 0.25f, 0.4f, 0.25f, 0.05f};
+    int width = pyramid->width;
+    int height = pyramid->height;
+
+    for (y=0; y<height; y++) {
+	for (x=0; x<width; x++) {
+	    int index = y * width + x;
+	    a[index] = 0.0f;
+	    for (i=-2; i<=2; i++) {
+		for (j=-2; j<=2; j++) {
+		    nx=x+i;
+		    ny=y+j;
+		    if (nx<0) nx=-nx;
+		    if (ny<0) ny=-ny;
+		    if (nx>=width) nx=2*(width-1)-nx;
+		    if (ny>=height) ny=2*(height-1)-ny;
+		    a[index] += Kernel[i+2] * Kernel[j+2] * b[ny * width + nx];
+		}
+	    }
+	}
+    }
+}
+
+/*
+ * Construction/Destruction
+ */
+
+lpyramid_t *
+lpyramid_create (float *image, int width, int height)
+{
+    lpyramid_t *pyramid;
+    int i;
+
+    /* XXX: Remove stupid cast after finishing port to C */
+    pyramid = (lpyramid_t *) malloc (sizeof (lpyramid_t));
+    if (pyramid == NULL) {
+	fprintf (stderr, "Out of memory.\n");
+	exit (1);
+    }
+    pyramid->width = width;
+    pyramid->height = height;
+
+    /* Make the Laplacian pyramid by successively
+     * copying the earlier levels and blurring them */
+    for (i=0; i<MAX_PYR_LEVELS; i++) {
+	/* XXX: Remove stupid cast after finishing port to C */
+	pyramid->levels[i] = (float *) malloc (width * height * sizeof (float));
+	if (pyramid->levels[i] == NULL) {
+	    fprintf (stderr, "Out of memory.\n");
+	    exit (1);
+	}
+	if (i == 0) {
+	    memcpy (pyramid->levels[i], image, width * height * sizeof (float));
+	} else {
+	    convolve(pyramid, pyramid->levels[i], pyramid->levels[i - 1]);
+	}
+    }
+
+    return pyramid;
+}
+
+void
+lpyramid_destroy (lpyramid_t *pyramid)
+{
+    int i;
+
+    for (i=0; i<MAX_PYR_LEVELS; i++)
+	free (pyramid->levels[i]);
+}
+
+float
+lpyramid_get_value (lpyramid_t *pyramid, int x, int y, int level)
+{
+    int index = x + y * pyramid->width;
+    int l = level;
+    if (l > MAX_PYR_LEVELS)
+	l = MAX_PYR_LEVELS;
+    return pyramid->levels[level][index];
+}
diff --git a/test/pdiff/lpyramid.cpp b/test/pdiff/lpyramid.cpp
deleted file mode 100644
index 92915ab..0000000
--- a/test/pdiff/lpyramid.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
-  Laplacian Pyramid
-  Copyright (C) 2006 Yangli Hector Yee
-
-  This program is free software; you can redistribute it and/or modify it under the terms of the
-  GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
-  or (at your option) any later version.
-
-  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
-  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-  See the GNU General Public License for more details.
-
-  You should have received a copy of the GNU General Public License along with this program;
-  if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "lpyramid.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-struct _lpyramid {
-    /* Succesively blurred versions of the original image */
-    float *levels[MAX_PYR_LEVELS];
-
-    int width;
-    int height;
-};
-
-static void
-convolve (lpyramid_t *pyramid, float *a, float *b)
-/* convolves image b with the filter kernel and stores it in a */
-{
-    int y,x,i,j,nx,ny;
-    const float Kernel[] = {0.05f, 0.25f, 0.4f, 0.25f, 0.05f};
-    int width = pyramid->width;
-    int height = pyramid->height;
-
-    for (y=0; y<height; y++) {
-	for (x=0; x<width; x++) {
-	    int index = y * width + x;
-	    a[index] = 0.0f;
-	    for (i=-2; i<=2; i++) {
-		for (j=-2; j<=2; j++) {
-		    nx=x+i;
-		    ny=y+j;
-		    if (nx<0) nx=-nx;
-		    if (ny<0) ny=-ny;
-		    if (nx>=width) nx=2*(width-1)-nx;
-		    if (ny>=height) ny=2*(height-1)-ny;
-		    a[index] += Kernel[i+2] * Kernel[j+2] * b[ny * width + nx];
-		}
-	    }
-	}
-    }
-}
-
-/*
- * Construction/Destruction
- */
-
-lpyramid_t *
-lpyramid_create (float *image, int width, int height)
-{
-    lpyramid_t *pyramid;
-    int i;
-
-    /* XXX: Remove stupid cast after finishing port to C */
-    pyramid = (lpyramid_t *) malloc (sizeof (lpyramid_t));
-    if (pyramid == NULL) {
-	fprintf (stderr, "Out of memory.\n");
-	exit (1);
-    }
-    pyramid->width = width;
-    pyramid->height = height;
-
-    /* Make the Laplacian pyramid by successively
-     * copying the earlier levels and blurring them */
-    for (i=0; i<MAX_PYR_LEVELS; i++) {
-	/* XXX: Remove stupid cast after finishing port to C */
-	pyramid->levels[i] = (float *) malloc (width * height * sizeof (float));
-	if (pyramid->levels[i] == NULL) {
-	    fprintf (stderr, "Out of memory.\n");
-	    exit (1);
-	}
-	if (i == 0) {
-	    memcpy (pyramid->levels[i], image, width * height * sizeof (float));
-	} else {
-	    convolve(pyramid, pyramid->levels[i], pyramid->levels[i - 1]);
-	}
-    }
-
-    return pyramid;
-}
-
-void
-lpyramid_destroy (lpyramid_t *pyramid)
-{
-    int i;
-
-    for (i=0; i<MAX_PYR_LEVELS; i++)
-	free (pyramid->levels[i]);
-}
-
-float
-lpyramid_get_value (lpyramid_t *pyramid, int x, int y, int level)
-{
-    int index = x + y * pyramid->width;
-    int l = level;
-    if (l > MAX_PYR_LEVELS)
-	l = MAX_PYR_LEVELS;
-    return pyramid->levels[level][index];
-}
diff --git a/test/pdiff/pdiff.c b/test/pdiff/pdiff.c
new file mode 100644
index 0000000..1b73e79
--- /dev/null
+++ b/test/pdiff/pdiff.c
@@ -0,0 +1,361 @@
+/*
+  Metric
+  Copyright (C) 2006 Yangli Hector Yee
+
+  This program is free software; you can redistribute it and/or modify it under the terms of the
+  GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License along with this program;
+  if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "lpyramid.h"
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include "pdiff.h"
+
+#ifndef M_PI
+#define M_PI 3.14159265f
+#endif
+
+/*
+ * Given the adaptation luminance, this function returns the
+ * threshold of visibility in cd per m^2
+ * TVI means Threshold vs Intensity function
+ * This version comes from Ward Larson Siggraph 1997
+ */
+static float
+tvi (float adaptation_luminance)
+{
+    /* returns the threshold luminance given the adaptation luminance
+       units are candelas per meter squared
+    */
+    float log_a, r, result;
+    log_a = log10f(adaptation_luminance);
+
+    if (log_a < -3.94f) {
+	r = -2.86f;
+    } else if (log_a < -1.44f) {
+	r = powf(0.405f * log_a + 1.6f , 2.18f) - 2.86f;
+    } else if (log_a < -0.0184f) {
+	r = log_a - 0.395f;
+    } else if (log_a < 1.9f) {
+	r = powf(0.249f * log_a + 0.65f, 2.7f) - 0.72f;
+    } else {
+	r = log_a - 1.255f;
+    }
+
+    result = powf(10.0f , r);
+
+    return result;
+}
+
+/* computes the contrast sensitivity function (Barten SPIE 1989)
+ * given the cycles per degree (cpd) and luminance (lum)
+ */
+static float
+csf (float cpd, float lum)
+{
+    float a, b, result;
+
+    a = 440.0f * powf((1.0f + 0.7f / lum), -0.2f);
+    b = 0.3f * powf((1.0f + 100.0f / lum), 0.15f);
+
+    result = a * cpd * expf(-b * cpd) * sqrtf(1.0f + 0.06f * expf(b * cpd));
+
+    return result;
+}
+
+/*
+ * Visual Masking Function
+ * from Daly 1993
+ */
+static float
+mask (float contrast)
+{
+    float a, b, result;
+    a = powf(392.498f * contrast,  0.7f);
+    b = powf(0.0153f * a, 4.0f);
+    result = powf(1.0f + b, 0.25f);
+
+    return result;
+}
+
+/* convert Adobe RGB (1998) with reference white D65 to XYZ */
+static void
+AdobeRGBToXYZ (float r, float g, float b, float *x, float *y, float *z)
+{
+    /* matrix is from http://www.brucelindbloom.com/ */
+    *x = r * 0.576700f + g * 0.185556f + b * 0.188212f;
+    *y = r * 0.297361f + g * 0.627355f + b * 0.0752847f;
+    *z = r * 0.0270328f + g * 0.0706879f + b * 0.991248f;
+}
+
+static void
+XYZToLAB (float x, float y, float z, float *L, float *A, float *B)
+{
+    static float xw = -1;
+    static float yw;
+    static float zw;
+    const float epsilon  = 216.0f / 24389.0f;
+    const float kappa = 24389.0f / 27.0f;
+    float f[3];
+    float r[3];
+    int i;
+
+    /* reference white */
+    if (xw < 0) {
+	AdobeRGBToXYZ(1, 1, 1, &xw, &yw, &zw);
+    }
+    r[0] = x / xw;
+    r[1] = y / yw;
+    r[2] = z / zw;
+    for (i = 0; i < 3; i++) {
+	if (r[i] > epsilon) {
+	    f[i] = powf(r[i], 1.0f / 3.0f);
+	} else {
+	    f[i] = (kappa * r[i] + 16.0f) / 116.0f;
+	}
+    }
+    *L = 116.0f * f[1] - 16.0f;
+    *A = 500.0f * (f[0] - f[1]);
+    *B = 200.0f * (f[1] - f[2]);
+}
+
+static uint32_t
+_get_pixel (cairo_surface_t *surface, int i)
+{
+    uint32_t *data;
+
+    data = (uint32_t *) cairo_image_surface_get_data (surface);
+    return data[i];
+}
+
+static unsigned char
+_get_red (cairo_surface_t *surface, int i)
+{
+    uint32_t pixel;
+    uint8_t alpha;
+
+    pixel = _get_pixel (surface, i);
+
+    alpha = (pixel & 0xff000000) >> 24;
+
+    if (alpha == 0)
+	return 0;
+    else
+	return (((pixel & 0x00ff0000) >> 16) * 255 + alpha / 2) / alpha;
+}
+
+static unsigned char
+_get_green (cairo_surface_t *surface, int i)
+{
+    uint32_t pixel;
+    uint8_t alpha;
+
+    pixel = _get_pixel (surface, i);
+
+    alpha = (pixel & 0xff000000) >> 24;
+
+    if (alpha == 0)
+	return 0;
+    else
+	return (((pixel & 0x0000ff00) >> 8) * 255 + alpha / 2) / alpha;
+}
+
+static unsigned char
+_get_blue (cairo_surface_t *surface, int i)
+{
+    uint32_t pixel;
+    uint8_t alpha;
+
+    pixel = _get_pixel (surface, i);
+
+    alpha = (pixel & 0xff000000) >> 24;
+
+    if (alpha == 0)
+	return 0;
+    else
+	return (((pixel & 0x000000ff) >> 0) * 255 + alpha / 2) / alpha;
+}
+
+static void *
+xmalloc (size_t size)
+{
+    void *buf;
+
+    buf = malloc (size);
+    if (buf == NULL) {
+	fprintf (stderr, "Out of memory.\n");
+	exit (1);
+    }
+}
+
+int
+pdiff_compare (cairo_surface_t *surface_a,
+	       cairo_surface_t *surface_b,
+	       double gamma,
+	       double luminance,
+	       double field_of_view)
+{
+    unsigned int dim = (cairo_image_surface_get_width (surface_a)
+			* cairo_image_surface_get_height (surface_a));
+    unsigned int i;
+
+    /* assuming colorspaces are in Adobe RGB (1998) convert to XYZ */
+    float *aX = xmalloc (dim * sizeof (float));
+    float *aY = xmalloc (dim * sizeof (float));
+    float *aZ = xmalloc (dim * sizeof (float));
+    float *bX = xmalloc (dim * sizeof (float));
+    float *bY = xmalloc (dim * sizeof (float));
+    float *bZ = xmalloc (dim * sizeof (float));
+    float *aLum = xmalloc (dim * sizeof (float));
+    float *bLum = xmalloc (dim * sizeof (float));
+
+    float *aA = xmalloc (dim * sizeof (float));
+    float *bA = xmalloc (dim * sizeof (float));
+    float *aB = xmalloc (dim * sizeof (float));
+    float *bB = xmalloc (dim * sizeof (float));
+
+    unsigned int x, y, w, h;
+
+    lpyramid_t *la, *lb;
+
+    float num_one_degree_pixels, pixels_per_degree, num_pixels;
+    unsigned int adaptation_level;
+
+    float cpd[MAX_PYR_LEVELS];
+    float F_freq[MAX_PYR_LEVELS - 2];
+    float csf_max;
+
+    unsigned int pixels_failed;
+
+    w = cairo_image_surface_get_width (surface_a);
+    h = cairo_image_surface_get_height (surface_a);
+    for (y = 0; y < h; y++) {
+	for (x = 0; x < w; x++) {
+	    float r, g, b, l;
+	    i = x + y * w;
+	    r = powf(_get_red (surface_a, i) / 255.0f, gamma);
+	    g = powf(_get_green (surface_a, i) / 255.0f, gamma);
+	    b = powf(_get_blue (surface_a, i) / 255.0f, gamma);
+
+	    AdobeRGBToXYZ(r,g,b,&aX[i],&aY[i],&aZ[i]);
+	    XYZToLAB(aX[i], aY[i], aZ[i], &l, &aA[i], &aB[i]);
+	    r = powf(_get_red (surface_b, i) / 255.0f, gamma);
+	    g = powf(_get_green (surface_b, i) / 255.0f, gamma);
+	    b = powf(_get_blue (surface_b, i) / 255.0f, gamma);
+
+	    AdobeRGBToXYZ(r,g,b,&bX[i],&bY[i],&bZ[i]);
+	    XYZToLAB(bX[i], bY[i], bZ[i], &l, &bA[i], &bB[i]);
+	    aLum[i] = aY[i] * luminance;
+	    bLum[i] = bY[i] * luminance;
+	}
+    }
+
+    la = lpyramid_create (aLum, w, h);
+    lb = lpyramid_create (bLum, w, h);
+
+    num_one_degree_pixels = (float) (2 * tan(field_of_view * 0.5 * M_PI / 180) * 180 / M_PI);
+    pixels_per_degree = w / num_one_degree_pixels;
+
+    num_pixels = 1;
+    adaptation_level = 0;
+    for (i = 0; i < MAX_PYR_LEVELS; i++) {
+	adaptation_level = i;
+	if (num_pixels > num_one_degree_pixels) break;
+	num_pixels *= 2;
+    }
+
+    cpd[0] = 0.5f * pixels_per_degree;
+    for (i = 1; i < MAX_PYR_LEVELS; i++) cpd[i] = 0.5f * cpd[i - 1];
+    csf_max = csf(3.248f, 100.0f);
+
+    for (i = 0; i < MAX_PYR_LEVELS - 2; i++) F_freq[i] = csf_max / csf( cpd[i], 100.0f);
+
+    pixels_failed = 0;
+    for (y = 0; y < h; y++) {
+	for (x = 0; x < w; x++) {
+	    int index = x + y * w;
+	    float contrast[MAX_PYR_LEVELS - 2];
+	    float F_mask[MAX_PYR_LEVELS - 2];
+	    float factor;
+	    float delta;
+	    bool pass;
+	    float sum_contrast = 0;
+	    for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
+		float n1 = fabsf(lpyramid_get_value (la,x,y,i) - lpyramid_get_value (la,x,y,i + 1));
+		float n2 = fabsf(lpyramid_get_value (lb,x,y,i) - lpyramid_get_value (lb,x,y,i + 1));
+		float numerator = (n1 > n2) ? n1 : n2;
+		float d1 = fabsf(lpyramid_get_value(la,x,y,i+2));
+		float d2 = fabsf(lpyramid_get_value(lb,x,y,i+2));
+		float denominator = (d1 > d2) ? d1 : d2;
+		if (denominator < 1e-5f) denominator = 1e-5f;
+		contrast[i] = numerator / denominator;
+		sum_contrast += contrast[i];
+	    }
+	    if (sum_contrast < 1e-5) sum_contrast = 1e-5f;
+	    float adapt = lpyramid_get_value(la,x,y,adaptation_level) + lpyramid_get_value(lb,x,y,adaptation_level);
+	    adapt *= 0.5f;
+	    if (adapt < 1e-5) adapt = 1e-5f;
+	    for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
+		F_mask[i] = mask(contrast[i] * csf(cpd[i], adapt));
+	    }
+	    factor = 0;
+	    for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
+		factor += contrast[i] * F_freq[i] * F_mask[i] / sum_contrast;
+	    }
+	    if (factor < 1) factor = 1;
+	    if (factor > 10) factor = 10;
+	    delta = fabsf(lpyramid_get_value(la,x,y,0) - lpyramid_get_value(lb,x,y,0));
+	    pass = true;
+	    /* pure luminance test */
+	    if (delta > factor * tvi(adapt)) {
+		pass = false;
+	    } else {
+		/* CIE delta E test with modifications */
+		float color_scale = 1.0f;
+		float da = aA[index] - bA[index];
+		float db = aB[index] - bB[index];
+		float delta_e;
+		/* ramp down the color test in scotopic regions */
+		if (adapt < 10.0f) {
+		    color_scale = 1.0f - (10.0f - color_scale) / 10.0f;
+		    color_scale = color_scale * color_scale;
+		}
+		da = da * da;
+		db = db * db;
+		delta_e = (da + db) * color_scale;
+		if (delta_e > factor) {
+		    pass = false;
+		}
+	    }
+	    if (!pass)
+		pixels_failed++;
+	}
+    }
+
+    free (aX);
+    free (aY);
+    free (aZ);
+    free (bX);
+    free (bY);
+    free (bZ);
+    free (aLum);
+    free (bLum);
+    lpyramid_destroy (la);
+    lpyramid_destroy (lb);
+    free (aA);
+    free (bA);
+    free (aB);
+    free (bB);
+
+    return pixels_failed;
+}
diff --git a/test/pdiff/pdiff.cpp b/test/pdiff/pdiff.cpp
deleted file mode 100644
index 1609cda..0000000
--- a/test/pdiff/pdiff.cpp
+++ /dev/null
@@ -1,347 +0,0 @@
-/*
-  Metric
-  Copyright (C) 2006 Yangli Hector Yee
-
-  This program is free software; you can redistribute it and/or modify it under the terms of the
-  GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
-  or (at your option) any later version.
-
-  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
-  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-  See the GNU General Public License for more details.
-
-  You should have received a copy of the GNU General Public License along with this program;
-  if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "lpyramid.h"
-#include <math.h>
-#include <stdint.h>
-#include "pdiff.h"
-
-#ifndef M_PI
-#define M_PI 3.14159265f
-#endif
-
-/*
- * Given the adaptation luminance, this function returns the
- * threshold of visibility in cd per m^2
- * TVI means Threshold vs Intensity function
- * This version comes from Ward Larson Siggraph 1997
- */
-static float
-tvi (float adaptation_luminance)
-{
-    /* returns the threshold luminance given the adaptation luminance
-       units are candelas per meter squared
-    */
-    float log_a, r, result;
-    log_a = log10f(adaptation_luminance);
-
-    if (log_a < -3.94f) {
-	r = -2.86f;
-    } else if (log_a < -1.44f) {
-	r = powf(0.405f * log_a + 1.6f , 2.18f) - 2.86f;
-    } else if (log_a < -0.0184f) {
-	r = log_a - 0.395f;
-    } else if (log_a < 1.9f) {
-	r = powf(0.249f * log_a + 0.65f, 2.7f) - 0.72f;
-    } else {
-	r = log_a - 1.255f;
-    }
-
-    result = powf(10.0f , r);
-
-    return result;
-}
-
-/* computes the contrast sensitivity function (Barten SPIE 1989)
- * given the cycles per degree (cpd) and luminance (lum)
- */
-static float
-csf (float cpd, float lum)
-{
-    float a, b, result;
-
-    a = 440.0f * powf((1.0f + 0.7f / lum), -0.2f);
-    b = 0.3f * powf((1.0f + 100.0f / lum), 0.15f);
-
-    result = a * cpd * expf(-b * cpd) * sqrtf(1.0f + 0.06f * expf(b * cpd));
-
-    return result;
-}
-
-/*
- * Visual Masking Function
- * from Daly 1993
- */
-static float
-mask (float contrast)
-{
-    float a, b, result;
-    a = powf(392.498f * contrast,  0.7f);
-    b = powf(0.0153f * a, 4.0f);
-    result = powf(1.0f + b, 0.25f);
-
-    return result;
-}
-
-/* convert Adobe RGB (1998) with reference white D65 to XYZ */
-static void
-AdobeRGBToXYZ (float r, float g, float b, float *x, float *y, float *z)
-{
-    /* matrix is from http://www.brucelindbloom.com/ */
-    *x = r * 0.576700f + g * 0.185556f + b * 0.188212f;
-    *y = r * 0.297361f + g * 0.627355f + b * 0.0752847f;
-    *z = r * 0.0270328f + g * 0.0706879f + b * 0.991248f;
-}
-
-static void
-XYZToLAB (float x, float y, float z, float *L, float *A, float *B)
-{
-    static float xw = -1;
-    static float yw;
-    static float zw;
-    const float epsilon  = 216.0f / 24389.0f;
-    const float kappa = 24389.0f / 27.0f;
-    float f[3];
-    float r[3];
-    int i;
-
-    /* reference white */
-    if (xw < 0) {
-	AdobeRGBToXYZ(1, 1, 1, &xw, &yw, &zw);
-    }
-    r[0] = x / xw;
-    r[1] = y / yw;
-    r[2] = z / zw;
-    for (i = 0; i < 3; i++) {
-	if (r[i] > epsilon) {
-	    f[i] = powf(r[i], 1.0f / 3.0f);
-	} else {
-	    f[i] = (kappa * r[i] + 16.0f) / 116.0f;
-	}
-    }
-    *L = 116.0f * f[1] - 16.0f;
-    *A = 500.0f * (f[0] - f[1]);
-    *B = 200.0f * (f[1] - f[2]);
-}
-
-static uint32_t
-_get_pixel (cairo_surface_t *surface, int i)
-{
-    uint32_t *data;
-
-    data = (uint32_t *) cairo_image_surface_get_data (surface);
-    return data[i];
-}
-
-static unsigned char
-_get_red (cairo_surface_t *surface, int i)
-{
-    uint32_t pixel;
-    uint8_t alpha;
-
-    pixel = _get_pixel (surface, i);
-
-    alpha = (pixel & 0xff000000) >> 24;
-
-    if (alpha == 0)
-	return 0;
-    else
-	return (((pixel & 0x00ff0000) >> 16) * 255 + alpha / 2) / alpha;
-}
-
-static unsigned char
-_get_green (cairo_surface_t *surface, int i)
-{
-    uint32_t pixel;
-    uint8_t alpha;
-
-    pixel = _get_pixel (surface, i);
-
-    alpha = (pixel & 0xff000000) >> 24;
-
-    if (alpha == 0)
-	return 0;
-    else
-	return (((pixel & 0x0000ff00) >> 8) * 255 + alpha / 2) / alpha;
-}
-
-static unsigned char
-_get_blue (cairo_surface_t *surface, int i)
-{
-    uint32_t pixel;
-    uint8_t alpha;
-
-    pixel = _get_pixel (surface, i);
-
-    alpha = (pixel & 0xff000000) >> 24;
-
-    if (alpha == 0)
-	return 0;
-    else
-	return (((pixel & 0x000000ff) >> 0) * 255 + alpha / 2) / alpha;
-}
-
-int
-pdiff_compare (cairo_surface_t *surface_a,
-	       cairo_surface_t *surface_b,
-	       double gamma,
-	       double luminance,
-	       double field_of_view)
-{
-    unsigned int dim = (cairo_image_surface_get_width (surface_a)
-			* cairo_image_surface_get_height (surface_a));
-    unsigned int i;
-
-    /* assuming colorspaces are in Adobe RGB (1998) convert to XYZ */
-    float *aX = new float[dim];
-    float *aY = new float[dim];
-    float *aZ = new float[dim];
-    float *bX = new float[dim];
-    float *bY = new float[dim];
-    float *bZ = new float[dim];
-    float *aLum = new float[dim];
-    float *bLum = new float[dim];
-
-    float *aA = new float[dim];
-    float *bA = new float[dim];
-    float *aB = new float[dim];
-    float *bB = new float[dim];
-
-    unsigned int x, y, w, h;
-
-    lpyramid_t *la, *lb;
-
-    float num_one_degree_pixels, pixels_per_degree, num_pixels;
-    unsigned int adaptation_level;
-
-    float cpd[MAX_PYR_LEVELS];
-    float F_freq[MAX_PYR_LEVELS - 2];
-    float csf_max;
-
-    unsigned int pixels_failed;
-
-    w = cairo_image_surface_get_width (surface_a);
-    h = cairo_image_surface_get_height (surface_a);
-    for (y = 0; y < h; y++) {
-	for (x = 0; x < w; x++) {
-	    float r, g, b, l;
-	    i = x + y * w;
-	    r = powf(_get_red (surface_a, i) / 255.0f, gamma);
-	    g = powf(_get_green (surface_a, i) / 255.0f, gamma);
-	    b = powf(_get_blue (surface_a, i) / 255.0f, gamma);
-
-	    AdobeRGBToXYZ(r,g,b,&aX[i],&aY[i],&aZ[i]);
-	    XYZToLAB(aX[i], aY[i], aZ[i], &l, &aA[i], &aB[i]);
-	    r = powf(_get_red (surface_b, i) / 255.0f, gamma);
-	    g = powf(_get_green (surface_b, i) / 255.0f, gamma);
-	    b = powf(_get_blue (surface_b, i) / 255.0f, gamma);
-
-	    AdobeRGBToXYZ(r,g,b,&bX[i],&bY[i],&bZ[i]);
-	    XYZToLAB(bX[i], bY[i], bZ[i], &l, &bA[i], &bB[i]);
-	    aLum[i] = aY[i] * luminance;
-	    bLum[i] = bY[i] * luminance;
-	}
-    }
-
-    la = lpyramid_create (aLum, w, h);
-    lb = lpyramid_create (bLum, w, h);
-
-    num_one_degree_pixels = (float) (2 * tan(field_of_view * 0.5 * M_PI / 180) * 180 / M_PI);
-    pixels_per_degree = w / num_one_degree_pixels;
-
-    num_pixels = 1;
-    adaptation_level = 0;
-    for (i = 0; i < MAX_PYR_LEVELS; i++) {
-	adaptation_level = i;
-	if (num_pixels > num_one_degree_pixels) break;
-	num_pixels *= 2;
-    }
-
-    cpd[0] = 0.5f * pixels_per_degree;
-    for (i = 1; i < MAX_PYR_LEVELS; i++) cpd[i] = 0.5f * cpd[i - 1];
-    csf_max = csf(3.248f, 100.0f);
-
-    for (i = 0; i < MAX_PYR_LEVELS - 2; i++) F_freq[i] = csf_max / csf( cpd[i], 100.0f);
-
-    pixels_failed = 0;
-    for (y = 0; y < h; y++) {
-	for (x = 0; x < w; x++) {
-	    int index = x + y * w;
-	    float contrast[MAX_PYR_LEVELS - 2];
-	    float F_mask[MAX_PYR_LEVELS - 2];
-	    float factor;
-	    float delta;
-	    bool pass;
-	    float sum_contrast = 0;
-	    for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
-		float n1 = fabsf(lpyramid_get_value (la,x,y,i) - lpyramid_get_value (la,x,y,i + 1));
-		float n2 = fabsf(lpyramid_get_value (lb,x,y,i) - lpyramid_get_value (lb,x,y,i + 1));
-		float numerator = (n1 > n2) ? n1 : n2;
-		float d1 = fabsf(lpyramid_get_value(la,x,y,i+2));
-		float d2 = fabsf(lpyramid_get_value(lb,x,y,i+2));
-		float denominator = (d1 > d2) ? d1 : d2;
-		if (denominator < 1e-5f) denominator = 1e-5f;
-		contrast[i] = numerator / denominator;
-		sum_contrast += contrast[i];
-	    }
-	    if (sum_contrast < 1e-5) sum_contrast = 1e-5f;
-	    float adapt = lpyramid_get_value(la,x,y,adaptation_level) + lpyramid_get_value(lb,x,y,adaptation_level);
-	    adapt *= 0.5f;
-	    if (adapt < 1e-5) adapt = 1e-5f;
-	    for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
-		F_mask[i] = mask(contrast[i] * csf(cpd[i], adapt));
-	    }
-	    factor = 0;
-	    for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
-		factor += contrast[i] * F_freq[i] * F_mask[i] / sum_contrast;
-	    }
-	    if (factor < 1) factor = 1;
-	    if (factor > 10) factor = 10;
-	    delta = fabsf(lpyramid_get_value(la,x,y,0) - lpyramid_get_value(lb,x,y,0));
-	    pass = true;
-	    /* pure luminance test */
-	    if (delta > factor * tvi(adapt)) {
-		pass = false;
-	    } else {
-		/* CIE delta E test with modifications */
-		float color_scale = 1.0f;
-		float da = aA[index] - bA[index];
-		float db = aB[index] - bB[index];
-		float delta_e;
-		/* ramp down the color test in scotopic regions */
-		if (adapt < 10.0f) {
-		    color_scale = 1.0f - (10.0f - color_scale) / 10.0f;
-		    color_scale = color_scale * color_scale;
-		}
-		da = da * da;
-		db = db * db;
-		delta_e = (da + db) * color_scale;
-		if (delta_e > factor) {
-		    pass = false;
-		}
-	    }
-	    if (!pass)
-		pixels_failed++;
-	}
-    }
-
-    if (aX) delete[] aX;
-    if (aY) delete[] aY;
-    if (aZ) delete[] aZ;
-    if (bX) delete[] bX;
-    if (bY) delete[] bY;
-    if (bZ) delete[] bZ;
-    if (aLum) delete[] aLum;
-    if (bLum) delete[] bLum;
-    lpyramid_destroy (la);
-    lpyramid_destroy (lb);
-    if (aA) delete aA;
-    if (bA) delete bA;
-    if (aB) delete aB;
-    if (bB) delete bB;
-
-    return pixels_failed;
-}
diff --git a/test/pdiff/pdiff.h b/test/pdiff/pdiff.h
index d20ae86..b398cc6 100644
--- a/test/pdiff/pdiff.h
+++ b/test/pdiff/pdiff.h
@@ -17,12 +17,16 @@
 #ifndef _PDIFF_H
 #define _PDIFF_H
 
-#ifdef  __cplusplus
-extern "C" {
-#endif
-
 #include <cairo.h>
 
+typedef int bool;
+#ifndef true
+#define true 1
+#endif
+#ifndef false
+#define false 0
+#endif
+
 /* Image comparison metric using Yee's method (and a cairo interface)
  * References: A Perceptual Metric for Production Testing, Hector Yee, Journal of Graphics Tools 2004
  */
@@ -33,8 +37,4 @@ pdiff_compare (cairo_surface_t *surface_
 	       double luminance,
 	       double field_of_view);
 
-#ifdef  __cplusplus
-}
-#endif
-
 #endif
diff --git a/test/pdiff/perceptualdiff.c b/test/pdiff/perceptualdiff.c
new file mode 100644
index 0000000..953558e
--- /dev/null
+++ b/test/pdiff/perceptualdiff.c
@@ -0,0 +1,101 @@
+/*
+  PerceptualDiff - a program that compares two images using a perceptual metric
+  based on the paper :
+  A perceptual metric for production testing. Journal of graphics tools, 9(4):33-40, 2004, Hector Yee
+  Copyright (C) 2006 Yangli Hector Yee
+
+  This program is free software; you can redistribute it and/or modify it under the terms of the
+  GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License along with this program;
+  if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <math.h>
+#include "lpyramid.h"
+#include "args.h"
+#include "pdiff.h"
+
+static bool Yee_Compare(args_t *args)
+{
+    int width_a, height_a, stride_a;
+    unsigned char *data_a, *row_a;
+    uint32_t *pixel_a;
+    int width_b, height_b, stride_b;
+    unsigned char *data_b, *row_b;
+    uint32_t *pixel_b;
+    unsigned int x, y, dim, pixels_failed;
+    bool identical = true;
+
+    width_a = cairo_image_surface_get_width (args->surface_a);
+    height_a = cairo_image_surface_get_height (args->surface_a);
+    stride_a = cairo_image_surface_get_stride (args->surface_a);
+    data_a = cairo_image_surface_get_data (args->surface_a);
+
+    width_b = cairo_image_surface_get_width (args->surface_b);
+    height_b = cairo_image_surface_get_height (args->surface_b);
+    stride_b = cairo_image_surface_get_stride (args->surface_b);
+    data_b = cairo_image_surface_get_data (args->surface_b);
+
+    if ((width_a != width_b) || (height_a != height_b)) {
+	printf ("FAIL: Image dimensions do not match\n");
+	return false;
+    }
+
+    identical = true;
+
+    for (y = 0; y < height_a; y++) {
+	row_a = data_a + y * stride_a;
+	row_b = data_b + y * stride_b;
+	pixel_a = (uint32_t *) row_a;
+	pixel_b = (uint32_t *) row_b;
+	for (x = 0; x < width_a; x++) {
+	    if (*pixel_a != *pixel_b) {
+		identical = false;
+	    }
+	    pixel_a++;
+	    pixel_b++;
+	}
+    }
+    if (identical) {
+	printf ("PASS: Images are binary identical\n");
+	return true;
+    }
+
+    pixels_failed = pdiff_compare (args->surface_a, args->surface_b,
+				   args->Gamma, args->Luminance,
+				   args->FieldOfView);
+
+    if (pixels_failed < args->ThresholdPixels) {
+	printf ("PASS: Images are perceptually indistinguishable\n");
+	return true;
+    }
+
+    printf("FAIL: Images are visibly different\n"
+	   "%d pixels are different\n", pixels_failed);
+
+    return false;
+}
+
+int main(int argc, char **argv)
+{
+    args_t args;
+
+    args_init (&args);
+
+    if (!args_parse (&args, argc, argv)) {
+	return -1;
+    } else {
+	if (args.Verbose)
+	    args_print (&args);
+    }
+    return ! Yee_Compare(&args);
+}
diff-tree 18a4fa448fcdb6a72f427e997ee2b234f96a56f7 (from 871aba6c80b8f3101eac51cc055ad9ca26770a95)
Author: Carl Worth <cworth at cworth.org>
Date:   Thu Dec 14 03:25:51 2006 -0800

    pdiff: Replace CompareArgs class with args_t struct
    
    This gets rid of nearly the last vestiges of C++ from the pdiff code.

diff --git a/test/pdiff/CompareArgs.cpp b/test/pdiff/CompareArgs.cpp
index f33ba9f..3b58ff7 100644
--- a/test/pdiff/CompareArgs.cpp
+++ b/test/pdiff/CompareArgs.cpp
@@ -56,12 +56,14 @@ CompareArgs::~CompareArgs()
 
 bool CompareArgs::Parse_Args(int argc, char **argv)
 {
+    int i;
+
     if (argc < 3) {
 	fprintf (stderr, "%s", copyright);
 	fprintf (stderr, "%s", usage);
 	return false;
     }
-    for (int i = 0; i < argc; i++) {
+    for (i = 0; i < argc; i++) {
 	if (i == 1) {
 	    surface_a = cairo_image_surface_create_from_png (argv[1]);
 	    if (cairo_surface_status (surface_a))
diff --git a/test/pdiff/CompareArgs.h b/test/pdiff/CompareArgs.h
deleted file mode 100644
index 31cf059..0000000
--- a/test/pdiff/CompareArgs.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
-  Comapre Args
-  Copyright (C) 2006 Yangli Hector Yee
-
-  This program is free software; you can redistribute it and/or modify it under the terms of the
-  GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
-  or (at your option) any later version.
-
-  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
-  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-  See the GNU General Public License for more details.
-
-  You should have received a copy of the GNU General Public License along with this program;
-  if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#ifndef _COMPAREARGS_H
-#define _COMPAREARGS_H
-
-#include <string>
-#include <cairo.h>
-
-/* Args to pass into the comparison function */
-class CompareArgs
-{
-public:
-    CompareArgs();
-    ~CompareArgs();
-    bool Parse_Args(int argc, char **argv);
-    void Print_Args();
-
-    cairo_surface_t	*surface_a;		/* Image A */
-    cairo_surface_t	*surface_b;		/* Image B */
-    bool		Verbose;		/* Print lots of text or not */
-    float		FieldOfView;		/* Field of view in degrees */
-    float		Gamma;			/* The gamma to convert to linear color space */
-    float		Luminance;		/* the display's luminance */
-    unsigned int	ThresholdPixels;	/* How many pixels different to ignore */
-};
-
-#endif
diff --git a/test/pdiff/Makefile.am b/test/pdiff/Makefile.am
index 4d46238..f53c8d2 100644
--- a/test/pdiff/Makefile.am
+++ b/test/pdiff/Makefile.am
@@ -8,8 +8,8 @@ libpdiff_la_SOURCES = 		\
 	pdiff.cpp
 
 perceptualdiff_SOURCES =	\
-	CompareArgs.cpp		\
-	CompareArgs.h		\
+	args.cpp		\
+	args.h			\
 	PerceptualDiff.cpp
 
 INCLUDES = -I$(top_srcdir)/src
diff --git a/test/pdiff/PerceptualDiff.cpp b/test/pdiff/PerceptualDiff.cpp
index 41aea79..1df3614 100644
--- a/test/pdiff/PerceptualDiff.cpp
+++ b/test/pdiff/PerceptualDiff.cpp
@@ -21,10 +21,10 @@
 #include <math.h>
 #include <string>
 #include "lpyramid.h"
-#include "CompareArgs.h"
+#include "args.h"
 #include "pdiff.h"
 
-static bool Yee_Compare(CompareArgs &args)
+static bool Yee_Compare(args_t *args)
 {
     int width_a, height_a, stride_a;
     unsigned char *data_a, *row_a;
@@ -35,15 +35,15 @@ static bool Yee_Compare(CompareArgs &arg
     unsigned int x, y, dim, pixels_failed;
     bool identical = true;
 
-    width_a = cairo_image_surface_get_width (args.surface_a);
-    height_a = cairo_image_surface_get_height (args.surface_a);
-    stride_a = cairo_image_surface_get_stride (args.surface_a);
-    data_a = cairo_image_surface_get_data (args.surface_a);
-
-    width_b = cairo_image_surface_get_width (args.surface_b);
-    height_b = cairo_image_surface_get_height (args.surface_b);
-    stride_b = cairo_image_surface_get_stride (args.surface_b);
-    data_b = cairo_image_surface_get_data (args.surface_b);
+    width_a = cairo_image_surface_get_width (args->surface_a);
+    height_a = cairo_image_surface_get_height (args->surface_a);
+    stride_a = cairo_image_surface_get_stride (args->surface_a);
+    data_a = cairo_image_surface_get_data (args->surface_a);
+
+    width_b = cairo_image_surface_get_width (args->surface_b);
+    height_b = cairo_image_surface_get_height (args->surface_b);
+    stride_b = cairo_image_surface_get_stride (args->surface_b);
+    data_b = cairo_image_surface_get_data (args->surface_b);
 
     if ((width_a != width_b) || (height_a != height_b)) {
 	printf ("FAIL: Image dimensions do not match\n");
@@ -70,11 +70,11 @@ static bool Yee_Compare(CompareArgs &arg
 	return true;
     }
 
-    pixels_failed = pdiff_compare (args.surface_a, args.surface_b,
-				   args.Gamma, args.Luminance,
-				   args.FieldOfView);
+    pixels_failed = pdiff_compare (args->surface_a, args->surface_b,
+				   args->Gamma, args->Luminance,
+				   args->FieldOfView);
 
-    if (pixels_failed < args.ThresholdPixels) {
+    if (pixels_failed < args->ThresholdPixels) {
 	printf ("PASS: Images are perceptually indistinguishable\n");
 	return true;
     }
@@ -87,12 +87,15 @@ static bool Yee_Compare(CompareArgs &arg
 
 int main(int argc, char **argv)
 {
-    CompareArgs args;
+    args_t args;
 
-    if (!args.Parse_Args(argc, argv)) {
+    args_init (&args);
+
+    if (!args_parse (&args, argc, argv)) {
 	return -1;
     } else {
-	if (args.Verbose) args.Print_Args();
+	if (args.Verbose)
+	    args_print (&args);
     }
-    return ! Yee_Compare(args);
+    return ! Yee_Compare(&args);
 }
diff --git a/test/pdiff/args.cpp b/test/pdiff/args.cpp
new file mode 100644
index 0000000..9fbe23e
--- /dev/null
+++ b/test/pdiff/args.cpp
@@ -0,0 +1,118 @@
+/*
+  Comapre Args
+  Copyright (C) 2006 Yangli Hector Yee
+
+  This program is free software; you can redistribute it and/or modify it under the terms of the
+  GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License along with this program;
+  if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "args.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static const char* copyright =
+"PerceptualDiff version 1.0, Copyright (C) 2006 Yangli Hector Yee\n\
+PerceptualDiff comes with ABSOLUTELY NO WARRANTY;\n\
+This is free software, and you are welcome\n\
+to redistribute it under certain conditions;\n\
+See the GPL page for details: http://www.gnu.org/copyleft/gpl.html\n\n";
+
+static const char *usage =
+"PeceptualDiff image1.tif image2.tif\n\n\
+   Compares image1.tif and image2.tif using a perceptually based image metric\n\
+   Options:\n\
+\t-verbose       : Turns on verbose mode\n\
+\t-fov deg       : Field of view in degrees (0.1 to 89.9)\n\
+\t-threshold p	 : #pixels p below which differences are ignored\n\
+\t-gamma g       : Value to convert rgb into linear space (default 2.2)\n\
+\t-luminance l   : White luminance (default 100.0 cdm^-2)\n\
+\n\
+\n Note: Input files can also be in the PNG format\
+\n";
+
+void
+args_init (args_t *args)
+{
+    args->surface_a = NULL;
+    args->surface_b = NULL;
+    args->Verbose = false;
+    args->FieldOfView = 45.0f;
+    args->Gamma = 2.2f;
+    args->ThresholdPixels = 100;
+    args->Luminance = 100.0f;
+}
+
+void
+args_fini (args_t *args)
+{
+    cairo_surface_destroy (args->surface_a);
+    cairo_surface_destroy (args->surface_b);
+}
+
+bool
+args_parse (args_t *args, int argc, char **argv)
+{
+    if (argc < 3) {
+	fprintf (stderr, "%s", copyright);
+	fprintf (stderr, "%s", usage);
+	return false;
+    }
+    for (int i = 0; i < argc; i++) {
+	if (i == 1) {
+	    args->surface_a = cairo_image_surface_create_from_png (argv[1]);
+	    if (cairo_surface_status (args->surface_a))
+	    {
+		fprintf (stderr, "FAIL: Cannot open %s: %s\n",
+			 argv[1], cairo_status_to_string (cairo_surface_status (args->surface_a)));
+		return false;
+	    }
+	} else if (i == 2) {
+	    args->surface_b = cairo_image_surface_create_from_png (argv[2]);
+	    if (cairo_surface_status (args->surface_b))
+	    {
+		fprintf (stderr, "FAIL: Cannot open %s: %s\n",
+			 argv[2], cairo_status_to_string (cairo_surface_status (args->surface_b)));
+		return false;
+	    }
+	} else {
+	    if (strstr(argv[i], "-fov")) {
+		if (i + 1 < argc) {
+		    args->FieldOfView = (float) atof(argv[i + 1]);
+		}
+	    } else if (strstr(argv[i], "-verbose")) {
+		args->Verbose = true;
+	    } else 	if (strstr(argv[i], "-threshold")) {
+		if (i + 1 < argc) {
+		    args->ThresholdPixels = atoi(argv[i + 1]);
+		}
+	    } else 	if (strstr(argv[i], "-gamma")) {
+		if (i + 1 < argc) {
+		    args->Gamma = (float) atof(argv[i + 1]);
+		}
+	    }else 	if (strstr(argv[i], "-luminance")) {
+		if (i + 1 < argc) {
+		    args->Luminance = (float) atof(argv[i + 1]);
+		}
+	    }
+	}
+    } /* i */
+    return true;
+}
+
+void
+args_print (args_t *args)
+{
+    printf("Field of view is %f degrees\n", args->FieldOfView);
+    printf("Threshold pixels is %d pixels\n", args->ThresholdPixels);
+    printf("The Gamma is %f\n", args->Gamma);
+    printf("The Display's luminance is %f candela per meter squared\n", args->Luminance);
+}
diff --git a/test/pdiff/args.h b/test/pdiff/args.h
new file mode 100644
index 0000000..0197c90
--- /dev/null
+++ b/test/pdiff/args.h
@@ -0,0 +1,46 @@
+/*
+  Comapre Args
+  Copyright (C) 2006 Yangli Hector Yee
+
+  This program is free software; you can redistribute it and/or modify it under the terms of the
+  GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License along with this program;
+  if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef _ARGS_H
+#define _ARGS_H
+
+#include <cairo.h>
+
+/* Args to pass into the comparison function */
+typedef struct _args
+{
+    cairo_surface_t	*surface_a;		/* Image A */
+    cairo_surface_t	*surface_b;		/* Image B */
+    bool		Verbose;		/* Print lots of text or not */
+    float		FieldOfView;		/* Field of view in degrees */
+    float		Gamma;			/* The gamma to convert to linear color space */
+    float		Luminance;		/* the display's luminance */
+    unsigned int	ThresholdPixels;	/* How many pixels different to ignore */
+} args_t;
+
+void
+args_init (args_t *args);
+
+void
+args_fini (args_t *args);
+
+bool
+args_parse (args_t *args, int argc, char **argv);
+
+void
+args_print (args_t *args);
+
+#endif
diff-tree 871aba6c80b8f3101eac51cc055ad9ca26770a95 (from 2174ee247554feef6a24792390d858b12fd44acd)
Author: Carl Worth <cworth at cworth.org>
Date:   Thu Dec 14 03:16:18 2006 -0800

    pdiff: Fix return value from perceptualdiff program

diff --git a/test/pdiff/PerceptualDiff.cpp b/test/pdiff/PerceptualDiff.cpp
index 04b9e45..41aea79 100644
--- a/test/pdiff/PerceptualDiff.cpp
+++ b/test/pdiff/PerceptualDiff.cpp
@@ -94,6 +94,5 @@ int main(int argc, char **argv)
     } else {
 	if (args.Verbose) args.Print_Args();
     }
-    int result = Yee_Compare(args) == true;
-    return result;
+    return ! Yee_Compare(args);
 }
diff-tree 2174ee247554feef6a24792390d858b12fd44acd (from 91b156b82e0219b2b851c218813f24024cad7c69)
Author: Carl Worth <cworth at cworth.org>
Date:   Thu Dec 14 03:15:14 2006 -0800

    pdiff: Remove all uses of std::string

diff --git a/test/pdiff/CompareArgs.cpp b/test/pdiff/CompareArgs.cpp
index 265cfed..f33ba9f 100644
--- a/test/pdiff/CompareArgs.cpp
+++ b/test/pdiff/CompareArgs.cpp
@@ -57,8 +57,8 @@ CompareArgs::~CompareArgs()
 bool CompareArgs::Parse_Args(int argc, char **argv)
 {
     if (argc < 3) {
-	ErrorStr = copyright;
-	ErrorStr += usage;
+	fprintf (stderr, "%s", copyright);
+	fprintf (stderr, "%s", usage);
 	return false;
     }
     for (int i = 0; i < argc; i++) {
@@ -66,22 +66,16 @@ bool CompareArgs::Parse_Args(int argc, c
 	    surface_a = cairo_image_surface_create_from_png (argv[1]);
 	    if (cairo_surface_status (surface_a))
 	    {
-		ErrorStr = "FAIL: Cannot open ";
-		ErrorStr += argv[1];
-		ErrorStr += " ";
-		ErrorStr += cairo_status_to_string (cairo_surface_status (surface_a));
-		ErrorStr += "\n";
+		fprintf (stderr, "FAIL: Cannot open %s: %s\n",
+			 argv[1], cairo_status_to_string (cairo_surface_status (surface_a)));
 		return false;
 	    }
 	} else if (i == 2) {
 	    surface_b = cairo_image_surface_create_from_png (argv[2]);
 	    if (cairo_surface_status (surface_b))
 	    {
-		ErrorStr = "FAIL: Cannot open ";
-		ErrorStr += argv[2];
-		ErrorStr += " ";
-		ErrorStr += cairo_status_to_string (cairo_surface_status (surface_b));
-		ErrorStr += "\n";
+		fprintf (stderr, "FAIL: Cannot open %s: %s\n",
+			 argv[2], cairo_status_to_string (cairo_surface_status (surface_b)));
 		return false;
 	    }
 	} else {
diff --git a/test/pdiff/CompareArgs.h b/test/pdiff/CompareArgs.h
index ac368d5..31cf059 100644
--- a/test/pdiff/CompareArgs.h
+++ b/test/pdiff/CompareArgs.h
@@ -36,7 +36,6 @@ public:
     float		Gamma;			/* The gamma to convert to linear color space */
     float		Luminance;		/* the display's luminance */
     unsigned int	ThresholdPixels;	/* How many pixels different to ignore */
-    std::string		ErrorStr;		/* Error string */
 };
 
 #endif
diff --git a/test/pdiff/PerceptualDiff.cpp b/test/pdiff/PerceptualDiff.cpp
index 45ab7cb..04b9e45 100644
--- a/test/pdiff/PerceptualDiff.cpp
+++ b/test/pdiff/PerceptualDiff.cpp
@@ -32,6 +32,8 @@ static bool Yee_Compare(CompareArgs &arg
     int width_b, height_b, stride_b;
     unsigned char *data_b, *row_b;
     uint32_t *pixel_b;
+    unsigned int x, y, dim, pixels_failed;
+    bool identical = true;
 
     width_a = cairo_image_surface_get_width (args.surface_a);
     height_a = cairo_image_surface_get_height (args.surface_a);
@@ -44,12 +46,11 @@ static bool Yee_Compare(CompareArgs &arg
     data_b = cairo_image_surface_get_data (args.surface_b);
 
     if ((width_a != width_b) || (height_a != height_b)) {
-	args.ErrorStr = "Image dimensions do not match\n";
+	printf ("FAIL: Image dimensions do not match\n");
 	return false;
     }
 
-    unsigned int x, y, dim, pixels_failed;
-    bool identical = true;
+    identical = true;
 
     for (y = 0; y < height_a; y++) {
 	row_a = data_a + y * stride_a;
@@ -65,7 +66,7 @@ static bool Yee_Compare(CompareArgs &arg
 	}
     }
     if (identical) {
-	args.ErrorStr = "Images are binary identical\n";
+	printf ("PASS: Images are binary identical\n");
 	return true;
     }
 
@@ -74,15 +75,12 @@ static bool Yee_Compare(CompareArgs &arg
 				   args.FieldOfView);
 
     if (pixels_failed < args.ThresholdPixels) {
-	args.ErrorStr = "Images are perceptually indistinguishable\n";
+	printf ("PASS: Images are perceptually indistinguishable\n");
 	return true;
     }
 
-    char different[100];
-    sprintf(different, "%d pixels are different\n", pixels_failed);
-
-    args.ErrorStr = "Images are visibly different\n";
-    args.ErrorStr += different;
+    printf("FAIL: Images are visibly different\n"
+	   "%d pixels are different\n", pixels_failed);
 
     return false;
 }
@@ -92,16 +90,10 @@ int main(int argc, char **argv)
     CompareArgs args;
 
     if (!args.Parse_Args(argc, argv)) {
-	printf("%s", args.ErrorStr.c_str());
 	return -1;
     } else {
 	if (args.Verbose) args.Print_Args();
     }
     int result = Yee_Compare(args) == true;
-    if (result) {
-	printf("PASS: %s\n", args.ErrorStr.c_str());
-    } else {
-	printf("FAIL: %s\n", args.ErrorStr.c_str());
-    }
     return result;
 }
diff-tree 91b156b82e0219b2b851c218813f24024cad7c69 (from 4c812c38e4ec9885b9451185127e5c8877354d75)
Author: Carl Worth <cworth at cworth.org>
Date:   Thu Dec 14 03:02:48 2006 -0800

    pdiff: Remove RGBAImage classes now that we're just using cairo image surfaces

diff --git a/test/pdiff/CompareArgs.cpp b/test/pdiff/CompareArgs.cpp
index 38ff1f6..265cfed 100644
--- a/test/pdiff/CompareArgs.cpp
+++ b/test/pdiff/CompareArgs.cpp
@@ -15,7 +15,6 @@
 */
 
 #include "CompareArgs.h"
-#include "RGBAImage.h"
 #include <stdio.h>
 
 static const char* copyright =
diff --git a/test/pdiff/CompareArgs.h b/test/pdiff/CompareArgs.h
index ca51bf0..ac368d5 100644
--- a/test/pdiff/CompareArgs.h
+++ b/test/pdiff/CompareArgs.h
@@ -20,9 +20,6 @@
 #include <string>
 #include <cairo.h>
 
-class RGBAImage;
-class RGBACairoImage;
-
 /* Args to pass into the comparison function */
 class CompareArgs
 {
diff --git a/test/pdiff/Makefile.am b/test/pdiff/Makefile.am
index 67d13fb..4d46238 100644
--- a/test/pdiff/Makefile.am
+++ b/test/pdiff/Makefile.am
@@ -5,9 +5,7 @@ libpdiff_la_SOURCES = 		\
 	pdiff.h			\
 	lpyramid.c		\
 	lpyramid.h		\
-	pdiff.cpp		\
-	RGBAImage.cpp		\
-	RGBAImage.h
+	pdiff.cpp
 
 perceptualdiff_SOURCES =	\
 	CompareArgs.cpp		\
diff --git a/test/pdiff/PerceptualDiff.cpp b/test/pdiff/PerceptualDiff.cpp
index eb89fbf..45ab7cb 100644
--- a/test/pdiff/PerceptualDiff.cpp
+++ b/test/pdiff/PerceptualDiff.cpp
@@ -21,7 +21,6 @@
 #include <math.h>
 #include <string>
 #include "lpyramid.h"
-#include "RGBAImage.h"
 #include "CompareArgs.h"
 #include "pdiff.h"
 
diff --git a/test/pdiff/RGBAImage.cpp b/test/pdiff/RGBAImage.cpp
deleted file mode 100644
index 2c38f9c..0000000
--- a/test/pdiff/RGBAImage.cpp
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
-  RGBAImage.cpp
-  Copyright (C) 2006 Yangli Hector Yee
-
-  This program is free software; you can redistribute it and/or modify it under the terms of the
-  GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
-  or (at your option) any later version.
-
-  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
-  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-  See the GNU General Public License for more details.
-
-  You should have received a copy of the GNU General Public License along with this program;
-  if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "RGBAImage.h"
-#include "png.h"
-
-#if HAVE_LIBTIFF
-#include "tiff.h"
-#include "tiffio.h"
-
-/* Reads Tiff Images */
-RGBAImage* RGBAImage::ReadTiff(char *filename)
-{
-    RGBAImage *fimg = 0;
-
-    TIFF* tif = TIFFOpen(filename, "r");
-    char emsg[1024];
-    emsg[0] = 0;
-    if (tif) {
-	TIFFRGBAImage img;
-
-	if (TIFFRGBAImageBegin(&img, tif, 0, emsg)) {
-	    size_t npixels;
-	    uint32* raster;
-
-	    npixels = img.width * img.height;
-	    raster = (uint32*) _TIFFmalloc(npixels * sizeof (uint32));
-	    if (raster != NULL) {
-		if (TIFFRGBAImageGet(&img, raster, img.width, img.height)) {
-		    /* result is in ABGR */
-		    fimg = new RGBAImage(img.width, img.height);
-		    for (int y = img.height - 1; y >= 0; y--) {
-			for (int x = 0; x < (int) img.width; x++) {
-			    fimg->Set(x,img.height - (y+1), raster[x + y * img.width]);
-			}
-		    }
-		}
-		_TIFFfree(raster);
-	    }
-	}
-	TIFFRGBAImageEnd(&img);
-    }
-    return fimg;
-}
-#endif /* HAVE_LIBTIFF */
-
-/* This portion was written by Scott Corley */
-RGBAImage* RGBAImage::ReadPNG(char *filename)
-{
-    RGBAImage *fimg = 0;
-    FILE *fp=fopen(filename, "rb");
-    if (!fp)
-    {
-	return NULL;
-    }
-    png_byte header[8];
-
-    fread(header, 1, 8, fp);
-    bool is_png = !png_sig_cmp(header, 0, 8);
-    if (!is_png)
-    {
-	return NULL;
-    }
-
-    png_structp png_ptr = png_create_read_struct
-	(PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
-	 NULL, NULL);
-    if (!png_ptr)
-        return (NULL);
-
-    png_infop info_ptr = png_create_info_struct(png_ptr);
-    if (!info_ptr)
-    {
-        png_destroy_read_struct(&png_ptr,
-				(png_infopp)NULL, (png_infopp)NULL);
-        return (NULL);
-    }
-
-    png_infop end_info = png_create_info_struct(png_ptr);
-    if (!end_info)
-    {
-        png_destroy_read_struct(&png_ptr, &info_ptr,
-				(png_infopp)NULL);
-        return (NULL);
-    }
-
-    png_init_io(png_ptr, fp);
-    png_set_sig_bytes(png_ptr, 8);
-
-    png_read_png(png_ptr, info_ptr, 0, NULL);
-
-    png_bytep *row_pointers;
-    row_pointers = png_get_rows(png_ptr, info_ptr);
-
-    fimg = new RGBAImage(png_ptr->width, png_ptr->height);
-    for (int y = 0; y < (int) png_ptr->height; y++) {
-	for (int x = 0; x < (int) png_ptr->width; x++) {
-	    uint32_t value = 0;
-	    if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
-		value = ((uint32_t)row_pointers[y][x*4]) | (((uint32_t)row_pointers[y][x*4+1])<<8) | (((uint32_t)row_pointers[y][x*4+2])<<16) |(((uint32_t)row_pointers[y][x*4+3])<<24);
-	    else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
-		value = ((uint32_t)row_pointers[y][x*3] /*B*/) | (((uint32_t)row_pointers[y][x*3+1] /*G*/)<<8) | (((uint32_t)row_pointers[y][x*3+2]/*R*/)<<16) | (0xFFUL << 24);
-	    fimg->Set(x,y, value);
-	}
-    }
-
-    png_read_destroy(png_ptr, info_ptr, end_info);
-    return fimg;
-}
-
-bool RGBAImage::WritePPM()
-{
-    if (Width <= 0) return false;
-    if (Height <=0 ) return false;
-    FILE *out = fopen(Name.c_str(), "wb");
-    if (!out) return false;
-    fprintf(out, "P6\n%d %d 255\n", Width, Height);
-    for (int y = 0; y < Height; y++) {
-	for (int x = 0; x < Width; x++) {
-	    int i = x + y * Width;
-	    unsigned char r = Get_Red(i);
-	    unsigned char g = Get_Green(i);
-	    unsigned char b = Get_Blue(i);
-	    fwrite(&r, 1, 1, out);
-	    fwrite(&g, 1, 1, out);
-	    fwrite(&b, 1, 1, out);
-	}
-    }
-    fclose(out);
-    return true;
-}
diff --git a/test/pdiff/RGBAImage.h b/test/pdiff/RGBAImage.h
deleted file mode 100644
index 710cabe..0000000
--- a/test/pdiff/RGBAImage.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
-  RGBAImage.h
-  Copyright (C) 2006 Yangli Hector Yee
-
-  This program is free software; you can redistribute it and/or modify it under the terms of the
-  GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
-  or (at your option) any later version.
-
-  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
-  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-  See the GNU General Public License for more details.
-
-  You should have received a copy of the GNU General Public License along with this program;
-  if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#ifndef _RGBAIMAGE_H
-#define _RGBAIMAGE_H
-
-#include<string>
-#include<cairo.h>
-
-/* assumes data is in the ABGR format */
-class RGBAImage
-{
-public:
-    RGBAImage() { Width = 0; Height = 0; Data = 0; }
-    RGBAImage(int w, int h, const char *name = 0)
-	{
-	    Width = w;
-	    Height = h;
-	    if (name) Name = name;
-	    Data = new unsigned int[w * h];
-	};
-    ~RGBAImage() { if (Data) delete[] Data; }
-    virtual unsigned char Get_Red(unsigned int i) { return (Data[i] & 0xFF); }
-    virtual unsigned char Get_Green(unsigned int i) { return ((Data[i]>>8) & 0xFF); }
-    virtual unsigned char Get_Blue(unsigned int i) { return ((Data[i]>>16) & 0xFF); }
-    virtual unsigned char Get_Alpha(unsigned int i) { return ((Data[i]>>24) & 0xFF); }
-    virtual void Set(unsigned char r, unsigned char g, unsigned char b, unsigned char a, unsigned int i)
-	{ Data[i] = r | (g << 8) | (b << 16) | (a << 24); }
-    int Get_Width(void) const { return Width; }
-    int Get_Height(void) const { return Height; }
-    virtual void Set(int x, int y, unsigned int d) { Data[x + y * Width] = d; }
-    virtual unsigned int Get(int x, int y) const { return Data[x + y * Width]; }
-    virtual unsigned int Get(int i) const { return Data[i]; }
-    const std::string &Get_Name(void) const { return Name; }
-
-    bool WritePPM();
-    static RGBAImage* ReadTiff(char *filename);
-    static RGBAImage* ReadPNG(char *filename);
-protected:
-    int Width;
-    int Height;
-    std::string Name;
-    unsigned int *Data;
-};
-
-class RGBACairoImage : public RGBAImage
-{
-public:
-    RGBACairoImage (cairo_surface_t *surface)
-	{
-	    Width = cairo_image_surface_get_width (surface);
-	    Height = cairo_image_surface_get_height (surface);
-	    Data = (unsigned int *) cairo_image_surface_get_data (surface);
-	    if (cairo_image_surface_get_stride (surface) != 4 * Width) {
-		fprintf (stderr, "Error: Currently only support images where stride == 4 * width\n");
-		exit (1);
-	    }
-	}
-    ~RGBACairoImage() { }
-
-    unsigned int ARGB_to_ABGR(unsigned int pixel) const {
-	unsigned int new_pixel;
-	new_pixel  =  pixel & 0xff00ff00;
-	new_pixel |= (pixel & 0x00ff0000) >> 16;
-	new_pixel |= (pixel & 0x000000ff) << 16;
-	return new_pixel;
-    }
-    unsigned int Get_Unpremultiply(unsigned int i) const {
-	uint32_t pixel;
-	uint8_t alpha;
-
-	pixel = Data[i];
-
-	alpha = (pixel & 0xff000000) >> 24;
-
-	if (alpha == 0)
-	    return 0;
-
-	return (alpha << 24) |
-	    ((((pixel & 0xff0000) >> 16) * 255 + alpha / 2) / alpha) << 16 |
-	    ((((pixel & 0x00ff00) >>  8) * 255 + alpha / 2) / alpha) <<  8 |
-	    ((((pixel & 0x0000ff) >>  0) * 255 + alpha / 2) / alpha) <<  0;
-    }
-    unsigned char Get_Alpha(unsigned int i) { return (Get_Unpremultiply(i) & 0xff000000) >> 24;}
-    unsigned char Get_Red(unsigned int i)   { return (Get_Unpremultiply(i) & 0x00ff0000) >> 16;}
-    unsigned char Get_Green(unsigned int i) { return (Get_Unpremultiply(i) & 0x0000ff00) >>  8;}
-    unsigned char Get_Blue(unsigned int i)  { return (Get_Unpremultiply(i) & 0x000000ff) >>  0;}
-    unsigned int Get(int x, int y) const { return Get(Width * y + x); }
-    unsigned int Get(int i) const { return ARGB_to_ABGR(Get_Unpremultiply(i)); }
-};
-
-#endif
diff --git a/test/pdiff/pdiff.cpp b/test/pdiff/pdiff.cpp
index ad8dd72..1609cda 100644
--- a/test/pdiff/pdiff.cpp
+++ b/test/pdiff/pdiff.cpp
@@ -14,10 +14,9 @@
   if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */
 
-#include "CompareArgs.h"
-#include "RGBAImage.h"
 #include "lpyramid.h"
 #include <math.h>
+#include <stdint.h>
 #include "pdiff.h"
 
 #ifndef M_PI
@@ -128,6 +127,63 @@ XYZToLAB (float x, float y, float z, flo
     *B = 200.0f * (f[1] - f[2]);
 }
 
+static uint32_t
+_get_pixel (cairo_surface_t *surface, int i)
+{
+    uint32_t *data;
+
+    data = (uint32_t *) cairo_image_surface_get_data (surface);
+    return data[i];
+}
+
+static unsigned char
+_get_red (cairo_surface_t *surface, int i)
+{
+    uint32_t pixel;
+    uint8_t alpha;
+
+    pixel = _get_pixel (surface, i);
+
+    alpha = (pixel & 0xff000000) >> 24;
+
+    if (alpha == 0)
+	return 0;
+    else
+	return (((pixel & 0x00ff0000) >> 16) * 255 + alpha / 2) / alpha;
+}
+
+static unsigned char
+_get_green (cairo_surface_t *surface, int i)
+{
+    uint32_t pixel;
+    uint8_t alpha;
+
+    pixel = _get_pixel (surface, i);
+
+    alpha = (pixel & 0xff000000) >> 24;
+
+    if (alpha == 0)
+	return 0;
+    else
+	return (((pixel & 0x0000ff00) >> 8) * 255 + alpha / 2) / alpha;
+}
+
+static unsigned char
+_get_blue (cairo_surface_t *surface, int i)
+{
+    uint32_t pixel;
+    uint8_t alpha;
+
+    pixel = _get_pixel (surface, i);
+
+    alpha = (pixel & 0xff000000) >> 24;
+
+    if (alpha == 0)
+	return 0;
+    else
+	return (((pixel & 0x000000ff) >> 0) * 255 + alpha / 2) / alpha;
+}
+
 int
 pdiff_compare (cairo_surface_t *surface_a,
 	       cairo_surface_t *surface_b,
@@ -135,7 +191,6 @@ pdiff_compare (cairo_surface_t *surface_
 	       double luminance,
 	       double field_of_view)
 {
-    RGBAImage *image_a, *image_b;
     unsigned int dim = (cairo_image_surface_get_width (surface_a)
 			* cairo_image_surface_get_height (surface_a));
     unsigned int i;
@@ -168,24 +223,21 @@ pdiff_compare (cairo_surface_t *surface_
 
     unsigned int pixels_failed;
 
-    image_a = new RGBACairoImage (surface_a);
-    image_b = new RGBACairoImage (surface_b);
-
-    w = image_a->Get_Width();
-    h = image_a->Get_Height();
+    w = cairo_image_surface_get_width (surface_a);
+    h = cairo_image_surface_get_height (surface_a);
     for (y = 0; y < h; y++) {
 	for (x = 0; x < w; x++) {
 	    float r, g, b, l;
 	    i = x + y * w;
-	    r = powf(image_a->Get_Red(i) / 255.0f, gamma);
-	    g = powf(image_a->Get_Green(i) / 255.0f, gamma);
-	    b = powf(image_a->Get_Blue(i) / 255.0f, gamma);
+	    r = powf(_get_red (surface_a, i) / 255.0f, gamma);
+	    g = powf(_get_green (surface_a, i) / 255.0f, gamma);
+	    b = powf(_get_blue (surface_a, i) / 255.0f, gamma);
 
 	    AdobeRGBToXYZ(r,g,b,&aX[i],&aY[i],&aZ[i]);
 	    XYZToLAB(aX[i], aY[i], aZ[i], &l, &aA[i], &aB[i]);
-	    r = powf(image_b->Get_Red(i) / 255.0f, gamma);
-	    g = powf(image_b->Get_Green(i) / 255.0f, gamma);
-	    b = powf(image_b->Get_Blue(i) / 255.0f, gamma);
+	    r = powf(_get_red (surface_b, i) / 255.0f, gamma);
+	    g = powf(_get_green (surface_b, i) / 255.0f, gamma);
+	    b = powf(_get_blue (surface_b, i) / 255.0f, gamma);
 
 	    AdobeRGBToXYZ(r,g,b,&bX[i],&bY[i],&bZ[i]);
 	    XYZToLAB(bX[i], bY[i], bZ[i], &l, &bA[i], &bB[i]);
diff --git a/test/pdiff/pdiff.h b/test/pdiff/pdiff.h
index 195a34c..d20ae86 100644
--- a/test/pdiff/pdiff.h
+++ b/test/pdiff/pdiff.h
@@ -21,6 +21,8 @@
 extern "C" {
 #endif
 
+#include <cairo.h>
+
 /* Image comparison metric using Yee's method (and a cairo interface)
  * References: A Perceptual Metric for Production Testing, Hector Yee, Journal of Graphics Tools 2004
  */
diff-tree 4c812c38e4ec9885b9451185127e5c8877354d75 (from 2457756afd66b69840640eff3aaf72e7ea0f64e8)
Author: Carl Worth <cworth at cworth.org>
Date:   Thu Dec 14 02:10:35 2006 -0800

    pdiff: Remove hideous C++ reference passing

diff --git a/test/pdiff/pdiff.cpp b/test/pdiff/pdiff.cpp
index 2c11cc6..ad8dd72 100644
--- a/test/pdiff/pdiff.cpp
+++ b/test/pdiff/pdiff.cpp
@@ -89,16 +89,16 @@ mask (float contrast)
 
 /* convert Adobe RGB (1998) with reference white D65 to XYZ */
 static void
-AdobeRGBToXYZ (float r, float g, float b, float &x, float &y, float &z)
+AdobeRGBToXYZ (float r, float g, float b, float *x, float *y, float *z)
 {
     /* matrix is from http://www.brucelindbloom.com/ */
-    x = r * 0.576700f + g * 0.185556f + b * 0.188212f;
-    y = r * 0.297361f + g * 0.627355f + b * 0.0752847f;
-    z = r * 0.0270328f + g * 0.0706879f + b * 0.991248f;
+    *x = r * 0.576700f + g * 0.185556f + b * 0.188212f;
+    *y = r * 0.297361f + g * 0.627355f + b * 0.0752847f;
+    *z = r * 0.0270328f + g * 0.0706879f + b * 0.991248f;
 }
 
 static void
-XYZToLAB (float x, float y, float z, float &L, float &A, float &B)
+XYZToLAB (float x, float y, float z, float *L, float *A, float *B)
 {
     static float xw = -1;
     static float yw;
@@ -111,7 +111,7 @@ XYZToLAB (float x, float y, float z, flo
 
     /* reference white */
     if (xw < 0) {
-	AdobeRGBToXYZ(1, 1, 1, xw, yw, zw);
+	AdobeRGBToXYZ(1, 1, 1, &xw, &yw, &zw);
     }
     r[0] = x / xw;
     r[1] = y / yw;
@@ -123,9 +123,9 @@ XYZToLAB (float x, float y, float z, flo
 	    f[i] = (kappa * r[i] + 16.0f) / 116.0f;
 	}
     }
-    L = 116.0f * f[1] - 16.0f;
-    A = 500.0f * (f[0] - f[1]);
-    B = 200.0f * (f[1] - f[2]);
+    *L = 116.0f * f[1] - 16.0f;
+    *A = 500.0f * (f[0] - f[1]);
+    *B = 200.0f * (f[1] - f[2]);
 }
 
 int
@@ -181,14 +181,14 @@ pdiff_compare (cairo_surface_t *surface_
 	    g = powf(image_a->Get_Green(i) / 255.0f, gamma);
 	    b = powf(image_a->Get_Blue(i) / 255.0f, gamma);
 
-	    AdobeRGBToXYZ(r,g,b,aX[i],aY[i],aZ[i]);
-	    XYZToLAB(aX[i], aY[i], aZ[i], l, aA[i], aB[i]);
+	    AdobeRGBToXYZ(r,g,b,&aX[i],&aY[i],&aZ[i]);
+	    XYZToLAB(aX[i], aY[i], aZ[i], &l, &aA[i], &aB[i]);
 	    r = powf(image_b->Get_Red(i) / 255.0f, gamma);
 	    g = powf(image_b->Get_Green(i) / 255.0f, gamma);
 	    b = powf(image_b->Get_Blue(i) / 255.0f, gamma);
 
-	    AdobeRGBToXYZ(r,g,b,bX[i],bY[i],bZ[i]);
-	    XYZToLAB(bX[i], bY[i], bZ[i], l, bA[i], bB[i]);
+	    AdobeRGBToXYZ(r,g,b,&bX[i],&bY[i],&bZ[i]);
+	    XYZToLAB(bX[i], bY[i], bZ[i], &l, &bA[i], &bB[i]);
 	    aLum[i] = aY[i] * luminance;
 	    bLum[i] = bY[i] * luminance;
 	}
diff-tree 2457756afd66b69840640eff3aaf72e7ea0f64e8 (from e947f5a4bdf4a4134faa8961406a10f32cf4e2d6)
Author: Carl Worth <cworth at cworth.org>
Date:   Thu Dec 14 02:08:30 2006 -0800

    pdiff: Remove intermingled statements and declarations

diff --git a/test/pdiff/pdiff.cpp b/test/pdiff/pdiff.cpp
index 12b055b..2c11cc6 100644
--- a/test/pdiff/pdiff.cpp
+++ b/test/pdiff/pdiff.cpp
@@ -36,7 +36,6 @@ tvi (float adaptation_luminance)
     /* returns the threshold luminance given the adaptation luminance
        units are candelas per meter squared
     */
-
     float log_a, r, result;
     log_a = log10f(adaptation_luminance);
 
@@ -55,7 +54,6 @@ tvi (float adaptation_luminance)
     result = powf(10.0f , r);
 
     return result;
-
 }
 
 /* computes the contrast sensitivity function (Barten SPIE 1989)
@@ -105,18 +103,20 @@ XYZToLAB (float x, float y, float z, flo
     static float xw = -1;
     static float yw;
     static float zw;
-    /* reference white */
-    if (xw < 0) {
-	AdobeRGBToXYZ(1, 1, 1, xw, yw, zw);
-    }
     const float epsilon  = 216.0f / 24389.0f;
     const float kappa = 24389.0f / 27.0f;
     float f[3];
     float r[3];
+    int i;
+
+    /* reference white */
+    if (xw < 0) {
+	AdobeRGBToXYZ(1, 1, 1, xw, yw, zw);
+    }
     r[0] = x / xw;
     r[1] = y / yw;
     r[2] = z / zw;
-    for (int i = 0; i < 3; i++) {
+    for (i = 0; i < 3; i++) {
 	if (r[i] > epsilon) {
 	    f[i] = powf(r[i], 1.0f / 3.0f);
 	} else {
@@ -136,12 +136,9 @@ pdiff_compare (cairo_surface_t *surface_
 	       double field_of_view)
 {
     RGBAImage *image_a, *image_b;
-    unsigned int i, dim;
-
-    image_a = new RGBACairoImage (surface_a);
-    image_b = new RGBACairoImage (surface_b);
-
-    dim = image_a->Get_Width() * image_a->Get_Height();
+    unsigned int dim = (cairo_image_surface_get_width (surface_a)
+			* cairo_image_surface_get_height (surface_a));
+    unsigned int i;
 
     /* assuming colorspaces are in Adobe RGB (1998) convert to XYZ */
     float *aX = new float[dim];
@@ -159,6 +156,21 @@ pdiff_compare (cairo_surface_t *surface_
     float *bB = new float[dim];
 
     unsigned int x, y, w, h;
+
+    lpyramid_t *la, *lb;
+
+    float num_one_degree_pixels, pixels_per_degree, num_pixels;
+    unsigned int adaptation_level;
+
+    float cpd[MAX_PYR_LEVELS];
+    float F_freq[MAX_PYR_LEVELS - 2];
+    float csf_max;
+
+    unsigned int pixels_failed;
+
+    image_a = new RGBACairoImage (surface_a);
+    image_b = new RGBACairoImage (surface_b);
+
     w = image_a->Get_Width();
     h = image_a->Get_Height();
     for (y = 0; y < h; y++) {
@@ -182,33 +194,35 @@ pdiff_compare (cairo_surface_t *surface_
 	}
     }
 
-    lpyramid_t *la = lpyramid_create (aLum, w, h);
-    lpyramid_t *lb = lpyramid_create (bLum, w, h);
+    la = lpyramid_create (aLum, w, h);
+    lb = lpyramid_create (bLum, w, h);
 
-    float num_one_degree_pixels = (float) (2 * tan(field_of_view * 0.5 * M_PI / 180) * 180 / M_PI);
-    float pixels_per_degree = w / num_one_degree_pixels;
+    num_one_degree_pixels = (float) (2 * tan(field_of_view * 0.5 * M_PI / 180) * 180 / M_PI);
+    pixels_per_degree = w / num_one_degree_pixels;
 
-    float num_pixels = 1;
-    unsigned int adaptation_level = 0;
+    num_pixels = 1;
+    adaptation_level = 0;
     for (i = 0; i < MAX_PYR_LEVELS; i++) {
 	adaptation_level = i;
 	if (num_pixels > num_one_degree_pixels) break;
 	num_pixels *= 2;
     }
 
-    float cpd[MAX_PYR_LEVELS];
     cpd[0] = 0.5f * pixels_per_degree;
     for (i = 1; i < MAX_PYR_LEVELS; i++) cpd[i] = 0.5f * cpd[i - 1];
-    float csf_max = csf(3.248f, 100.0f);
+    csf_max = csf(3.248f, 100.0f);
 
-    float F_freq[MAX_PYR_LEVELS - 2];
     for (i = 0; i < MAX_PYR_LEVELS - 2; i++) F_freq[i] = csf_max / csf( cpd[i], 100.0f);
 
-    unsigned int pixels_failed = 0;
+    pixels_failed = 0;
     for (y = 0; y < h; y++) {
 	for (x = 0; x < w; x++) {
 	    int index = x + y * w;
 	    float contrast[MAX_PYR_LEVELS - 2];
+	    float F_mask[MAX_PYR_LEVELS - 2];
+	    float factor;
+	    float delta;
+	    bool pass;
 	    float sum_contrast = 0;
 	    for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
 		float n1 = fabsf(lpyramid_get_value (la,x,y,i) - lpyramid_get_value (la,x,y,i + 1));
@@ -222,37 +236,37 @@ pdiff_compare (cairo_surface_t *surface_
 		sum_contrast += contrast[i];
 	    }
 	    if (sum_contrast < 1e-5) sum_contrast = 1e-5f;
-	    float F_mask[MAX_PYR_LEVELS - 2];
 	    float adapt = lpyramid_get_value(la,x,y,adaptation_level) + lpyramid_get_value(lb,x,y,adaptation_level);
 	    adapt *= 0.5f;
 	    if (adapt < 1e-5) adapt = 1e-5f;
 	    for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
 		F_mask[i] = mask(contrast[i] * csf(cpd[i], adapt));
 	    }
-	    float factor = 0;
+	    factor = 0;
 	    for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
 		factor += contrast[i] * F_freq[i] * F_mask[i] / sum_contrast;
 	    }
 	    if (factor < 1) factor = 1;
 	    if (factor > 10) factor = 10;
-	    float delta = fabsf(lpyramid_get_value(la,x,y,0) - lpyramid_get_value(lb,x,y,0));
-	    bool pass = true;
+	    delta = fabsf(lpyramid_get_value(la,x,y,0) - lpyramid_get_value(lb,x,y,0));
+	    pass = true;
 	    /* pure luminance test */
 	    if (delta > factor * tvi(adapt)) {
 		pass = false;
 	    } else {
 		/* CIE delta E test with modifications */
 		float color_scale = 1.0f;
+		float da = aA[index] - bA[index];
+		float db = aB[index] - bB[index];
+		float delta_e;
 		/* ramp down the color test in scotopic regions */
 		if (adapt < 10.0f) {
 		    color_scale = 1.0f - (10.0f - color_scale) / 10.0f;
 		    color_scale = color_scale * color_scale;
 		}
-		float da = aA[index] - bA[index];
-		float db = aB[index] - bB[index];
 		da = da * da;
 		db = db * db;
-		float delta_e = (da + db) * color_scale;
+		delta_e = (da + db) * color_scale;
 		if (delta_e > factor) {
 		    pass = false;
 		}
diff-tree e947f5a4bdf4a4134faa8961406a10f32cf4e2d6 (from bb4d4dc77117ded253d1f507e771de7f98c69fb8)
Author: Carl Worth <cworth at cworth.org>
Date:   Thu Dec 14 01:09:05 2006 -0800

    pdiff: Add .gitignore for perceptualdiff binary

diff --git a/test/pdiff/.gitignore b/test/pdiff/.gitignore
new file mode 100644
index 0000000..d2e5a94
--- /dev/null
+++ b/test/pdiff/.gitignore
@@ -0,0 +1 @@
+perceptualdiff
diff-tree bb4d4dc77117ded253d1f507e771de7f98c69fb8 (from 53c3a2f75b7f065b4c769ad087bbc9aaaaf6d7ee)
Author: Carl Worth <cworth at cworth.org>
Date:   Thu Dec 14 01:06:42 2006 -0800

    pdiff: Remove old, unused Yee_Compare interface

diff --git a/test/pdiff/Makefile.am b/test/pdiff/Makefile.am
index 5dd4003..67d13fb 100644
--- a/test/pdiff/Makefile.am
+++ b/test/pdiff/Makefile.am
@@ -5,7 +5,7 @@ libpdiff_la_SOURCES = 		\
 	pdiff.h			\
 	lpyramid.c		\
 	lpyramid.h		\
-	Metric.cpp		\
+	pdiff.cpp		\
 	RGBAImage.cpp		\
 	RGBAImage.h
 
diff --git a/test/pdiff/Metric.cpp b/test/pdiff/Metric.cpp
deleted file mode 100644
index d9e56ac..0000000
--- a/test/pdiff/Metric.cpp
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
-  Metric
-  Copyright (C) 2006 Yangli Hector Yee
-
-  This program is free software; you can redistribute it and/or modify it under the terms of the
-  GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
-  or (at your option) any later version.
-
-  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
-  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-  See the GNU General Public License for more details.
-
-  You should have received a copy of the GNU General Public License along with this program;
-  if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "CompareArgs.h"
-#include "RGBAImage.h"
-#include "lpyramid.h"
-#include <math.h>
-#include "pdiff.h"
-
-#ifndef M_PI
-#define M_PI 3.14159265f
-#endif
-
-/*
- * Given the adaptation luminance, this function returns the
- * threshold of visibility in cd per m^2
- * TVI means Threshold vs Intensity function
- * This version comes from Ward Larson Siggraph 1997
- */
-
-float tvi(float adaptation_luminance)
-{
-    /* returns the threshold luminance given the adaptation luminance
-       units are candelas per meter squared
-    */
-
-    float log_a, r, result;
-    log_a = log10f(adaptation_luminance);
-
-    if (log_a < -3.94f) {
-	r = -2.86f;
-    } else if (log_a < -1.44f) {
-	r = powf(0.405f * log_a + 1.6f , 2.18f) - 2.86f;
-    } else if (log_a < -0.0184f) {
-	r = log_a - 0.395f;
-    } else if (log_a < 1.9f) {
-	r = powf(0.249f * log_a + 0.65f, 2.7f) - 0.72f;
-    } else {
-	r = log_a - 1.255f;
-    }
-
-    result = powf(10.0f , r);
-
-    return result;
-
-}
-
-/* computes the contrast sensitivity function (Barten SPIE 1989)
- * given the cycles per degree (cpd) and luminance (lum)
- */
-float csf(float cpd, float lum)
-{
-    float a, b, result;
-
-    a = 440.0f * powf((1.0f + 0.7f / lum), -0.2f);
-    b = 0.3f * powf((1.0f + 100.0f / lum), 0.15f);
-
-    result = a * cpd * expf(-b * cpd) * sqrtf(1.0f + 0.06f * expf(b * cpd));
-
-    return result;
-}
-
-/*
- * Visual Masking Function
- * from Daly 1993
- */
-float mask(float contrast)
-{
-    float a, b, result;
-    a = powf(392.498f * contrast,  0.7f);
-    b = powf(0.0153f * a, 4.0f);
-    result = powf(1.0f + b, 0.25f);
-
-    return result;
-}
-
-/* convert Adobe RGB (1998) with reference white D65 to XYZ */
-void AdobeRGBToXYZ(float r, float g, float b, float &x, float &y, float &z)
-{
-    /* matrix is from http://www.brucelindbloom.com/ */
-    x = r * 0.576700f + g * 0.185556f + b * 0.188212f;
-    y = r * 0.297361f + g * 0.627355f + b * 0.0752847f;
-    z = r * 0.0270328f + g * 0.0706879f + b * 0.991248f;
-}
-
-void XYZToLAB(float x, float y, float z, float &L, float &A, float &B)
-{
-    static float xw = -1;
-    static float yw;
-    static float zw;
-    /* reference white */
-    if (xw < 0) {
-	AdobeRGBToXYZ(1, 1, 1, xw, yw, zw);
-    }
-    const float epsilon  = 216.0f / 24389.0f;
-    const float kappa = 24389.0f / 27.0f;
-    float f[3];
-    float r[3];
-    r[0] = x / xw;
-    r[1] = y / yw;
-    r[2] = z / zw;
-    for (int i = 0; i < 3; i++) {
-	if (r[i] > epsilon) {
-	    f[i] = powf(r[i], 1.0f / 3.0f);
-	} else {
-	    f[i] = (kappa * r[i] + 16.0f) / 116.0f;
-	}
-    }
-    L = 116.0f * f[1] - 16.0f;
-    A = 500.0f * (f[0] - f[1]);
-    B = 200.0f * (f[1] - f[2]);
-}
-
-int Yee_Compare_Images(RGBAImage *image_a,
-		       RGBAImage *image_b,
-		       float gamma,
-		       float luminance,
-		       float field_of_view,
-		       bool verbose)
-{
-    unsigned int i, dim;
-    dim = image_a->Get_Width() * image_a->Get_Height();
-
-    /* assuming colorspaces are in Adobe RGB (1998) convert to XYZ */
-    float *aX = new float[dim];
-    float *aY = new float[dim];
-    float *aZ = new float[dim];
-    float *bX = new float[dim];
-    float *bY = new float[dim];
-    float *bZ = new float[dim];
-    float *aLum = new float[dim];
-    float *bLum = new float[dim];
-
-    float *aA = new float[dim];
-    float *bA = new float[dim];
-    float *aB = new float[dim];
-    float *bB = new float[dim];
-
-    if (verbose) printf("Converting RGB to XYZ\n");
-
-    unsigned int x, y, w, h;
-    w = image_a->Get_Width();
-    h = image_a->Get_Height();
-    for (y = 0; y < h; y++) {
-	for (x = 0; x < w; x++) {
-	    float r, g, b, l;
-	    i = x + y * w;
-	    r = powf(image_a->Get_Red(i) / 255.0f, gamma);
-	    g = powf(image_a->Get_Green(i) / 255.0f, gamma);
-	    b = powf(image_a->Get_Blue(i) / 255.0f, gamma);
-
-	    AdobeRGBToXYZ(r,g,b,aX[i],aY[i],aZ[i]);
-	    XYZToLAB(aX[i], aY[i], aZ[i], l, aA[i], aB[i]);
-	    r = powf(image_b->Get_Red(i) / 255.0f, gamma);
-	    g = powf(image_b->Get_Green(i) / 255.0f, gamma);
-	    b = powf(image_b->Get_Blue(i) / 255.0f, gamma);
-
-	    AdobeRGBToXYZ(r,g,b,bX[i],bY[i],bZ[i]);
-	    XYZToLAB(bX[i], bY[i], bZ[i], l, bA[i], bB[i]);
-	    aLum[i] = aY[i] * luminance;
-	    bLum[i] = bY[i] * luminance;
-	}
-    }
-
-    if (verbose) printf("Constructing Laplacian Pyramids\n");
-
-    lpyramid_t *la = lpyramid_create (aLum, w, h);
-    lpyramid_t *lb = lpyramid_create (bLum, w, h);
-
-    float num_one_degree_pixels = (float) (2 * tan(field_of_view * 0.5 * M_PI / 180) * 180 / M_PI);
-    float pixels_per_degree = w / num_one_degree_pixels;
-
-    if (verbose) printf("Performing test\n");
-
-    float num_pixels = 1;
-    unsigned int adaptation_level = 0;
-    for (i = 0; i < MAX_PYR_LEVELS; i++) {
-	adaptation_level = i;
-	if (num_pixels > num_one_degree_pixels) break;
-	num_pixels *= 2;
-    }
-
-    float cpd[MAX_PYR_LEVELS];
-    cpd[0] = 0.5f * pixels_per_degree;
-    for (i = 1; i < MAX_PYR_LEVELS; i++) cpd[i] = 0.5f * cpd[i - 1];
-    float csf_max = csf(3.248f, 100.0f);
-
-    float F_freq[MAX_PYR_LEVELS - 2];
-    for (i = 0; i < MAX_PYR_LEVELS - 2; i++) F_freq[i] = csf_max / csf( cpd[i], 100.0f);
-
-    unsigned int pixels_failed = 0;
-    for (y = 0; y < h; y++) {
-	for (x = 0; x < w; x++) {
-	    int index = x + y * w;
-	    float contrast[MAX_PYR_LEVELS - 2];
-	    float sum_contrast = 0;
-	    for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
-		float n1 = fabsf(lpyramid_get_value (la,x,y,i) - lpyramid_get_value (la,x,y,i + 1));
-		float n2 = fabsf(lpyramid_get_value (lb,x,y,i) - lpyramid_get_value (lb,x,y,i + 1));
-		float numerator = (n1 > n2) ? n1 : n2;
-		float d1 = fabsf(lpyramid_get_value(la,x,y,i+2));
-		float d2 = fabsf(lpyramid_get_value(lb,x,y,i+2));
-		float denominator = (d1 > d2) ? d1 : d2;
-		if (denominator < 1e-5f) denominator = 1e-5f;
-		contrast[i] = numerator / denominator;
-		sum_contrast += contrast[i];
-	    }
-	    if (sum_contrast < 1e-5) sum_contrast = 1e-5f;
-	    float F_mask[MAX_PYR_LEVELS - 2];
-	    float adapt = lpyramid_get_value(la,x,y,adaptation_level) + lpyramid_get_value(lb,x,y,adaptation_level);
-	    adapt *= 0.5f;
-	    if (adapt < 1e-5) adapt = 1e-5f;
-	    for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
-		F_mask[i] = mask(contrast[i] * csf(cpd[i], adapt));
-	    }
-	    float factor = 0;
-	    for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
-		factor += contrast[i] * F_freq[i] * F_mask[i] / sum_contrast;
-	    }
-	    if (factor < 1) factor = 1;
-	    if (factor > 10) factor = 10;
-	    float delta = fabsf(lpyramid_get_value(la,x,y,0) - lpyramid_get_value(lb,x,y,0));
-	    bool pass = true;
-	    /* pure luminance test */
-	    if (delta > factor * tvi(adapt)) {
-		pass = false;
-	    } else {
-		/* CIE delta E test with modifications */
-		float color_scale = 1.0f;
-		/* ramp down the color test in scotopic regions */
-		if (adapt < 10.0f) {
-		    color_scale = 1.0f - (10.0f - color_scale) / 10.0f;
-		    color_scale = color_scale * color_scale;
-		}
-		float da = aA[index] - bA[index];
-		float db = aB[index] - bB[index];
-		da = da * da;
-		db = db * db;
-		float delta_e = (da + db) * color_scale;
-		if (delta_e > factor) {
-		    pass = false;
-		}
-	    }
-	    if (!pass)
-		pixels_failed++;
-	}
-    }
-
-    if (aX) delete[] aX;
-    if (aY) delete[] aY;
-    if (aZ) delete[] aZ;
-    if (bX) delete[] bX;
-    if (bY) delete[] bY;
-    if (bZ) delete[] bZ;
-    if (aLum) delete[] aLum;
-    if (bLum) delete[] bLum;
-    lpyramid_destroy (la);
-    lpyramid_destroy (lb);
-    if (aA) delete aA;
-    if (bA) delete bA;
-    if (aB) delete aB;
-    if (bB) delete bB;
-
-    return pixels_failed;
-}
-
-int
-pdiff_compare (cairo_surface_t *surface_a,
-	       cairo_surface_t *surface_b,
-	       double gamma,
-	       double luminance,
-	       double field_of_view)
-{
-    RGBAImage *image_a, *image_b;
-
-    image_a = new RGBACairoImage (surface_a);
-    image_b = new RGBACairoImage (surface_b);
-
-    return Yee_Compare_Images (image_a, image_b,
-			       gamma, luminance,
-			       field_of_view, false);
-}
diff --git a/test/pdiff/pdiff.cpp b/test/pdiff/pdiff.cpp
new file mode 100644
index 0000000..12b055b
--- /dev/null
+++ b/test/pdiff/pdiff.cpp
@@ -0,0 +1,281 @@
+/*
+  Metric
+  Copyright (C) 2006 Yangli Hector Yee
+
+  This program is free software; you can redistribute it and/or modify it under the terms of the
+  GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License along with this program;
+  if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "CompareArgs.h"
+#include "RGBAImage.h"
+#include "lpyramid.h"
+#include <math.h>
+#include "pdiff.h"
+
+#ifndef M_PI
+#define M_PI 3.14159265f
+#endif
+
+/*
+ * Given the adaptation luminance, this function returns the
+ * threshold of visibility in cd per m^2
+ * TVI means Threshold vs Intensity function
+ * This version comes from Ward Larson Siggraph 1997
+ */
+static float
+tvi (float adaptation_luminance)
+{
+    /* returns the threshold luminance given the adaptation luminance
+       units are candelas per meter squared
+    */
+
+    float log_a, r, result;
+    log_a = log10f(adaptation_luminance);
+
+    if (log_a < -3.94f) {
+	r = -2.86f;
+    } else if (log_a < -1.44f) {
+	r = powf(0.405f * log_a + 1.6f , 2.18f) - 2.86f;
+    } else if (log_a < -0.0184f) {
+	r = log_a - 0.395f;
+    } else if (log_a < 1.9f) {
+	r = powf(0.249f * log_a + 0.65f, 2.7f) - 0.72f;
+    } else {
+	r = log_a - 1.255f;
+    }
+
+    result = powf(10.0f , r);
+
+    return result;
+
+}
+
+/* computes the contrast sensitivity function (Barten SPIE 1989)
+ * given the cycles per degree (cpd) and luminance (lum)
+ */
+static float
+csf (float cpd, float lum)
+{
+    float a, b, result;
+
+    a = 440.0f * powf((1.0f + 0.7f / lum), -0.2f);
+    b = 0.3f * powf((1.0f + 100.0f / lum), 0.15f);
+
+    result = a * cpd * expf(-b * cpd) * sqrtf(1.0f + 0.06f * expf(b * cpd));
+
+    return result;
+}
+
+/*
+ * Visual Masking Function
+ * from Daly 1993
+ */
+static float
+mask (float contrast)
+{
+    float a, b, result;
+    a = powf(392.498f * contrast,  0.7f);
+    b = powf(0.0153f * a, 4.0f);
+    result = powf(1.0f + b, 0.25f);
+
+    return result;
+}
+
+/* convert Adobe RGB (1998) with reference white D65 to XYZ */
+static void
+AdobeRGBToXYZ (float r, float g, float b, float &x, float &y, float &z)
+{
+    /* matrix is from http://www.brucelindbloom.com/ */
+    x = r * 0.576700f + g * 0.185556f + b * 0.188212f;
+    y = r * 0.297361f + g * 0.627355f + b * 0.0752847f;
+    z = r * 0.0270328f + g * 0.0706879f + b * 0.991248f;
+}
+
+static void
+XYZToLAB (float x, float y, float z, float &L, float &A, float &B)
+{
+    static float xw = -1;
+    static float yw;
+    static float zw;
+    /* reference white */
+    if (xw < 0) {
+	AdobeRGBToXYZ(1, 1, 1, xw, yw, zw);
+    }
+    const float epsilon  = 216.0f / 24389.0f;
+    const float kappa = 24389.0f / 27.0f;
+    float f[3];
+    float r[3];
+    r[0] = x / xw;
+    r[1] = y / yw;
+    r[2] = z / zw;
+    for (int i = 0; i < 3; i++) {
+	if (r[i] > epsilon) {
+	    f[i] = powf(r[i], 1.0f / 3.0f);
+	} else {
+	    f[i] = (kappa * r[i] + 16.0f) / 116.0f;
+	}
+    }
+    L = 116.0f * f[1] - 16.0f;
+    A = 500.0f * (f[0] - f[1]);
+    B = 200.0f * (f[1] - f[2]);
+}
+
+int
+pdiff_compare (cairo_surface_t *surface_a,
+	       cairo_surface_t *surface_b,
+	       double gamma,
+	       double luminance,
+	       double field_of_view)
+{
+    RGBAImage *image_a, *image_b;
+    unsigned int i, dim;
+
+    image_a = new RGBACairoImage (surface_a);
+    image_b = new RGBACairoImage (surface_b);
+
+    dim = image_a->Get_Width() * image_a->Get_Height();
+
+    /* assuming colorspaces are in Adobe RGB (1998) convert to XYZ */
+    float *aX = new float[dim];
+    float *aY = new float[dim];
+    float *aZ = new float[dim];
+    float *bX = new float[dim];
+    float *bY = new float[dim];
+    float *bZ = new float[dim];
+    float *aLum = new float[dim];
+    float *bLum = new float[dim];
+
+    float *aA = new float[dim];
+    float *bA = new float[dim];
+    float *aB = new float[dim];
+    float *bB = new float[dim];
+
+    unsigned int x, y, w, h;
+    w = image_a->Get_Width();
+    h = image_a->Get_Height();
+    for (y = 0; y < h; y++) {
+	for (x = 0; x < w; x++) {
+	    float r, g, b, l;
+	    i = x + y * w;
+	    r = powf(image_a->Get_Red(i) / 255.0f, gamma);
+	    g = powf(image_a->Get_Green(i) / 255.0f, gamma);
+	    b = powf(image_a->Get_Blue(i) / 255.0f, gamma);
+
+	    AdobeRGBToXYZ(r,g,b,aX[i],aY[i],aZ[i]);
+	    XYZToLAB(aX[i], aY[i], aZ[i], l, aA[i], aB[i]);
+	    r = powf(image_b->Get_Red(i) / 255.0f, gamma);
+	    g = powf(image_b->Get_Green(i) / 255.0f, gamma);
+	    b = powf(image_b->Get_Blue(i) / 255.0f, gamma);
+
+	    AdobeRGBToXYZ(r,g,b,bX[i],bY[i],bZ[i]);
+	    XYZToLAB(bX[i], bY[i], bZ[i], l, bA[i], bB[i]);
+	    aLum[i] = aY[i] * luminance;
+	    bLum[i] = bY[i] * luminance;
+	}
+    }
+
+    lpyramid_t *la = lpyramid_create (aLum, w, h);
+    lpyramid_t *lb = lpyramid_create (bLum, w, h);
+
+    float num_one_degree_pixels = (float) (2 * tan(field_of_view * 0.5 * M_PI / 180) * 180 / M_PI);
+    float pixels_per_degree = w / num_one_degree_pixels;
+
+    float num_pixels = 1;
+    unsigned int adaptation_level = 0;
+    for (i = 0; i < MAX_PYR_LEVELS; i++) {
+	adaptation_level = i;
+	if (num_pixels > num_one_degree_pixels) break;
+	num_pixels *= 2;
+    }
+
+    float cpd[MAX_PYR_LEVELS];
+    cpd[0] = 0.5f * pixels_per_degree;
+    for (i = 1; i < MAX_PYR_LEVELS; i++) cpd[i] = 0.5f * cpd[i - 1];
+    float csf_max = csf(3.248f, 100.0f);
+
+    float F_freq[MAX_PYR_LEVELS - 2];
+    for (i = 0; i < MAX_PYR_LEVELS - 2; i++) F_freq[i] = csf_max / csf( cpd[i], 100.0f);
+
+    unsigned int pixels_failed = 0;
+    for (y = 0; y < h; y++) {
+	for (x = 0; x < w; x++) {
+	    int index = x + y * w;
+	    float contrast[MAX_PYR_LEVELS - 2];
+	    float sum_contrast = 0;
+	    for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
+		float n1 = fabsf(lpyramid_get_value (la,x,y,i) - lpyramid_get_value (la,x,y,i + 1));
+		float n2 = fabsf(lpyramid_get_value (lb,x,y,i) - lpyramid_get_value (lb,x,y,i + 1));
+		float numerator = (n1 > n2) ? n1 : n2;
+		float d1 = fabsf(lpyramid_get_value(la,x,y,i+2));
+		float d2 = fabsf(lpyramid_get_value(lb,x,y,i+2));
+		float denominator = (d1 > d2) ? d1 : d2;
+		if (denominator < 1e-5f) denominator = 1e-5f;
+		contrast[i] = numerator / denominator;
+		sum_contrast += contrast[i];
+	    }
+	    if (sum_contrast < 1e-5) sum_contrast = 1e-5f;
+	    float F_mask[MAX_PYR_LEVELS - 2];
+	    float adapt = lpyramid_get_value(la,x,y,adaptation_level) + lpyramid_get_value(lb,x,y,adaptation_level);
+	    adapt *= 0.5f;
+	    if (adapt < 1e-5) adapt = 1e-5f;
+	    for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
+		F_mask[i] = mask(contrast[i] * csf(cpd[i], adapt));
+	    }
+	    float factor = 0;
+	    for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
+		factor += contrast[i] * F_freq[i] * F_mask[i] / sum_contrast;
+	    }
+	    if (factor < 1) factor = 1;
+	    if (factor > 10) factor = 10;
+	    float delta = fabsf(lpyramid_get_value(la,x,y,0) - lpyramid_get_value(lb,x,y,0));
+	    bool pass = true;
+	    /* pure luminance test */
+	    if (delta > factor * tvi(adapt)) {
+		pass = false;
+	    } else {
+		/* CIE delta E test with modifications */
+		float color_scale = 1.0f;
+		/* ramp down the color test in scotopic regions */
+		if (adapt < 10.0f) {
+		    color_scale = 1.0f - (10.0f - color_scale) / 10.0f;
+		    color_scale = color_scale * color_scale;
+		}
+		float da = aA[index] - bA[index];
+		float db = aB[index] - bB[index];
+		da = da * da;
+		db = db * db;
+		float delta_e = (da + db) * color_scale;
+		if (delta_e > factor) {
+		    pass = false;
+		}
+	    }
+	    if (!pass)
+		pixels_failed++;
+	}
+    }
+
+    if (aX) delete[] aX;
+    if (aY) delete[] aY;
+    if (aZ) delete[] aZ;
+    if (bX) delete[] bX;
+    if (bY) delete[] bY;
+    if (bZ) delete[] bZ;
+    if (aLum) delete[] aLum;
+    if (bLum) delete[] bLum;
+    lpyramid_destroy (la);
+    lpyramid_destroy (lb);
+    if (aA) delete aA;
+    if (bA) delete bA;
+    if (aB) delete aB;
+    if (bB) delete bB;
+
+    return pixels_failed;
+}
diff-tree 53c3a2f75b7f065b4c769ad087bbc9aaaaf6d7ee (from 358645d6eb68b4eaf79159e7aefa01bca4cb0acf)
Author: Carl Worth <cworth at cworth.org>
Date:   Thu Dec 14 01:00:43 2006 -0800

    pdiff: Rewrite main program to use cairo-based pdiff_compare interface

diff --git a/test/pdiff/CompareArgs.cpp b/test/pdiff/CompareArgs.cpp
index 0f9cb0f..38ff1f6 100644
--- a/test/pdiff/CompareArgs.cpp
+++ b/test/pdiff/CompareArgs.cpp
@@ -40,8 +40,8 @@ static const char *usage =
 
 CompareArgs::CompareArgs()
 {
-    ImgA = NULL;
-    ImgB = NULL;
+    surface_a = NULL;
+    surface_b = NULL;
     Verbose = false;
     FieldOfView = 45.0f;
     Gamma = 2.2f;
@@ -51,13 +51,12 @@ CompareArgs::CompareArgs()
 
 CompareArgs::~CompareArgs()
 {
-    if (ImgA) delete ImgA;
-    if (ImgB) delete ImgB;
+    cairo_surface_destroy (surface_a);
+    cairo_surface_destroy (surface_b);
 }
 
 bool CompareArgs::Parse_Args(int argc, char **argv)
 {
-    cairo_surface_t *surface;
     if (argc < 3) {
 	ErrorStr = copyright;
 	ErrorStr += usage;
@@ -65,29 +64,27 @@ bool CompareArgs::Parse_Args(int argc, c
     }
     for (int i = 0; i < argc; i++) {
 	if (i == 1) {
-	    surface = cairo_image_surface_create_from_png (argv[1]);
-	    if (cairo_surface_status (surface))
+	    surface_a = cairo_image_surface_create_from_png (argv[1]);
+	    if (cairo_surface_status (surface_a))
 	    {
 		ErrorStr = "FAIL: Cannot open ";
 		ErrorStr += argv[1];
 		ErrorStr += " ";
-		ErrorStr += cairo_status_to_string (cairo_surface_status (surface));
+		ErrorStr += cairo_status_to_string (cairo_surface_status (surface