[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_a));
 		ErrorStr += "\n";
 		return false;
 	    }
-	    ImgA = new RGBACairoImage (surface);
 	} else if (i == 2) {
-	    surface = cairo_image_surface_create_from_png (argv[2]);
-	    if (cairo_surface_status (surface))
+	    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));
+		ErrorStr += cairo_status_to_string (cairo_surface_status (surface_b));
 		ErrorStr += "\n";
 		return false;
 	    }
-	    ImgB = new RGBACairoImage (surface);
 	} else {
 	    if (strstr(argv[i], "-fov")) {
 		if (i + 1 < argc) {
diff --git a/test/pdiff/CompareArgs.h b/test/pdiff/CompareArgs.h
index 1cab0da..ca51bf0 100644
--- a/test/pdiff/CompareArgs.h
+++ b/test/pdiff/CompareArgs.h
@@ -18,6 +18,7 @@
 #define _COMPAREARGS_H
 
 #include <string>
+#include <cairo.h>
 
 class RGBAImage;
 class RGBACairoImage;
@@ -31,8 +32,8 @@ public:
     bool Parse_Args(int argc, char **argv);
     void Print_Args();
 
-    RGBAImage		*ImgA;			/* Image A */
-    RGBAImage		*ImgB;			/* Image B */
+    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 */
diff --git a/test/pdiff/Makefile.am b/test/pdiff/Makefile.am
index 0179f05..5dd4003 100644
--- a/test/pdiff/Makefile.am
+++ b/test/pdiff/Makefile.am
@@ -6,7 +6,6 @@ libpdiff_la_SOURCES = 		\
 	lpyramid.c		\
 	lpyramid.h		\
 	Metric.cpp		\
-	Metric.h		\
 	RGBAImage.cpp		\
 	RGBAImage.h
 
diff --git a/test/pdiff/Metric.cpp b/test/pdiff/Metric.cpp
index 44a704d..d9e56ac 100644
--- a/test/pdiff/Metric.cpp
+++ b/test/pdiff/Metric.cpp
@@ -14,7 +14,6 @@
   if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */
 
-#include "Metric.h"
 #include "CompareArgs.h"
 #include "RGBAImage.h"
 #include "lpyramid.h"
@@ -125,23 +124,6 @@ void XYZToLAB(float x, float y, float z,
     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;
-
-    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);
-}
-
 int Yee_Compare_Images(RGBAImage *image_a,
 		       RGBAImage *image_b,
 		       float gamma,
@@ -294,3 +276,20 @@ int Yee_Compare_Images(RGBAImage *image_
 
     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/Metric.h b/test/pdiff/Metric.h
deleted file mode 100644
index 8235a0e..0000000
--- a/test/pdiff/Metric.h
+++ /dev/null
@@ -1,32 +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
-*/
-
-#ifndef _METRIC_H
-#define _METRIC_H
-
-#include "RGBAImage.h"
-
-/* Image comparison metric using Yee's method
- * References: A Perceptual Metric for Production Testing, Hector Yee, Journal of Graphics Tools 2004
- */
-int Yee_Compare_Images(RGBAImage *image_a,
-		       RGBAImage *image_b,
-		       float gamma,
-		       float luminance,
-		       float field_of_view,
-		       bool verbose);
-
-#endif
diff --git a/test/pdiff/PerceptualDiff.cpp b/test/pdiff/PerceptualDiff.cpp
index 3affa16..eb89fbf 100644
--- a/test/pdiff/PerceptualDiff.cpp
+++ b/test/pdiff/PerceptualDiff.cpp
@@ -23,23 +23,46 @@
 #include "lpyramid.h"
 #include "RGBAImage.h"
 #include "CompareArgs.h"
-#include "Metric.h"
+#include "pdiff.h"
 
 static bool Yee_Compare(CompareArgs &args)
 {
-    if ((args.ImgA->Get_Width() != args.ImgB->Get_Width()) ||
-	(args.ImgA->Get_Height() != args.ImgB->Get_Height())) {
+    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;
+
+    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)) {
 	args.ErrorStr = "Image dimensions do not match\n";
 	return false;
     }
 
-    unsigned int i, dim, pixels_failed;
-    dim = args.ImgA->Get_Width() * args.ImgA->Get_Height();
+    unsigned int x, y, dim, pixels_failed;
     bool identical = true;
-    for (i = 0; i < dim; i++) {
-	if (args.ImgA->Get(i) != args.ImgB->Get(i)) {
-	    identical = false;
-	    break;
+
+    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) {
@@ -47,9 +70,9 @@ static bool Yee_Compare(CompareArgs &arg
 	return true;
     }
 
-    pixels_failed = Yee_Compare_Images (args.ImgA, args.ImgB,
-					args.Gamma, args.Luminance,
-					args.FieldOfView, args.Verbose);
+    pixels_failed = pdiff_compare (args.surface_a, args.surface_b,
+				   args.Gamma, args.Luminance,
+				   args.FieldOfView);
 
     if (pixels_failed < args.ThresholdPixels) {
 	args.ErrorStr = "Images are perceptually indistinguishable\n";
diff-tree 358645d6eb68b4eaf79159e7aefa01bca4cb0acf (from 4438fb6dca1b4b6c0a30d66508339c3997ee94a4)
Author: Carl Worth <cworth at cworth.org>
Date:   Thu Dec 14 00:42:52 2006 -0800

    pdiff: Rip out unused ImgDiff code, (dropping -output option)

diff --git a/test/pdiff/CompareArgs.cpp b/test/pdiff/CompareArgs.cpp
index 716f79e..0f9cb0f 100644
--- a/test/pdiff/CompareArgs.cpp
+++ b/test/pdiff/CompareArgs.cpp
@@ -34,7 +34,6 @@ static const char *usage =
 \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\
-\t-output o.ppm  : Write difference to the file o.ppm\n\
 \n\
 \n Note: Input files can also be in the PNG format\
 \n";
@@ -43,7 +42,6 @@ CompareArgs::CompareArgs()
 {
     ImgA = NULL;
     ImgB = NULL;
-    ImgDiff = NULL;
     Verbose = false;
     FieldOfView = 45.0f;
     Gamma = 2.2f;
@@ -55,7 +53,6 @@ CompareArgs::~CompareArgs()
 {
     if (ImgA) delete ImgA;
     if (ImgB) delete ImgB;
-    if (ImgDiff) delete ImgDiff;
 }
 
 bool CompareArgs::Parse_Args(int argc, char **argv)
@@ -110,10 +107,6 @@ bool CompareArgs::Parse_Args(int argc, c
 		if (i + 1 < argc) {
 		    Luminance = (float) atof(argv[i + 1]);
 		}
-	    }else 	if (strstr(argv[i], "-output")) {
-		if (i + 1 < argc) {
-		    ImgDiff = new RGBAImage(ImgA->Get_Width(), ImgA->Get_Height(), argv[i+1]);
-		}
 	    }
 	}
     } /* i */
diff --git a/test/pdiff/CompareArgs.h b/test/pdiff/CompareArgs.h
index 85f0174..1cab0da 100644
--- a/test/pdiff/CompareArgs.h
+++ b/test/pdiff/CompareArgs.h
@@ -33,7 +33,6 @@ public:
 
     RGBAImage		*ImgA;			/* Image A */
     RGBAImage		*ImgB;			/* Image B */
-    RGBAImage		*ImgDiff;		/* Diff image */
     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 */
diff --git a/test/pdiff/Metric.cpp b/test/pdiff/Metric.cpp
index c1a8b99..44a704d 100644
--- a/test/pdiff/Metric.cpp
+++ b/test/pdiff/Metric.cpp
@@ -274,17 +274,6 @@ int Yee_Compare_Images(RGBAImage *image_
 	    }
 	    if (!pass)
 		pixels_failed++;
-#if IMAGE_DIFF_ENABLED
-	    if (!pass) {
-		if (args.ImgDiff) {
-		    args.ImgDiff->Set(255, 0, 0, 255, index);
-		}
-	    } else {
-		if (args.ImgDiff) {
-		    args.ImgDiff->Set(0, 0, 0, 255, index);
-		}
-	    }
-#endif
 	}
     }
 
diff --git a/test/pdiff/PerceptualDiff.cpp b/test/pdiff/PerceptualDiff.cpp
index 6e098ed..3affa16 100644
--- a/test/pdiff/PerceptualDiff.cpp
+++ b/test/pdiff/PerceptualDiff.cpp
@@ -62,20 +62,6 @@ static bool Yee_Compare(CompareArgs &arg
     args.ErrorStr = "Images are visibly different\n";
     args.ErrorStr += different;
 
-    if (args.ImgDiff) {
-#if IMAGE_DIFF_CODE_ENABLED
-	if (args.ImgDiff->WritePPM()) {
-	    args.ErrorStr += "Wrote difference image to ";
-	    args.ErrorStr+= args.ImgDiff->Get_Name();
-	    args.ErrorStr += "\n";
-	} else {
-	    args.ErrorStr += "Could not write difference image to ";
-	    args.ErrorStr+= args.ImgDiff->Get_Name();
-	    args.ErrorStr += "\n";
-	}
-#endif
-	args.ErrorStr += "Generation of image \"difference\" is currently disabled\n";
-    }
     return false;
 }
 
diff --git a/test/pdiff/README.txt b/test/pdiff/README.txt
index a873f3c..922ddaf 100644
--- a/test/pdiff/README.txt
+++ b/test/pdiff/README.txt
@@ -36,10 +36,10 @@ a theatre has a field of view of around 
 -gamma g : The gamma to use to convert to RGB linear space. Default is 2.2
 -luminance l: The luminance of the display the observer is seeing. Default
  is 100 candela per meter squared
--output foo.ppm : Saves the difference image to foo.ppm
 
 Credits
 
 Hector Yee, project administrator and originator - hectorgon.blogspot.com
 Scott Corley, for png file IO code
-Mick Weiss, Linux build and release & QA
\ No newline at end of file
+Mick Weiss, Linux build and release & QA
+Carl Worth, Rewrite as library, depend on cairo, and port to C
\ No newline at end of file
diff-tree 4438fb6dca1b4b6c0a30d66508339c3997ee94a4 (from c7379fcea478fbd3fc5e09a10828586e641e2375)
Author: Carl Worth <cworth at cworth.org>
Date:   Thu Dec 14 00:38:39 2006 -0800

    pdiff: Move function that depends on command-line argument class to same file as main

diff --git a/test/pdiff/Metric.cpp b/test/pdiff/Metric.cpp
index 5bb90ce..c1a8b99 100644
--- a/test/pdiff/Metric.cpp
+++ b/test/pdiff/Metric.cpp
@@ -125,67 +125,6 @@ void XYZToLAB(float x, float y, float z,
     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);
-
-bool Yee_Compare(CompareArgs &args)
-{
-    if ((args.ImgA->Get_Width() != args.ImgB->Get_Width()) ||
-	(args.ImgA->Get_Height() != args.ImgB->Get_Height())) {
-	args.ErrorStr = "Image dimensions do not match\n";
-	return false;
-    }
-
-    unsigned int i, dim, pixels_failed;
-    dim = args.ImgA->Get_Width() * args.ImgA->Get_Height();
-    bool identical = true;
-    for (i = 0; i < dim; i++) {
-	if (args.ImgA->Get(i) != args.ImgB->Get(i)) {
-	    identical = false;
-	    break;
-	}
-    }
-    if (identical) {
-	args.ErrorStr = "Images are binary identical\n";
-	return true;
-    }
-
-    pixels_failed = Yee_Compare_Images (args.ImgA, args.ImgB,
-					args.Gamma, args.Luminance,
-					args.FieldOfView, args.Verbose);
-
-    if (pixels_failed < args.ThresholdPixels) {
-	args.ErrorStr = "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;
-
-    if (args.ImgDiff) {
-#if IMAGE_DIFF_CODE_ENABLED
-	if (args.ImgDiff->WritePPM()) {
-	    args.ErrorStr += "Wrote difference image to ";
-	    args.ErrorStr+= args.ImgDiff->Get_Name();
-	    args.ErrorStr += "\n";
-	} else {
-	    args.ErrorStr += "Could not write difference image to ";
-	    args.ErrorStr+= args.ImgDiff->Get_Name();
-	    args.ErrorStr += "\n";
-	}
-#endif
-	args.ErrorStr += "Generation of image \"difference\" is currently disabled\n";
-    }
-    return false;
-}
-
 int
 pdiff_compare (cairo_surface_t *surface_a,
 	       cairo_surface_t *surface_b,
diff --git a/test/pdiff/Metric.h b/test/pdiff/Metric.h
index 4801f86..8235a0e 100644
--- a/test/pdiff/Metric.h
+++ b/test/pdiff/Metric.h
@@ -17,11 +17,16 @@ if not, write to the Free Software Found
 #ifndef _METRIC_H
 #define _METRIC_H
 
-class CompareArgs;
+#include "RGBAImage.h"
 
 /* Image comparison metric using Yee's method
  * References: A Perceptual Metric for Production Testing, Hector Yee, Journal of Graphics Tools 2004
  */
-bool Yee_Compare(CompareArgs &args);
+int Yee_Compare_Images(RGBAImage *image_a,
+		       RGBAImage *image_b,
+		       float gamma,
+		       float luminance,
+		       float field_of_view,
+		       bool verbose);
 
 #endif
diff --git a/test/pdiff/PerceptualDiff.cpp b/test/pdiff/PerceptualDiff.cpp
index 7f2229d..6e098ed 100644
--- a/test/pdiff/PerceptualDiff.cpp
+++ b/test/pdiff/PerceptualDiff.cpp
@@ -25,6 +25,60 @@
 #include "CompareArgs.h"
 #include "Metric.h"
 
+static bool Yee_Compare(CompareArgs &args)
+{
+    if ((args.ImgA->Get_Width() != args.ImgB->Get_Width()) ||
+	(args.ImgA->Get_Height() != args.ImgB->Get_Height())) {
+	args.ErrorStr = "Image dimensions do not match\n";
+	return false;
+    }
+
+    unsigned int i, dim, pixels_failed;
+    dim = args.ImgA->Get_Width() * args.ImgA->Get_Height();
+    bool identical = true;
+    for (i = 0; i < dim; i++) {
+	if (args.ImgA->Get(i) != args.ImgB->Get(i)) {
+	    identical = false;
+	    break;
+	}
+    }
+    if (identical) {
+	args.ErrorStr = "Images are binary identical\n";
+	return true;
+    }
+
+    pixels_failed = Yee_Compare_Images (args.ImgA, args.ImgB,
+					args.Gamma, args.Luminance,
+					args.FieldOfView, args.Verbose);
+
+    if (pixels_failed < args.ThresholdPixels) {
+	args.ErrorStr = "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;
+
+    if (args.ImgDiff) {
+#if IMAGE_DIFF_CODE_ENABLED
+	if (args.ImgDiff->WritePPM()) {
+	    args.ErrorStr += "Wrote difference image to ";
+	    args.ErrorStr+= args.ImgDiff->Get_Name();
+	    args.ErrorStr += "\n";
+	} else {
+	    args.ErrorStr += "Could not write difference image to ";
+	    args.ErrorStr+= args.ImgDiff->Get_Name();
+	    args.ErrorStr += "\n";
+	}
+#endif
+	args.ErrorStr += "Generation of image \"difference\" is currently disabled\n";
+    }
+    return false;
+}
+
 int main(int argc, char **argv)
 {
     CompareArgs args;
diff --git a/test/pdiff/RGBAImage.h b/test/pdiff/RGBAImage.h
index ec33d22..710cabe 100644
--- a/test/pdiff/RGBAImage.h
+++ b/test/pdiff/RGBAImage.h
@@ -14,7 +14,7 @@
   if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */
 
-#ifndef _RGAIMAGE_H
+#ifndef _RGBAIMAGE_H
 #define _RGBAIMAGE_H
 
 #include<string>
diff-tree c7379fcea478fbd3fc5e09a10828586e641e2375 (from 29456d38658b8ba7267fadeac9820a68227df787)
Author: Carl Worth <cworth at cworth.org>
Date:   Thu Dec 14 00:30:54 2006 -0800

    pdiff: Rewrite Laplacian pyramid code from C++ to C

diff --git a/test/pdiff/LPyramid.cpp b/test/pdiff/LPyramid.cpp
deleted file mode 100644
index 5b69a8e..0000000
--- a/test/pdiff/LPyramid.cpp
+++ /dev/null
@@ -1,87 +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"
-
-
-/*
- * Construction/Destruction
- */
-
-LPyramid::LPyramid(float *image, int width, int height) :
-    Width(width),
-    Height(height)
-{
-    /* Make the Laplacian pyramid by successively
-     * copying the earlier levels and blurring them */
-    for (int i=0; i<MAX_PYR_LEVELS; i++) {
-	if (i == 0) {
-	    Levels[i] = Copy(image);
-	} else {
-	    Levels[i] = new float[Width * Height];
-	    Convolve(Levels[i], Levels[i - 1]);
-	}
-    }
-}
-
-LPyramid::~LPyramid()
-{
-    for (int i=0; i<MAX_PYR_LEVELS; i++) {
-	if (Levels[i]) delete Levels[i];
-    }
-}
-
-float *LPyramid::Copy(float *img)
-{
-    int max = Width * Height;
-    float *out = new float[max];
-    for (int i = 0; i < max; i++) out[i] = img[i];
-
-    return out;
-}
-
-void LPyramid::Convolve(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};
-
-    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];
-		}
-	    }
-	}
-    }
-}
-
-float LPyramid::Get_Value(int x, int y, int level)
-{
-    int index = x + y * Width;
-    int l = level;
-    if (l > MAX_PYR_LEVELS) l = MAX_PYR_LEVELS;
-    return Levels[level][index];
-}
diff --git a/test/pdiff/LPyramid.h b/test/pdiff/LPyramid.h
deleted file mode 100644
index d558616..0000000
--- a/test/pdiff/LPyramid.h
+++ /dev/null
@@ -1,38 +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
-*/
-#ifndef _LPYRAMID_H
-#define _LPYRAMID_H
-
-#define MAX_PYR_LEVELS 8
-
-class LPyramid
-{
-public:
-    LPyramid(float *image, int width, int height);
-    virtual ~LPyramid();
-    float Get_Value(int x, int y, int level);
-protected:
-    float *Copy(float *img);
-    void Convolve(float *a, float *b);
-
-    /* Succesively blurred versions of the original image */
-    float *Levels[MAX_PYR_LEVELS];
-
-    int Width;
-    int Height;
-};
-
-#endif /* _LPYRAMID_H */
diff --git a/test/pdiff/Makefile.am b/test/pdiff/Makefile.am
index 6443269..0179f05 100644
--- a/test/pdiff/Makefile.am
+++ b/test/pdiff/Makefile.am
@@ -3,8 +3,8 @@ EXTRA_PROGRAMS = perceptualdiff
 noinst_LTLIBRARIES = libpdiff.la
 libpdiff_la_SOURCES = 		\
 	pdiff.h			\
-	LPyramid.cpp		\
-	LPyramid.h		\
+	lpyramid.c		\
+	lpyramid.h		\
 	Metric.cpp		\
 	Metric.h		\
 	RGBAImage.cpp		\
diff --git a/test/pdiff/Metric.cpp b/test/pdiff/Metric.cpp
index 2f19ef9..5bb90ce 100644
--- a/test/pdiff/Metric.cpp
+++ b/test/pdiff/Metric.cpp
@@ -17,7 +17,7 @@
 #include "Metric.h"
 #include "CompareArgs.h"
 #include "RGBAImage.h"
-#include "LPyramid.h"
+#include "lpyramid.h"
 #include <math.h>
 #include "pdiff.h"
 
@@ -256,8 +256,8 @@ int Yee_Compare_Images(RGBAImage *image_
 
     if (verbose) printf("Constructing Laplacian Pyramids\n");
 
-    LPyramid *la = new LPyramid(aLum, w, h);
-    LPyramid *lb = new LPyramid(bLum, w, h);
+    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;
@@ -287,11 +287,11 @@ int Yee_Compare_Images(RGBAImage *image_
 	    float contrast[MAX_PYR_LEVELS - 2];
 	    float sum_contrast = 0;
 	    for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
-		float n1 = fabsf(la->Get_Value(x,y,i) - la->Get_Value(x,y,i + 1));
-		float n2 = fabsf(lb->Get_Value(x,y,i) - lb->Get_Value(x,y,i + 1));
+		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(la->Get_Value(x,y,i+2));
-		float d2 = fabsf(lb->Get_Value(x,y,i+2));
+		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;
@@ -299,7 +299,7 @@ int Yee_Compare_Images(RGBAImage *image_
 	    }
 	    if (sum_contrast < 1e-5) sum_contrast = 1e-5f;
 	    float F_mask[MAX_PYR_LEVELS - 2];
-	    float adapt = la->Get_Value(x,y,adaptation_level) + lb->Get_Value(x,y,adaptation_level);
+	    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++) {
@@ -311,7 +311,7 @@ int Yee_Compare_Images(RGBAImage *image_
 	    }
 	    if (factor < 1) factor = 1;
 	    if (factor > 10) factor = 10;
-	    float delta = fabsf(la->Get_Value(x,y,0) - lb->Get_Value(x,y,0));
+	    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)) {
@@ -357,8 +357,8 @@ int Yee_Compare_Images(RGBAImage *image_
     if (bZ) delete[] bZ;
     if (aLum) delete[] aLum;
     if (bLum) delete[] bLum;
-    if (la) delete la;
-    if (lb) delete lb;
+    lpyramid_destroy (la);
+    lpyramid_destroy (lb);
     if (aA) delete aA;
     if (bA) delete bA;
     if (aB) delete aB;
diff --git a/test/pdiff/PerceptualDiff.cpp b/test/pdiff/PerceptualDiff.cpp
index 1fd66b9..7f2229d 100644
--- a/test/pdiff/PerceptualDiff.cpp
+++ b/test/pdiff/PerceptualDiff.cpp
@@ -20,7 +20,7 @@
 #include <string.h>
 #include <math.h>
 #include <string>
-#include "LPyramid.h"
+#include "lpyramid.h"
 #include "RGBAImage.h"
 #include "CompareArgs.h"
 #include "Metric.h"
diff --git a/test/pdiff/lpyramid.cpp b/test/pdiff/lpyramid.cpp
new file mode 100644
index 0000000..92915ab
--- /dev/null
+++ b/test/pdiff/lpyramid.cpp
@@ -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.h b/test/pdiff/lpyramid.h
new file mode 100644
index 0000000..ab1235c
--- /dev/null
+++ b/test/pdiff/lpyramid.h
@@ -0,0 +1,32 @@
+/*
+  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
+*/
+#ifndef _LPYRAMID_H
+#define _LPYRAMID_H
+
+#define MAX_PYR_LEVELS 8
+
+typedef struct _lpyramid lpyramid_t;
+
+lpyramid_t *
+lpyramid_create (float *image, int width, int height);
+
+void
+lpyramid_destroy (lpyramid_t *pyramid);
+
+float
+lpyramid_get_value (lpyramid_t *pyramid, int x, int y, int level);
+
+#endif /* _LPYRAMID_H */
diff-tree 29456d38658b8ba7267fadeac9820a68227df787 (from 34a6af3c55cf8bba292cec8dc42fdc1917759a08)
Author: Carl Worth <cworth at cworth.org>
Date:   Thu Dec 14 00:13:23 2006 -0800

    pdiff: Convert C++-style comments to good old-fashioned C-style comments

diff --git a/test/pdiff/CompareArgs.cpp b/test/pdiff/CompareArgs.cpp
index 6b8fe8a..716f79e 100644
--- a/test/pdiff/CompareArgs.cpp
+++ b/test/pdiff/CompareArgs.cpp
@@ -116,7 +116,7 @@ bool CompareArgs::Parse_Args(int argc, c
 		}
 	    }
 	}
-    } // i
+    } /* i */
     return true;
 }
 
diff --git a/test/pdiff/CompareArgs.h b/test/pdiff/CompareArgs.h
index ab2a251..85f0174 100644
--- a/test/pdiff/CompareArgs.h
+++ b/test/pdiff/CompareArgs.h
@@ -22,7 +22,7 @@
 class RGBAImage;
 class RGBACairoImage;
 
-// Args to pass into the comparison function
+/* Args to pass into the comparison function */
 class CompareArgs
 {
 public:
@@ -31,15 +31,15 @@ public:
     bool Parse_Args(int argc, char **argv);
     void Print_Args();
 
-    RGBAImage		*ImgA;				// Image A
-    RGBAImage		*ImgB;				// Image B
-    RGBAImage		*ImgDiff;			// Diff image
-    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
-    std::string		ErrorStr;			// Error string
+    RGBAImage		*ImgA;			/* Image A */
+    RGBAImage		*ImgB;			/* Image B */
+    RGBAImage		*ImgDiff;		/* Diff image */
+    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 */
+    std::string		ErrorStr;		/* Error string */
 };
 
 #endif
diff --git a/test/pdiff/LPyramid.cpp b/test/pdiff/LPyramid.cpp
index 104179d..5b69a8e 100644
--- a/test/pdiff/LPyramid.cpp
+++ b/test/pdiff/LPyramid.cpp
@@ -17,16 +17,16 @@
 #include "LPyramid.h"
 
 
-//////////////////////////////////////////////////////////////////////
-// Construction/Destruction
-//////////////////////////////////////////////////////////////////////
+/*
+ * Construction/Destruction
+ */
 
 LPyramid::LPyramid(float *image, int width, int height) :
     Width(width),
     Height(height)
 {
-    // Make the Laplacian pyramid by successively
-    // copying the earlier levels and blurring them
+    /* Make the Laplacian pyramid by successively
+     * copying the earlier levels and blurring them */
     for (int i=0; i<MAX_PYR_LEVELS; i++) {
 	if (i == 0) {
 	    Levels[i] = Copy(image);
@@ -54,7 +54,7 @@ float *LPyramid::Copy(float *img)
 }
 
 void LPyramid::Convolve(float *a, float *b)
-// convolves image b with the filter kernel and stores it in a
+/* 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};
diff --git a/test/pdiff/LPyramid.h b/test/pdiff/LPyramid.h
index 27e041b..d558616 100644
--- a/test/pdiff/LPyramid.h
+++ b/test/pdiff/LPyramid.h
@@ -28,11 +28,11 @@ protected:
     float *Copy(float *img);
     void Convolve(float *a, float *b);
 
-    // Succesively blurred versions of the original image
+    /* Succesively blurred versions of the original image */
     float *Levels[MAX_PYR_LEVELS];
 
     int Width;
     int Height;
 };
 
-#endif // _LPYRAMID_H
+#endif /* _LPYRAMID_H */
diff --git a/test/pdiff/Metric.cpp b/test/pdiff/Metric.cpp
index dde17c0..2f19ef9 100644
--- a/test/pdiff/Metric.cpp
+++ b/test/pdiff/Metric.cpp
@@ -34,8 +34,9 @@
 
 float tvi(float adaptation_luminance)
 {
-    // returns the threshold luminance given the adaptation luminance
-    // units are candelas per meter squared
+    /* returns the threshold luminance given the adaptation luminance
+       units are candelas per meter squared
+    */
 
     float log_a, r, result;
     log_a = log10f(adaptation_luminance);
@@ -58,8 +59,9 @@ float tvi(float adaptation_luminance)
 
 }
 
-// computes the contrast sensitivity function (Barten SPIE 1989)
-// given the cycles per degree (cpd) and luminance (lum)
+/* 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;
@@ -86,10 +88,10 @@ float mask(float contrast)
     return result;
 }
 
-// convert Adobe RGB (1998) with reference white D65 to XYZ
+/* 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/
+    /* 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;
@@ -100,7 +102,7 @@ void XYZToLAB(float x, float y, float z,
     static float xw = -1;
     static float yw;
     static float zw;
-    // reference white
+    /* reference white */
     if (xw < 0) {
 	AdobeRGBToXYZ(1, 1, 1, xw, yw, zw);
     }
@@ -211,7 +213,7 @@ int Yee_Compare_Images(RGBAImage *image_
     unsigned int i, dim;
     dim = image_a->Get_Width() * image_a->Get_Height();
 
-    // assuming colorspaces are in Adobe RGB (1998) convert to XYZ
+    /* 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];
@@ -311,13 +313,13 @@ int Yee_Compare_Images(RGBAImage *image_
 	    if (factor > 10) factor = 10;
 	    float delta = fabsf(la->Get_Value(x,y,0) - lb->Get_Value(x,y,0));
 	    bool pass = true;
-	    // pure luminance test
+	    /* pure luminance test */
 	    if (delta > factor * tvi(adapt)) {
 		pass = false;
 	    } else {
-		// CIE delta E test with modifications
+		/* CIE delta E test with modifications */
 		float color_scale = 1.0f;
-		// ramp down the color test in scotopic regions
+		/* 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;
diff --git a/test/pdiff/Metric.h b/test/pdiff/Metric.h
index a6b234e..4801f86 100644
--- a/test/pdiff/Metric.h
+++ b/test/pdiff/Metric.h
@@ -19,8 +19,9 @@ if not, write to the Free Software Found
 
 class CompareArgs;
 
-// Image comparison metric using Yee's method
-// References: A Perceptual Metric for Production Testing, Hector Yee, Journal of Graphics Tools 2004
+/* Image comparison metric using Yee's method
+ * References: A Perceptual Metric for Production Testing, Hector Yee, Journal of Graphics Tools 2004
+ */
 bool Yee_Compare(CompareArgs &args);
 
 #endif
diff --git a/test/pdiff/RGBAImage.cpp b/test/pdiff/RGBAImage.cpp
index 08e5cd9..2c38f9c 100644
--- a/test/pdiff/RGBAImage.cpp
+++ b/test/pdiff/RGBAImage.cpp
@@ -21,7 +21,7 @@
 #include "tiff.h"
 #include "tiffio.h"
 
-// Reads Tiff Images
+/* Reads Tiff Images */
 RGBAImage* RGBAImage::ReadTiff(char *filename)
 {
     RGBAImage *fimg = 0;
@@ -40,7 +40,7 @@ RGBAImage* RGBAImage::ReadTiff(char *fil
 	    raster = (uint32*) _TIFFmalloc(npixels * sizeof (uint32));
 	    if (raster != NULL) {
 		if (TIFFRGBAImageGet(&img, raster, img.width, img.height)) {
-		    // result is in ABGR
+		    /* 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++) {
@@ -57,7 +57,7 @@ RGBAImage* RGBAImage::ReadTiff(char *fil
 }
 #endif /* HAVE_LIBTIFF */
 
-// This portion was written by Scott Corley
+/* This portion was written by Scott Corley */
 RGBAImage* RGBAImage::ReadPNG(char *filename)
 {
     RGBAImage *fimg = 0;
diff --git a/test/pdiff/RGBAImage.h b/test/pdiff/RGBAImage.h
index 5f662bb..ec33d22 100644
--- a/test/pdiff/RGBAImage.h
+++ b/test/pdiff/RGBAImage.h
@@ -20,7 +20,7 @@
 #include<string>
 #include<cairo.h>
 
-// assumes data is in the ABGR format
+/* assumes data is in the ABGR format */
 class RGBAImage
 {
 public:
diff-tree 34a6af3c55cf8bba292cec8dc42fdc1917759a08 (from d421a856d08fba2fa0fdbd362d947497a952b347)
Author: Carl Worth <cworth at cworth.org>
Date:   Wed Dec 13 18:10:21 2006 -0800

    pdiff: Delete all trailing whitespace.

diff --git a/test/pdiff/CompareArgs.cpp b/test/pdiff/CompareArgs.cpp
index 2c5e5d4..6b8fe8a 100644
--- a/test/pdiff/CompareArgs.cpp
+++ b/test/pdiff/CompareArgs.cpp
@@ -18,7 +18,7 @@
 #include "RGBAImage.h"
 #include <stdio.h>
 
-static const char* copyright = 
+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\
@@ -79,7 +79,7 @@ bool CompareArgs::Parse_Args(int argc, c
 		return false;
 	    }
 	    ImgA = new RGBACairoImage (surface);
-	} else if (i == 2) {			
+	} else if (i == 2) {
 	    surface = cairo_image_surface_create_from_png (argv[2]);
 	    if (cairo_surface_status (surface))
 	    {
diff --git a/test/pdiff/CompareArgs.h b/test/pdiff/CompareArgs.h
index fb5fc9d..ab2a251 100644
--- a/test/pdiff/CompareArgs.h
+++ b/test/pdiff/CompareArgs.h
@@ -28,9 +28,9 @@ class CompareArgs
 public:
     CompareArgs();
     ~CompareArgs();
-    bool Parse_Args(int argc, char **argv);	
+    bool Parse_Args(int argc, char **argv);
     void Print_Args();
-	
+
     RGBAImage		*ImgA;				// Image A
     RGBAImage		*ImgB;				// Image B
     RGBAImage		*ImgDiff;			// Diff image
diff --git a/test/pdiff/LPyramid.cpp b/test/pdiff/LPyramid.cpp
index cefd24b..104179d 100644
--- a/test/pdiff/LPyramid.cpp
+++ b/test/pdiff/LPyramid.cpp
@@ -49,7 +49,7 @@ float *LPyramid::Copy(float *img)
     int max = Width * Height;
     float *out = new float[max];
     for (int i = 0; i < max; i++) out[i] = img[i];
-	
+
     return out;
 }
 
@@ -72,7 +72,7 @@ void LPyramid::Convolve(float *a, float 
 		    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];
-		} 
+		}
 	    }
 	}
     }
diff --git a/test/pdiff/LPyramid.h b/test/pdiff/LPyramid.h
index bb9777a..27e041b 100644
--- a/test/pdiff/LPyramid.h
+++ b/test/pdiff/LPyramid.h
@@ -20,14 +20,14 @@
 
 class LPyramid
 {
-public:	
+public:
     LPyramid(float *image, int width, int height);
     virtual ~LPyramid();
     float Get_Value(int x, int y, int level);
 protected:
     float *Copy(float *img);
     void Convolve(float *a, float *b);
-	
+
     // Succesively blurred versions of the original image
     float *Levels[MAX_PYR_LEVELS];
 
diff --git a/test/pdiff/Metric.cpp b/test/pdiff/Metric.cpp
index b92dd5c..dde17c0 100644
--- a/test/pdiff/Metric.cpp
+++ b/test/pdiff/Metric.cpp
@@ -30,14 +30,14 @@
  * 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; 
+    float log_a, r, result;
     log_a = log10f(adaptation_luminance);
 
     if (log_a < -3.94f) {
@@ -52,24 +52,24 @@ float tvi(float adaptation_luminance)
 	r = log_a - 1.255f;
     }
 
-    result = powf(10.0f , r); 
+    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; 
-	
+    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;	
+
+    result = a * cpd * expf(-b * cpd) * sqrtf(1.0f + 0.06f * expf(b * cpd));
+
+    return result;
 }
 
 /*
@@ -81,10 +81,10 @@ 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); 
+    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)
@@ -137,7 +137,7 @@ bool Yee_Compare(CompareArgs &args)
 	args.ErrorStr = "Image dimensions do not match\n";
 	return false;
     }
-	
+
     unsigned int i, dim, pixels_failed;
     dim = args.ImgA->Get_Width() * args.ImgA->Get_Height();
     bool identical = true;
@@ -160,7 +160,7 @@ bool Yee_Compare(CompareArgs &args)
 	args.ErrorStr = "Images are perceptually indistinguishable\n";
 	return true;
     }
-	
+
     char different[100];
     sprintf(different, "%d pixels are different\n", pixels_failed);
 
@@ -220,14 +220,14 @@ int Yee_Compare_Images(RGBAImage *image_
     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();
@@ -251,17 +251,17 @@ int Yee_Compare_Images(RGBAImage *image_
 	    bLum[i] = bY[i] * luminance;
 	}
     }
-	
+
     if (verbose) printf("Constructing Laplacian Pyramids\n");
-	
+
     LPyramid *la = new LPyramid(aLum, w, h);
     LPyramid *lb = new LPyramid(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++) {
@@ -269,15 +269,15 @@ int Yee_Compare_Images(RGBAImage *image_
 	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++) {
@@ -301,7 +301,7 @@ int Yee_Compare_Images(RGBAImage *image_
 	    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)); 
+		F_mask[i] = mask(contrast[i] * csf(cpd[i], adapt));
 	    }
 	    float factor = 0;
 	    for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
@@ -346,7 +346,7 @@ int Yee_Compare_Images(RGBAImage *image_
 #endif
 	}
     }
-	
+
     if (aX) delete[] aX;
     if (aY) delete[] aY;
     if (aZ) delete[] aZ;
diff --git a/test/pdiff/PerceptualDiff.cpp b/test/pdiff/PerceptualDiff.cpp
index 70c6e12..1fd66b9 100644
--- a/test/pdiff/PerceptualDiff.cpp
+++ b/test/pdiff/PerceptualDiff.cpp
@@ -28,7 +28,7 @@
 int main(int argc, char **argv)
 {
     CompareArgs args;
-	
+
     if (!args.Parse_Args(argc, argv)) {
 	printf("%s", args.ErrorStr.c_str());
 	return -1;
diff --git a/test/pdiff/RGBAImage.cpp b/test/pdiff/RGBAImage.cpp
index 0b540d2..08e5cd9 100644
--- a/test/pdiff/RGBAImage.cpp
+++ b/test/pdiff/RGBAImage.cpp
@@ -25,13 +25,13 @@
 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;
@@ -120,9 +120,9 @@ RGBAImage* RGBAImage::ReadPNG(char *file
     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");
diff --git a/test/pdiff/RGBAImage.h b/test/pdiff/RGBAImage.h
index 31727fa..5f662bb 100644
--- a/test/pdiff/RGBAImage.h
+++ b/test/pdiff/RGBAImage.h
@@ -45,7 +45,7 @@ public:
     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);
diff-tree d421a856d08fba2fa0fdbd362d947497a952b347 (from 4f6611ef6cac3928427b6fc28dab40829ef0d748)
Author: Carl Worth <cworth at cworth.org>
Date:   Wed Dec 13 18:08:25 2006 -0800

    pdiff: Re-indent all code
    
    I've given up on trying to preserve the old code formatting
    for compatibility. We're not planning on augmenting the algorithm
    itself, just integrating it into cairo. So I don't expect to
    make changes that we'll be all that interested in pushing
    upstream.

diff --git a/test/pdiff/CompareArgs.cpp b/test/pdiff/CompareArgs.cpp
index 60520b0..2c5e5d4 100644
--- a/test/pdiff/CompareArgs.cpp
+++ b/test/pdiff/CompareArgs.cpp
@@ -1,17 +1,17 @@
 /*
-Comapre Args
-Copyright (C) 2006 Yangli Hector Yee
+  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.
+  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
+  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"
@@ -41,89 +41,89 @@ static const char *usage =
 
 CompareArgs::CompareArgs()
 {
-	ImgA = NULL;
-	ImgB = NULL;
-	ImgDiff = NULL;
-	Verbose = false;
-	FieldOfView = 45.0f;
-	Gamma = 2.2f;
-	ThresholdPixels = 100;
-	Luminance = 100.0f;
+    ImgA = NULL;
+    ImgB = NULL;
+    ImgDiff = NULL;
+    Verbose = false;
+    FieldOfView = 45.0f;
+    Gamma = 2.2f;
+    ThresholdPixels = 100;
+    Luminance = 100.0f;
 }
 
 CompareArgs::~CompareArgs()
 {
-	if (ImgA) delete ImgA;
-	if (ImgB) delete ImgB;
-	if (ImgDiff) delete ImgDiff;
+    if (ImgA) delete ImgA;
+    if (ImgB) delete ImgB;
+    if (ImgDiff) delete ImgDiff;
 }
 
 bool CompareArgs::Parse_Args(int argc, char **argv)
 {
-	cairo_surface_t *surface;
-	if (argc < 3) {
-		ErrorStr = copyright;
-		ErrorStr += usage;
+    cairo_surface_t *surface;
+    if (argc < 3) {
+	ErrorStr = copyright;
+	ErrorStr += usage;
+	return false;
+    }
+    for (int i = 0; i < argc; i++) {
+	if (i == 1) {
+	    surface = cairo_image_surface_create_from_png (argv[1]);
+	    if (cairo_surface_status (surface))
+	    {
+		ErrorStr = "FAIL: Cannot open ";
+		ErrorStr += argv[1];
+		ErrorStr += " ";
+		ErrorStr += cairo_status_to_string (cairo_surface_status (surface));
+		ErrorStr += "\n";
 		return false;
-	}
-	for (int i = 0; i < argc; i++) {
-		if (i == 1) {
-			surface = cairo_image_surface_create_from_png (argv[1]);
-			if (cairo_surface_status (surface))
-			{
-				ErrorStr = "FAIL: Cannot open ";
-				ErrorStr += argv[1];
-				ErrorStr += " ";
-				ErrorStr += cairo_status_to_string (cairo_surface_status (surface));
-				ErrorStr += "\n";
-				return false;
-			}
-			ImgA = new RGBACairoImage (surface);
-		} else if (i == 2) {			
-			surface = cairo_image_surface_create_from_png (argv[2]);
-			if (cairo_surface_status (surface))
-			{
-				ErrorStr = "FAIL: Cannot open ";
-				ErrorStr += argv[2];
-				ErrorStr += " ";
-				ErrorStr += cairo_status_to_string (cairo_surface_status (surface));
-				ErrorStr += "\n";
-				return false;
-			}
-			ImgB = new RGBACairoImage (surface);
-		} 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]);
-				}
-			}else 	if (strstr(argv[i], "-output")) {
-				if (i + 1 < argc) {
-					ImgDiff = new RGBAImage(ImgA->Get_Width(), ImgA->Get_Height(), argv[i+1]);
-				}
-			}
+	    }
+	    ImgA = new RGBACairoImage (surface);
+	} else if (i == 2) {			
+	    surface = cairo_image_surface_create_from_png (argv[2]);
+	    if (cairo_surface_status (surface))
+	    {
+		ErrorStr = "FAIL: Cannot open ";
+		ErrorStr += argv[2];
+		ErrorStr += " ";
+		ErrorStr += cairo_status_to_string (cairo_surface_status (surface));
+		ErrorStr += "\n";
+		return false;
+	    }
+	    ImgB = new RGBACairoImage (surface);
+	} 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]);
 		}
-	} // i
-	return true;
+	    }else 	if (strstr(argv[i], "-luminance")) {
+		if (i + 1 < argc) {
+		    Luminance = (float) atof(argv[i + 1]);
+		}
+	    }else 	if (strstr(argv[i], "-output")) {
+		if (i + 1 < argc) {
+		    ImgDiff = new RGBAImage(ImgA->Get_Width(), ImgA->Get_Height(), 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);
+    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/CompareArgs.h b/test/pdiff/CompareArgs.h
index fc6993f..fb5fc9d 100644
--- a/test/pdiff/CompareArgs.h
+++ b/test/pdiff/CompareArgs.h
@@ -1,17 +1,17 @@
 /*
-Comapre Args
-Copyright (C) 2006 Yangli Hector Yee
+  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.
+  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
+  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
@@ -26,20 +26,20 @@ class RGBACairoImage;
 class CompareArgs
 {
 public:
-	CompareArgs();
-	~CompareArgs();
-	bool Parse_Args(int argc, char **argv);	
-	void Print_Args();
+    CompareArgs();
+    ~CompareArgs();
+    bool Parse_Args(int argc, char **argv);	
+    void Print_Args();
 	
-	RGBAImage		*ImgA;				// Image A
-	RGBAImage		*ImgB;				// Image B
-	RGBAImage		*ImgDiff;			// Diff image
-	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
-	std::string		ErrorStr;			// Error string
+    RGBAImage		*ImgA;				// Image A
+    RGBAImage		*ImgB;				// Image B
+    RGBAImage		*ImgDiff;			// Diff image
+    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
+    std::string		ErrorStr;			// Error string
 };
 
 #endif
diff --git a/test/pdiff/LPyramid.cpp b/test/pdiff/LPyramid.cpp
index be0daa5..cefd24b 100644
--- a/test/pdiff/LPyramid.cpp
+++ b/test/pdiff/LPyramid.cpp
@@ -1,17 +1,17 @@
 /*
-Laplacian Pyramid
-Copyright (C) 2006 Yangli Hector Yee
+  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.
+  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
+  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"
@@ -22,66 +22,66 @@ if not, write to the Free Software Found
 //////////////////////////////////////////////////////////////////////
 
 LPyramid::LPyramid(float *image, int width, int height) :
-	Width(width),
-	Height(height)
+    Width(width),
+    Height(height)
 {
-	// Make the Laplacian pyramid by successively
-	// copying the earlier levels and blurring them
-	for (int i=0; i<MAX_PYR_LEVELS; i++) {
-		if (i == 0) {
-			Levels[i] = Copy(image);
-		} else {
-			Levels[i] = new float[Width * Height];
-			Convolve(Levels[i], Levels[i - 1]);
-		}
+    // Make the Laplacian pyramid by successively
+    // copying the earlier levels and blurring them
+    for (int i=0; i<MAX_PYR_LEVELS; i++) {
+	if (i == 0) {
+	    Levels[i] = Copy(image);
+	} else {
+	    Levels[i] = new float[Width * Height];
+	    Convolve(Levels[i], Levels[i - 1]);
 	}
+    }
 }
 
 LPyramid::~LPyramid()
 {
-	for (int i=0; i<MAX_PYR_LEVELS; i++) {
-		if (Levels[i]) delete Levels[i];
-	}
+    for (int i=0; i<MAX_PYR_LEVELS; i++) {
+	if (Levels[i]) delete Levels[i];
+    }
 }
 
 float *LPyramid::Copy(float *img)
 {
-	int max = Width * Height;
-	float *out = new float[max];
-	for (int i = 0; i < max; i++) out[i] = img[i];
+    int max = Width * Height;
+    float *out = new float[max];
+    for (int i = 0; i < max; i++) out[i] = img[i];
 	
-	return out;
+    return out;
 }
 
 void LPyramid::Convolve(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 y,x,i,j,nx,ny;
+    const float Kernel[] = {0.05f, 0.25f, 0.4f, 0.25f, 0.05f};
 
-	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];
-				} 
-			}
-		}
+    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];
+		} 
+	    }
 	}
+    }
 }
 
 float LPyramid::Get_Value(int x, int y, int level)
 {
-	int index = x + y * Width;
-	int l = level;
-	if (l > MAX_PYR_LEVELS) l = MAX_PYR_LEVELS;
-	return Levels[level][index];
+    int index = x + y * Width;
+    int l = level;
+    if (l > MAX_PYR_LEVELS) l = MAX_PYR_LEVELS;
+    return Levels[level][index];
 }
diff --git a/test/pdiff/LPyramid.h b/test/pdiff/LPyramid.h
index 162d464..bb9777a 100644
--- a/test/pdiff/LPyramid.h
+++ b/test/pdiff/LPyramid.h
@@ -1,17 +1,17 @@
 /*
-Laplacian Pyramid
-Copyright (C) 2006 Yangli Hector Yee
+  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.
+  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
+  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 _LPYRAMID_H
 #define _LPYRAMID_H
@@ -21,18 +21,18 @@ if not, write to the Free Software Found
 class LPyramid
 {
 public:	
-	LPyramid(float *image, int width, int height);
-	virtual ~LPyramid();
-	float Get_Value(int x, int y, int level);
+    LPyramid(float *image, int width, int height);
+    virtual ~LPyramid();
+    float Get_Value(int x, int y, int level);
 protected:
-	float *Copy(float *img);
-	void Convolve(float *a, float *b);
+    float *Copy(float *img);
+    void Convolve(float *a, float *b);
 	
-	// Succesively blurred versions of the original image
-	float *Levels[MAX_PYR_LEVELS];
+    // Succesively blurred versions of the original image
+    float *Levels[MAX_PYR_LEVELS];
 
-	int Width;
-	int Height;
+    int Width;
+    int Height;
 };
 
 #endif // _LPYRAMID_H
diff --git a/test/pdiff/Metric.cpp b/test/pdiff/Metric.cpp
index ded0afc..b92dd5c 100644
--- a/test/pdiff/Metric.cpp
+++ b/test/pdiff/Metric.cpp
@@ -1,17 +1,17 @@
 /*
-Metric
-Copyright (C) 2006 Yangli Hector Yee
+  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.
+  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
+  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 "Metric.h"
@@ -26,35 +26,35 @@ if not, write to the Free Software Found
 #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
-*/ 
+ * 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
+    // returns the threshold luminance given the adaptation luminance
+    // units are candelas per meter squared
 
-      float log_a, r, result; 
-      log_a = log10f(adaptation_luminance);
+    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;
-      }
+    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); 
+    result = powf(10.0f , r); 
 
-      return result;
+    return result;
 
 } 
 
@@ -62,65 +62,65 @@ float tvi(float adaptation_luminance)
 // given the cycles per degree (cpd) and luminance (lum)
 float csf(float cpd, float lum)
 {
-	float a, b, result; 
+    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);
+    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)); 
+    result = a * cpd * expf(-b * cpd) * sqrtf(1.0f + 0.06f * expf(b * cpd)); 
 	
-	return result;	
+    return result;	
 }
 
 /*
-* Visual Masking Function
-* from Daly 1993
-*/
+ * 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); 
+    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;
+    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;
+    // 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;
-		}
+    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]);
+    }
+    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,
@@ -132,56 +132,56 @@ int Yee_Compare_Images(RGBAImage *image_
 
 bool Yee_Compare(CompareArgs &args)
 {
-	if ((args.ImgA->Get_Width() != args.ImgB->Get_Width()) ||
-		(args.ImgA->Get_Height() != args.ImgB->Get_Height())) {
-		args.ErrorStr = "Image dimensions do not match\n";
-		return false;
-	}
+    if ((args.ImgA->Get_Width() != args.ImgB->Get_Width()) ||
+	(args.ImgA->Get_Height() != args.ImgB->Get_Height())) {
+	args.ErrorStr = "Image dimensions do not match\n";
+	return false;
+    }
 	
-	unsigned int i, dim, pixels_failed;
-	dim = args.ImgA->Get_Width() * args.ImgA->Get_Height();
-	bool identical = true;
-	for (i = 0; i < dim; i++) {
-		if (args.ImgA->Get(i) != args.ImgB->Get(i)) {
-		  identical = false;
-		  break;
-		}
-	}
-	if (identical) {
-		args.ErrorStr = "Images are binary identical\n";
-		return true;
-	}
-
-	pixels_failed = Yee_Compare_Images (args.ImgA, args.ImgB,
-					    args.Gamma, args.Luminance,
-					    args.FieldOfView, args.Verbose);
-
-	if (pixels_failed < args.ThresholdPixels) {
-		args.ErrorStr = "Images are perceptually indistinguishable\n";
-		return true;
+    unsigned int i, dim, pixels_failed;
+    dim = args.ImgA->Get_Width() * args.ImgA->Get_Height();
+    bool identical = true;
+    for (i = 0; i < dim; i++) {
+	if (args.ImgA->Get(i) != args.ImgB->Get(i)) {
+	    identical = false;
+	    break;
 	}
+    }
+    if (identical) {
+	args.ErrorStr = "Images are binary identical\n";
+	return true;
+    }
+
+    pixels_failed = Yee_Compare_Images (args.ImgA, args.ImgB,
+					args.Gamma, args.Luminance,
+					args.FieldOfView, args.Verbose);
+
+    if (pixels_failed < args.ThresholdPixels) {
+	args.ErrorStr = "Images are perceptually indistinguishable\n";
+	return true;
+    }
 	
-	char different[100];
-	sprintf(different, "%d pixels are different\n", pixels_failed);
+    char different[100];
+    sprintf(different, "%d pixels are different\n", pixels_failed);
 
-	args.ErrorStr = "Images are visibly different\n";
-	args.ErrorStr += different;
+    args.ErrorStr = "Images are visibly different\n";
+    args.ErrorStr += different;
 
-	if (args.ImgDiff) {
+    if (args.ImgDiff) {
 #if IMAGE_DIFF_CODE_ENABLED
-		if (args.ImgDiff->WritePPM()) {
-			args.ErrorStr += "Wrote difference image to ";
-			args.ErrorStr+= args.ImgDiff->Get_Name();
-			args.ErrorStr += "\n";
-		} else {
-			args.ErrorStr += "Could not write difference image to ";
-			args.ErrorStr+= args.ImgDiff->Get_Name();
-			args.ErrorStr += "\n";
-		}
-#endif
-		args.ErrorStr += "Generation of image \"difference\" is currently disabled\n";
+	if (args.ImgDiff->WritePPM()) {
+	    args.ErrorStr += "Wrote difference image to ";
+	    args.ErrorStr+= args.ImgDiff->Get_Name();
+	    args.ErrorStr += "\n";
+	} else {
+	    args.ErrorStr += "Could not write difference image to ";
+	    args.ErrorStr+= args.ImgDiff->Get_Name();
+	    args.ErrorStr += "\n";
 	}
-	return false;
+#endif
+	args.ErrorStr += "Generation of image \"difference\" is currently disabled\n";
+    }
+    return false;
 }
 
 int
@@ -191,14 +191,14 @@ pdiff_compare (cairo_surface_t *surface_
 	       double luminance,
 	       double field_of_view)
 {
-	RGBAImage *image_a, *image_b;
+    RGBAImage *image_a, *image_b;
 
-	image_a = new RGBACairoImage (surface_a);
-	image_b = new RGBACairoImage (surface_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);
+    return Yee_Compare_Images (image_a, image_b,
+			       gamma, luminance,
+			       field_of_view, false);
 }
 
 int Yee_Compare_Images(RGBAImage *image_a,
@@ -208,159 +208,159 @@ int Yee_Compare_Images(RGBAImage *image_
 		       float field_of_view,
 		       bool verbose)
 {
-	unsigned int i, dim;
-	dim = image_a->Get_Width() * image_a->Get_Height();
+    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;
-		}
+    // 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 *la = new LPyramid(aLum, w, h);
-	LPyramid *lb = new LPyramid(bLum, w, h);
+    if (verbose) printf("Constructing Laplacian Pyramids\n");
 	
-	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;
+    LPyramid *la = new LPyramid(aLum, w, h);
+    LPyramid *lb = new LPyramid(bLum, w, h);
 	
-	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(la->Get_Value(x,y,i) - la->Get_Value(x,y,i + 1));
-			float n2 = fabsf(lb->Get_Value(x,y,i) - lb->Get_Value(x,y,i + 1));
-			float numerator = (n1 > n2) ? n1 : n2;
-			float d1 = fabsf(la->Get_Value(x,y,i+2));
-			float d2 = fabsf(lb->Get_Value(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 = la->Get_Value(x,y,adaptation_level) + lb->Get_Value(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 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(la->Get_Value(x,y,i) - la->Get_Value(x,y,i + 1));
+		float n2 = fabsf(lb->Get_Value(x,y,i) - lb->Get_Value(x,y,i + 1));
+		float numerator = (n1 > n2) ? n1 : n2;
+		float d1 = fabsf(la->Get_Value(x,y,i+2));
+		float d2 = fabsf(lb->Get_Value(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 = la->Get_Value(x,y,adaptation_level) + lb->Get_Value(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(la->Get_Value(x,y,0) - lb->Get_Value(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 factor = 0;
-		for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
-			factor += contrast[i] * F_freq[i] * F_mask[i] / sum_contrast;
+		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 (factor < 1) factor = 1;
-		if (factor > 10) factor = 10;
-		float delta = fabsf(la->Get_Value(x,y,0) - lb->Get_Value(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 (!pass)
+		pixels_failed++;
 #if IMAGE_DIFF_ENABLED
-		if (!pass) {
-			if (args.ImgDiff) {
-				args.ImgDiff->Set(255, 0, 0, 255, index);
-			}
-		} else {
-			if (args.ImgDiff) {
-				args.ImgDiff->Set(0, 0, 0, 255, index);
-			}
+	    if (!pass) {
+		if (args.ImgDiff) {
+		    args.ImgDiff->Set(255, 0, 0, 255, index);
+		}
+	    } else {
+		if (args.ImgDiff) {
+		    args.ImgDiff->Set(0, 0, 0, 255, index);
 		}
+	    }
 #endif
-	  }
 	}
+    }
 	
-	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;
-	if (la) delete la;
-	if (lb) delete lb;
-	if (aA) delete aA;
-	if (bA) delete bA;
-	if (aB) delete aB;
-	if (bB) delete bB;
+    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;
+    if (la) delete la;
+    if (lb) delete lb;
+    if (aA) delete aA;
+    if (bA) delete bA;
+    if (aB) delete aB;
+    if (bB) delete bB;
 
-	return pixels_failed;
+    return pixels_failed;
 }
diff --git a/test/pdiff/PerceptualDiff.cpp b/test/pdiff/PerceptualDiff.cpp
index ee79666..70c6e12 100644
--- a/test/pdiff/PerceptualDiff.cpp
+++ b/test/pdiff/PerceptualDiff.cpp
@@ -1,19 +1,19 @@
 /*
-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
+  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 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.
+  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
+  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>
@@ -27,19 +27,19 @@ if not, write to the Free Software Found
 
 int main(int argc, char **argv)
 {
-	CompareArgs args;
+    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;
+    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 --git a/test/pdiff/RGBAImage.cpp b/test/pdiff/RGBAImage.cpp
index a39195f..0b540d2 100644
--- a/test/pdiff/RGBAImage.cpp
+++ b/test/pdiff/RGBAImage.cpp
@@ -1,17 +1,17 @@
 /*
-RGBAImage.cpp
-Copyright (C) 2006 Yangli Hector Yee
+  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.
+  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
+  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"
@@ -24,60 +24,60 @@ if not, write to the Free Software Found
 // Reads Tiff Images
 RGBAImage* RGBAImage::ReadTiff(char *filename)
 {
-	RGBAImage *fimg = 0;
+    RGBAImage *fimg = 0;
 	
     TIFF* tif = TIFFOpen(filename, "r");
-	char emsg[1024];
-	emsg[0] = 0;
+    char emsg[1024];
+    emsg[0] = 0;
     if (tif) {
-		TIFFRGBAImage img;
+	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);
+	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;
+	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];
+    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;
-	}
+    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);
+	(PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
+	 NULL, NULL);
     if (!png_ptr)
         return (NULL);
 
@@ -85,7 +85,7 @@ RGBAImage* RGBAImage::ReadPNG(char *file
     if (!info_ptr)
     {
         png_destroy_read_struct(&png_ptr,
-           (png_infopp)NULL, (png_infopp)NULL);
+				(png_infopp)NULL, (png_infopp)NULL);
         return (NULL);
     }
 
@@ -93,52 +93,52 @@ RGBAImage* RGBAImage::ReadPNG(char *file
     if (!end_info)
     {
         png_destroy_read_struct(&png_ptr, &info_ptr,
-          (png_infopp)NULL);
+				(png_infopp)NULL);
         return (NULL);
     }
 
-	png_init_io(png_ptr, fp);
-	png_set_sig_bytes(png_ptr, 8);
+    png_init_io(png_ptr, fp);
+    png_set_sig_bytes(png_ptr, 8);
 
-	png_read_png(png_ptr, info_ptr, 0, NULL);
+    png_read_png(png_ptr, info_ptr, 0, NULL);
 
-	png_bytep *row_pointers;
-	row_pointers = png_get_rows(png_ptr, info_ptr);
+    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);
-		}
+    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;
+    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);
-		}
+    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;
+    }
+    fclose(out);
+    return true;
 }
diff --git a/test/pdiff/RGBAImage.h b/test/pdiff/RGBAImage.h
index f5d27c5..31727fa 100644
--- a/test/pdiff/RGBAImage.h
+++ b/test/pdiff/RGBAImage.h
@@ -1,17 +1,17 @@
 /*
-RGBAImage.h
-Copyright (C) 2006 Yangli Hector Yee
+  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.
+  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
+  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 _RGAIMAGE_H
@@ -24,51 +24,51 @@ if not, write to the Free Software Found
 class RGBAImage
 {
 public:
-        RGBAImage() { Width = 0; Height = 0; Data = 0; }
-	RGBAImage(int w, int h, const char *name = 0)
+    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];
+	    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)
+    ~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; }
+    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);
+    bool WritePPM();
+    static RGBAImage* ReadTiff(char *filename);
+    static RGBAImage* ReadPNG(char *filename);
 protected:
-	int Width;
-	int Height;
-	std::string Name;
-	unsigned int *Data;
+    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);
+	{
+	    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 {
diff --git a/test/pdiff/pdiff.h b/test/pdiff/pdiff.h
index 7c2c401..195a34c 100644
--- a/test/pdiff/pdiff.h
+++ b/test/pdiff/pdiff.h
@@ -1,17 +1,17 @@
 /*
-Copyright (C) 2006 Yangli Hector Yee
-Copyright (C) 2006 Red Hat, Inc.
+  Copyright (C) 2006 Yangli Hector Yee
+  Copyright (C) 2006 Red Hat, Inc.
 
-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.
+  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
+  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 _PDIFF_H
diff-tree 4f6611ef6cac3928427b6fc28dab40829ef0d748 (from ccb3a6c4deadeaecf133dce6f1b152507ab5a14f)
Author: Carl Worth <cworth at cworth.org>
Date:   Wed Dec 13 17:40:59 2006 -0800

    pdiff: Fix line endings

diff --git a/test/pdiff/LPyramid.cpp b/test/pdiff/LPyramid.cpp
index 0e8d68a..be0daa5 100644
--- a/test/pdiff/LPyramid.cpp
+++ b/test/pdiff/LPyramid.cpp
@@ -1,87 +1,87 @@
-/*
-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"
-
-
-//////////////////////////////////////////////////////////////////////
-// Construction/Destruction
-//////////////////////////////////////////////////////////////////////
-
-LPyramid::LPyramid(float *image, int width, int height) :
-	Width(width),
-	Height(height)
-{
-	// Make the Laplacian pyramid by successively
-	// copying the earlier levels and blurring them
-	for (int i=0; i<MAX_PYR_LEVELS; i++) {
-		if (i == 0) {
-			Levels[i] = Copy(image);
-		} else {
-			Levels[i] = new float[Width * Height];
-			Convolve(Levels[i], Levels[i - 1]);
-		}
-	}
-}
-
-LPyramid::~LPyramid()
-{
-	for (int i=0; i<MAX_PYR_LEVELS; i++) {
-		if (Levels[i]) delete Levels[i];
-	}
-}
-
-float *LPyramid::Copy(float *img)
-{
-	int max = Width * Height;
-	float *out = new float[max];
-	for (int i = 0; i < max; i++) out[i] = img[i];
-	
-	return out;
-}
-
-void LPyramid::Convolve(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};
-
-	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];
-				} 
-			}
-		}
-	}
-}
-
-float LPyramid::Get_Value(int x, int y, int level)
-{
-	int index = x + y * Width;
-	int l = level;
-	if (l > MAX_PYR_LEVELS) l = MAX_PYR_LEVELS;
-	return Levels[level][index];
-}
+/*
+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"
+
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+LPyramid::LPyramid(float *image, int width, int height) :
+	Width(width),
+	Height(height)
+{
+	// Make the Laplacian pyramid by successively
+	// copying the earlier levels and blurring them
+	for (int i=0; i<MAX_PYR_LEVELS; i++) {
+		if (i == 0) {
+			Levels[i] = Copy(image);
+		} else {
+			Levels[i] = new float[Width * Height];
+			Convolve(Levels[i], Levels[i - 1]);
+		}
+	}
+}
+
+LPyramid::~LPyramid()
+{
+	for (int i=0; i<MAX_PYR_LEVELS; i++) {
+		if (Levels[i]) delete Levels[i];
+	}
+}
+
+float *LPyramid::Copy(float *img)
+{
+	int max = Width * Height;
+	float *out = new float[max];
+	for (int i = 0; i < max; i++) out[i] = img[i];
+	
+	return out;
+}
+
+void LPyramid::Convolve(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};
+
+	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];
+				} 
+			}
+		}
+	}
+}
+
+float LPyramid::Get_Value(int x, int y, int level)
+{
+	int index = x + y * Width;
+	int l = level;
+	if (l > MAX_PYR_LEVELS) l = MAX_PYR_LEVELS;
+	return Levels[level][index];
+}
diff --git a/test/pdiff/LPyramid.h b/test/pdiff/LPyramid.h
index b53f3ef..162d464 100644
--- a/test/pdiff/LPyramid.h
+++ b/test/pdiff/LPyramid.h
@@ -1,38 +1,38 @@
-/*
-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
-*/
-#ifndef _LPYRAMID_H
-#define _LPYRAMID_H
-
-#define MAX_PYR_LEVELS 8
-
-class LPyramid
-{
-public:	
-	LPyramid(float *image, int width, int height);
-	virtual ~LPyramid();
-	float Get_Value(int x, int y, int level);
-protected:
-	float *Copy(float *img);
-	void Convolve(float *a, float *b);
-	
-	// Succesively blurred versions of the original image
-	float *Levels[MAX_PYR_LEVELS];
-
-	int Width;
-	int Height;
-};
-
-#endif // _LPYRAMID_H
+/*
+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
+*/
+#ifndef _LPYRAMID_H
+#define _LPYRAMID_H
+
+#define MAX_PYR_LEVELS 8
+
+class LPyramid
+{
+public:	
+	LPyramid(float *image, int width, int height);
+	virtual ~LPyramid();
+	float Get_Value(int x, int y, int level);
+protected:
+	float *Copy(float *img);
+	void Convolve(float *a, float *b);
+	
+	// Succesively blurred versions of the original image
+	float *Levels[MAX_PYR_LEVELS];
+
+	int Width;
+	int Height;
+};
+
+#endif // _LPYRAMID_H
diff-tree ccb3a6c4deadeaecf133dce6f1b152507ab5a14f (from 55f776876d231a035cdc5da9bb90cbba14f19248)
Author: Carl Worth <cworth at cworth.org>
Date:   Tue Dec 12 16:49:27 2006 -0800

    pdiff: Compile pdiff algorithm as a libtool convenience library
    
    The convenience library provides a pdiff_compare function with a
    cairo interface into the perceptual diff algorithm.

diff --git a/test/Makefile.am b/test/Makefile.am
index 65325f1..26f28b5 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -1,4 +1,4 @@
-DIST_SUBDIRS=pdiff
+SUBDIRS=pdiff .
 
 # Here are all the tests that are run unconditionally
 TESTS = 			\
diff --git a/test/pdiff/Makefile.am b/test/pdiff/Makefile.am
index 9f441b9..6443269 100644
--- a/test/pdiff/Makefile.am
+++ b/test/pdiff/Makefile.am
@@ -1,15 +1,19 @@
 EXTRA_PROGRAMS = perceptualdiff
 
-perceptualdiff_SOURCES =	\
-	CompareArgs.cpp		\
-	CompareArgs.h		\
+noinst_LTLIBRARIES = libpdiff.la
+libpdiff_la_SOURCES = 		\
+	pdiff.h			\
 	LPyramid.cpp		\
 	LPyramid.h		\
 	Metric.cpp		\
 	Metric.h		\
-	PerceptualDiff.cpp	\
 	RGBAImage.cpp		\
 	RGBAImage.h
 
+perceptualdiff_SOURCES =	\
+	CompareArgs.cpp		\
+	CompareArgs.h		\
+	PerceptualDiff.cpp
+
 INCLUDES = -I$(top_srcdir)/src
-LDADD = $(top_builddir)/src/libcairo.la
+LDADD = libpdiff.la $(top_builddir)/src/libcairo.la
diff --git a/test/pdiff/Metric.cpp b/test/pdiff/Metric.cpp
index 7974fa5..ded0afc 100644
--- a/test/pdiff/Metric.cpp
+++ b/test/pdiff/Metric.cpp
@@ -19,6 +19,7 @@ if not, write to the Free Software Found
 #include "RGBAImage.h"
 #include "LPyramid.h"
 #include <math.h>
+#include "pdiff.h"
 
 #ifndef M_PI
 #define M_PI 3.14159265f
@@ -183,6 +184,23 @@ bool Yee_Compare(CompareArgs &args)
 	return false;
 }
 
+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);
+}
+
 int Yee_Compare_Images(RGBAImage *image_a,
 		       RGBAImage *image_b,
 		       float gamma,
diff --git a/test/pdiff/RGBAImage.h b/test/pdiff/RGBAImage.h
index 6aa5ff9..f5d27c5 100644
--- a/test/pdiff/RGBAImage.h
+++ b/test/pdiff/RGBAImage.h
@@ -99,7 +99,7 @@ public:
     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_Pixel_Unpremultiply(i)); }
+    unsigned int Get(int i) const { return ARGB_to_ABGR(Get_Unpremultiply(i)); }
 };
 
 #endif
diff --git a/test/pdiff/pdiff.h b/test/pdiff/pdiff.h
new file mode 100644
index 0000000..7c2c401
--- /dev/null
+++ b/test/pdiff/pdiff.h
@@ -0,0 +1,38 @@
+/*
+Copyright (C) 2006 Yangli Hector Yee
+Copyright (C) 2006 Red Hat, Inc.
+
+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 _PDIFF_H
+#define _PDIFF_H
+
+#ifdef  __cplusplus
+extern "C" {
+#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
+ */
+int
+pdiff_compare (cairo_surface_t *surface_a,
+	       cairo_surface_t *surface_b,
+	       double gamma,
+	       double luminance,
+	       double field_of_view);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
diff-tree 55f776876d231a035cdc5da9bb90cbba14f19248 (from 0d7870b6bf13edfe513e2de25a5814a0a1b78c79)
Author: Carl Worth <cworth at cworth.org>
Date:   Tue Dec 12 16:37:35 2006 -0800

    test: Rework buffer_diff interface as new compare_surfaces
    
    This is a slightly kinder interface that accepts cairo_image_surface_t
    pointers rather than pointers to the raw image data and width, height,
    stride. This brings us closer to hooking up the pdiff code.

diff --git a/test/buffer-diff.c b/test/buffer-diff.c
index 819ba16..99501bc 100644
--- a/test/buffer-diff.c
+++ b/test/buffer-diff.c
@@ -117,17 +117,19 @@ buffer_diff_core (unsigned char *_buf_a,
 }
 
 void
-buffer_diff (unsigned char *buf_a,
-	     unsigned char *buf_b,
-	     unsigned char *buf_diff,
-	     int	   width,
-	     int	   height,
-	     int	   stride,
-	     buffer_diff_result_t *result)
-{
-    buffer_diff_core(buf_a, buf_b, buf_diff,
-		     width, height, stride, 0xffffffff,
-		     result);
+compare_surfaces (cairo_surface_t	*surface_a,
+		  cairo_surface_t	*surface_b,
+		  cairo_surface_t	*surface_diff,
+		  buffer_diff_result_t	*result)
+{
+    buffer_diff_core (cairo_image_surface_get_data (surface_a),
+		      cairo_image_surface_get_data (surface_b),
+		      cairo_image_surface_get_data (surface_diff),
+		      cairo_image_surface_get_width (surface_a),
+		      cairo_image_surface_get_height (surface_a),
+		      cairo_image_surface_get_stride (surface_a),
+		      0xffffffff,
+		      result);
 }
 
 void
@@ -304,11 +306,7 @@ image_diff_core (const char *filename_a,
     surface_diff = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
 					       width_a, height_a);
 
-    buffer_diff (cairo_image_surface_get_data (surface_a),
-		 cairo_image_surface_get_data (surface_b),
-		 cairo_image_surface_get_data (surface_diff),
-		 width_a, height_a, stride_a,
-		 result);
+    compare_surfaces (surface_a, surface_b, surface_diff, result);
 
     if (result->pixels_changed) {
 	FILE *png_file;
diff --git a/test/buffer-diff.h b/test/buffer-diff.h
index d95c213..cd35345 100644
--- a/test/buffer-diff.h
+++ b/test/buffer-diff.h
@@ -36,22 +36,19 @@ typedef struct _buffer_diff_result {
     unsigned int max_diff;
 } buffer_diff_result_t;
 
-/* Compares two image buffers.
+/* Compares two image surfaces
  *
  * Provides number of pixels changed and maximum single-channel
  * difference in result.
  *
- * Also fills in a "diff" buffer intended to visually show where the
+ * Also fills in a "diff" surface intended to visually show where the
  * images differ.
  */
 void
-buffer_diff (unsigned char *buf_a,
-	     unsigned char *buf_b,
-	     unsigned char *buf_diff,
-	     int	    width,
-	     int	    height,
-	     int	    stride,
-	     buffer_diff_result_t *result);
+compare_surfaces (cairo_surface_t	*surface_a,
+		  cairo_surface_t	*surface_b,
+		  cairo_surface_t	*surface_diff,
+		  buffer_diff_result_t *result);
 
 /* Compares two image buffers ignoring the alpha channel.
  *
diff-tree 0d7870b6bf13edfe513e2de25a5814a0a1b78c79 (from a87f494d4b91f3acc78d6d7dd737939633f28d71)
Author: Carl Worth <cworth at cworth.org>
Date:   Tue Dec 12 16:15:08 2006 -0800

    pdiff: Teach pdiff code to accept cairo image surfaces
    
    This is a second small step in enabling cairo's test suite and the
    pdiff code to start working together.

diff --git a/test/pdiff/CompareArgs.cpp b/test/pdiff/CompareArgs.cpp
index aa69a7d..60520b0 100644
--- a/test/pdiff/CompareArgs.cpp
+++ b/test/pdiff/CompareArgs.cpp
@@ -60,6 +60,7 @@ CompareArgs::~CompareArgs()
 
 bool CompareArgs::Parse_Args(int argc, char **argv)
 {
+	cairo_surface_t *surface;
 	if (argc < 3) {
 		ErrorStr = copyright;
 		ErrorStr += usage;
@@ -67,37 +68,29 @@ bool CompareArgs::Parse_Args(int argc, c
 	}
 	for (int i = 0; i < argc; i++) {
 		if (i == 1) {
-#if HAVE_LIBTIFF
-			ImgA = RGBAImage::ReadTiff(argv[1]);
-			if (!ImgA) {
-#endif /* HAVE_LIBTIFF */
-				ImgA = RGBAImage::ReadPNG(argv[1]);
-				if (!ImgA)
-				{
-					ErrorStr = "FAIL: Cannot open ";
-					ErrorStr += argv[1];
-					ErrorStr += "\n";
-					return false;
-				}
-#if HAVE_LIBTIFF
+			surface = cairo_image_surface_create_from_png (argv[1]);
+			if (cairo_surface_status (surface))
+			{
+				ErrorStr = "FAIL: Cannot open ";
+				ErrorStr += argv[1];
+				ErrorStr += " ";
+				ErrorStr += cairo_status_to_string (cairo_surface_status (surface));
+				ErrorStr += "\n";
+				return false;
 			}
-#endif /* HAVE_LIBTIFF */
+			ImgA = new RGBACairoImage (surface);
 		} else if (i == 2) {			
-#if HAVE_LIBTIFF
-			ImgB = RGBAImage::ReadTiff(argv[2]);
-			if (!ImgB) {
-#endif /* HAVE_LIBTIFF */
-				ImgB = RGBAImage::ReadPNG(argv[2]);
-				if (!ImgB)
-				{
-					ErrorStr = "FAIL: Cannot open ";
-					ErrorStr += argv[2];
-					ErrorStr += "\n";
-					return false;
-				}
-#if HAVE_LIBTIFF
+			surface = cairo_image_surface_create_from_png (argv[2]);
+			if (cairo_surface_status (surface))
+			{
+				ErrorStr = "FAIL: Cannot open ";
+				ErrorStr += argv[2];
+				ErrorStr += " ";
+				ErrorStr += cairo_status_to_string (cairo_surface_status (surface));
+				ErrorStr += "\n";
+				return false;
 			}
-#endif /* HAVE_LIBTIFF */
+			ImgB = new RGBACairoImage (surface);
 		} else {
 			if (strstr(argv[i], "-fov")) {
 				if (i + 1 < argc) {
diff --git a/test/pdiff/CompareArgs.h b/test/pdiff/CompareArgs.h
index a4a1ddd..fc6993f 100644
--- a/test/pdiff/CompareArgs.h
+++ b/test/pdiff/CompareArgs.h
@@ -20,6 +20,7 @@ if not, write to the Free Software Found
 #include <string>
 
 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 36bebd0..9f441b9 100644
--- a/test/pdiff/Makefile.am
+++ b/test/pdiff/Makefile.am
@@ -11,4 +11,5 @@ perceptualdiff_SOURCES =	\
 	RGBAImage.cpp		\
 	RGBAImage.h
 
+INCLUDES = -I$(top_srcdir)/src
 LDADD = $(top_builddir)/src/libcairo.la
diff --git a/test/pdiff/RGBAImage.h b/test/pdiff/RGBAImage.h
index 65802f9..6aa5ff9 100644
--- a/test/pdiff/RGBAImage.h
+++ b/test/pdiff/RGBAImage.h
@@ -18,11 +18,13 @@ if not, write to the Free Software Found
 #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;
@@ -31,17 +33,17 @@ public:
 		Data = new unsigned int[w * h];
 	};
 	~RGBAImage() { if (Data) delete[] Data; }
-	unsigned char Get_Red(unsigned int i) { return (Data[i] & 0xFF); }
-	unsigned char Get_Green(unsigned int i) { return ((Data[i]>>8) & 0xFF); }
-	unsigned char Get_Blue(unsigned int i) { return ((Data[i]>>16) & 0xFF); }
-	unsigned char Get_Alpha(unsigned int i) { return ((Data[i]>>24) & 0xFF); }
-	void Set(unsigned char r, unsigned char g, unsigned char b, unsigned char a, unsigned int i)
+	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; }
-	void Set(int x, int y, unsigned int d) { Data[x + y * Width] = d; }
-	unsigned int Get(int x, int y) const { return Data[x + y * Width]; }
-	unsigned int Get(int i) const { return Data[i]; }
+	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();
@@ -54,4 +56,50 @@ protected:
 	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_Pixel_Unpremultiply(i)); }
+};
+
 #endif


More information about the cairo-commit mailing list