diff options
-rw-r--r-- | COPYING | 21 | ||||
-rw-r--r-- | test/pdiff/CMakeLists.txt | 55 | ||||
-rw-r--r-- | test/pdiff/CompareArgs.cpp | 128 | ||||
-rw-r--r-- | test/pdiff/CompareArgs.h | 44 | ||||
-rw-r--r-- | test/pdiff/LPyramid.cpp | 88 | ||||
-rw-r--r-- | test/pdiff/LPyramid.h | 38 | ||||
-rw-r--r-- | test/pdiff/Metric.cpp | 316 | ||||
-rw-r--r-- | test/pdiff/Metric.h | 26 | ||||
-rw-r--r-- | test/pdiff/PerceptualDiff.cpp | 45 | ||||
-rw-r--r-- | test/pdiff/README.txt | 45 | ||||
-rw-r--r-- | test/pdiff/RGBAImage.cpp | 141 | ||||
-rw-r--r-- | test/pdiff/RGBAImage.h | 57 | ||||
-rw-r--r-- | test/pdiff/gpl.txt | 340 |
13 files changed, 1341 insertions, 3 deletions
@@ -1,6 +1,6 @@ Cairo is free software. -Every source file in the implementation of cairo is available to be +Every source file in the implementation[*] of cairo is available to be redistributed and/or modified under the terms of either the GNU Lesser General Public License (LGPL) version 2.1 or the Mozilla Public License (MPL) version 1.1. Some files are available under more @@ -13,5 +13,20 @@ conditions of either license: COPYING-LGPL-2.1 COPYING-MPL-1.1 -Please see each file in the implementation for Copyright and licensing -information. +Please see each file in the implementation for copyright and licensing +information, (in the opening comment of each file). + +[*] The implementation of cairo is contained entirely within the "src" +and "pixman" directories of the cairo source distribution. There are +other components of the cairo source distribution (such as the "test" +and "perf") that are auxiliary to the library itself. None of the +source code in these directories contributes to a build of the cairo +library itself, (libcairo.so or cairo.dll or similar). + +These auxilary components are also free software, but may be under +different license terms than cairo itself. For example, most of the +test cases in the perf and test directories are made available under +an MIT license to simplify any use of this code for reference purposes +in using cairo itself. Other files might be available under the GNU +General Public License (GPL), for example. Again, please see the +opening comment of each file for copyright and licensing information. diff --git a/test/pdiff/CMakeLists.txt b/test/pdiff/CMakeLists.txt new file mode 100644 index 00000000..6e4fa7a8 --- /dev/null +++ b/test/pdiff/CMakeLists.txt @@ -0,0 +1,55 @@ +PROJECT (PerceptualDiff) +SET(DIFF_SRC PerceptualDiff.cpp LPyramid.cpp RGBAImage.cpp +CompareArgs.cpp Metric.cpp) + +ADD_EXECUTABLE (perceptualdiff ${DIFF_SRC}) + +# look for libtiff +FIND_PATH(TIFF_INCLUDE_DIR tiff.h + /usr/local/include + /usr/include + /opt/local/include +) + +FIND_LIBRARY(TIFF_LIBRARY tiff + /usr/lib + /usr/local/lib + /opt/local/lib +) + +IF(TIFF_INCLUDE_DIR) + IF(TIFF_LIBRARY) + SET( TIFF_FOUND "YES" ) + SET( TIFF_LIBRARIES ${TIFF_LIBRARY} ) + ENDIF(TIFF_LIBRARY) +ENDIF(TIFF_INCLUDE_DIR) + +IF(TIFF_FOUND) + INCLUDE_DIRECTORIES(${TIFF_INCLUDE_DIR}) + TARGET_LINK_LIBRARIES(perceptualdiff ${TIFF_LIBRARY}) +ENDIF(TIFF_FOUND) + +# look for libpng +FIND_PATH(PNG_INCLUDE_DIR png.h + /usr/local/include + /usr/include + /opt/local/include +) + +FIND_LIBRARY(PNG_LIBRARY png + /usr/lib + /usr/local/lib + /opt/local/lib +) + +IF(PNG_INCLUDE_DIR) + IF(PNG_LIBRARY) + SET( PNG_FOUND "YES" ) + SET( PNG_LIBRARIES ${PNG_LIBRARY} ) + ENDIF(PNG_LIBRARY) +ENDIF(PNG_INCLUDE_DIR) + +IF(PNG_FOUND) + INCLUDE_DIRECTORIES(${PNG_INCLUDE_DIR}) + TARGET_LINK_LIBRARIES(perceptualdiff ${PNG_LIBRARY}) +ENDIF(PNG_FOUND)
\ No newline at end of file diff --git a/test/pdiff/CompareArgs.cpp b/test/pdiff/CompareArgs.cpp new file mode 100644 index 00000000..25925f80 --- /dev/null +++ b/test/pdiff/CompareArgs.cpp @@ -0,0 +1,128 @@ +/* +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 "RGBAImage.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\ +\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"; + +CompareArgs::CompareArgs() +{ + 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; +} + +bool CompareArgs::Parse_Args(int argc, char **argv) +{ + if (argc < 3) { + ErrorStr = copyright; + ErrorStr += usage; + return false; + } + for (int i = 0; i < argc; i++) { + if (i == 1) { + ImgA = RGBAImage::ReadTiff(argv[1]); + if (!ImgA) { + ImgA = RGBAImage::ReadPNG(argv[1]); + if (!ImgA) + { + ErrorStr = "FAIL: Cannot open "; + ErrorStr += argv[1]; + ErrorStr += "\n"; + return false; + } + } + } else if (i == 2) { + ImgB = RGBAImage::ReadTiff(argv[2]); + if (!ImgB) { + ImgB = RGBAImage::ReadPNG(argv[2]); + if (!ImgB) + { + ErrorStr = "FAIL: Cannot open "; + ErrorStr += argv[2]; + ErrorStr += "\n"; + 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]); + } + }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); +} diff --git a/test/pdiff/CompareArgs.h b/test/pdiff/CompareArgs.h new file mode 100644 index 00000000..29265c34 --- /dev/null +++ b/test/pdiff/CompareArgs.h @@ -0,0 +1,44 @@ +/* +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> + +class RGBAImage; + +// Args to pass into the comparison function +class CompareArgs +{ +public: + 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 +}; + +#endif
\ No newline at end of file diff --git a/test/pdiff/LPyramid.cpp b/test/pdiff/LPyramid.cpp new file mode 100644 index 00000000..6871c155 --- /dev/null +++ b/test/pdiff/LPyramid.cpp @@ -0,0 +1,88 @@ +/*
+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 new file mode 100644 index 00000000..5f98a426 --- /dev/null +++ b/test/pdiff/LPyramid.h @@ -0,0 +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
\ No newline at end of file diff --git a/test/pdiff/Metric.cpp b/test/pdiff/Metric.cpp new file mode 100644 index 00000000..bcfb8ae4 --- /dev/null +++ b/test/pdiff/Metric.cpp @@ -0,0 +1,316 @@ +/* +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 "Metric.h" +#include "CompareArgs.h" +#include "RGBAImage.h" +#include "LPyramid.h" +#include <math.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]); +} + +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; + 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; + } + + // 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 (args.Verbose) printf("Converting RGB to XYZ\n"); + + unsigned int x, y, w, h; + w = args.ImgA->Get_Width(); + h = args.ImgA->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(args.ImgA->Get_Red(i) / 255.0f, args.Gamma); + g = powf(args.ImgA->Get_Green(i) / 255.0f, args.Gamma); + b = powf(args.ImgA->Get_Blue(i) / 255.0f, args.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(args.ImgB->Get_Red(i) / 255.0f, args.Gamma); + g = powf(args.ImgB->Get_Green(i) / 255.0f, args.Gamma); + b = powf(args.ImgB->Get_Blue(i) / 255.0f, args.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] * args.Luminance; + bLum[i] = bY[i] * args.Luminance; + } + } + + if (args.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( args.FieldOfView * 0.5 * M_PI / 180) * 180 / M_PI); + float pixels_per_degree = w / num_one_degree_pixels; + + if (args.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 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 (args.ImgDiff) { + args.ImgDiff->Set(255, 0, 0, 255, index); + } + } else { + if (args.ImgDiff) { + args.ImgDiff->Set(0, 0, 0, 255, index); + } + } + } + } + + 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 (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 (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; +}
\ No newline at end of file diff --git a/test/pdiff/Metric.h b/test/pdiff/Metric.h new file mode 100644 index 00000000..86540de0 --- /dev/null +++ b/test/pdiff/Metric.h @@ -0,0 +1,26 @@ +/* +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 + +class CompareArgs; + +// 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
\ No newline at end of file diff --git a/test/pdiff/PerceptualDiff.cpp b/test/pdiff/PerceptualDiff.cpp new file mode 100644 index 00000000..ee796665 --- /dev/null +++ b/test/pdiff/PerceptualDiff.cpp @@ -0,0 +1,45 @@ +/* +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 "RGBAImage.h" +#include "CompareArgs.h" +#include "Metric.h" + +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 --git a/test/pdiff/README.txt b/test/pdiff/README.txt new file mode 100644 index 00000000..a873f3c0 --- /dev/null +++ b/test/pdiff/README.txt @@ -0,0 +1,45 @@ +pdiff - a program that compares two images using +a perceptually based image metric. +Copyright (C) 2006 Yangli Hector Yee +yeehector@users.sourceforge.net +http://pdiff.sourceforge.net/ + +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 in the file gpl.txt. + +Build Instructions +1. Download cross platform make from http://www.cmake.org +2. Download libtiff from http://www.libtiff.org. Download libpng from http://www.libpng.org +3. Edit CMakeLists.txt to tell it where to find your tiff library +4. Type cmake . +5. Type make . (or on Windows systems cmake makes a Visual Studio +Project file) +6. To specify the install directory, use make install DESTDIR="/home/me/mydist" + +Usage + +pdiff image1.(tif | png) image2.(tif | png) [options] +-verbose : Turns on verbose mode +-fov deg: field of view, deg, in degrees. Usually between 10.0 to 85.0. +This controls how much of the screen the oberserver is seeing. Front row of +a theatre has a field of view of around 25 degrees. Back row has a field of + view of around 60 degrees. +-threshold p : Sets the number of pixels, p, to reject. For example if p is + 100, then the test fails if 100 or more pixels are perceptably different. +-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 diff --git a/test/pdiff/RGBAImage.cpp b/test/pdiff/RGBAImage.cpp new file mode 100644 index 00000000..267b4606 --- /dev/null +++ b/test/pdiff/RGBAImage.cpp @@ -0,0 +1,141 @@ +/* +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" +#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; +} + +// 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 value = 0; + if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + value = ((uint32)row_pointers[y][x*4]) | (((uint32)row_pointers[y][x*4+1])<<8) | (((uint32)row_pointers[y][x*4+2])<<16) |(((uint32)row_pointers[y][x*4+3])<<24); + else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB) + value = ((uint32)row_pointers[y][x*3] /*B*/) | (((uint32)row_pointers[y][x*3+1] /*G*/)<<8) | (((uint32)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 new file mode 100644 index 00000000..473a59fb --- /dev/null +++ b/test/pdiff/RGBAImage.h @@ -0,0 +1,57 @@ +/* +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 _RGAIMAGE_H +#define _RGBAIMAGE_H + +#include<string> + +// assumes data is in the ABGR format +class RGBAImage +{ +public: + 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; } + 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) + { 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]; } + 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; +}; + +#endif
\ No newline at end of file diff --git a/test/pdiff/gpl.txt b/test/pdiff/gpl.txt new file mode 100644 index 00000000..f90922ee --- /dev/null +++ b/test/pdiff/gpl.txt @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. |