Stores index.html in the output (diff) directory rather than in the current
working directory.
Skips PDFs since we have no way to compare them.
Includes prototype of --weighted option to scale percent different metric by
intensity of difference at each pixel.

(qv http://codereview.appspot.com/4557042/)



git-svn-id: http://skia.googlecode.com/svn/trunk@1411 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/tools/skdiff_main.cpp b/tools/skdiff_main.cpp
index 915e8bd..5a057c4 100644
--- a/tools/skdiff_main.cpp
+++ b/tools/skdiff_main.cpp
@@ -24,7 +24,8 @@
 struct DiffRecord {
     DiffRecord (const SkString filename)
         : fFilename (filename)
-        , fMetricValue (0)
+        , fPercentDifference (0)
+        , fWeightedPercent (0)
         , fAverageMismatchR (0)
         , fAverageMismatchG (0)
         , fAverageMismatchB (0)
@@ -41,7 +42,8 @@
     /// Arbitrary floating-point metric to be used to sort images from most
     /// to least different from baseline; values of 0 will be omitted from the
     /// summary webpage.
-    float fMetricValue;
+    float fPercentDifference;
+    float fWeightedPercent;
 
     float fAverageMismatchR;
     float fAverageMismatchG;
@@ -54,13 +56,23 @@
 
 typedef SkTDArray<DiffRecord*> RecordArray;
 
-/// Comparison routine for qsort;  sorts by fMetricValue
+/// Comparison routine for qsort;  sorts by fPercentDifference
 /// from largest to smallest.
 static int compare_diff_metrics (DiffRecord** lhs, DiffRecord** rhs) {
-    if ((*lhs)->fMetricValue < (*rhs)->fMetricValue) {
+    if ((*lhs)->fPercentDifference < (*rhs)->fPercentDifference) {
         return 1;
     }
-    if ((*rhs)->fMetricValue < (*lhs)->fMetricValue) {
+    if ((*rhs)->fPercentDifference < (*lhs)->fPercentDifference) {
+        return -1;
+    }
+    return 0;
+}
+
+static int compare_diff_weighted (DiffRecord** lhs, DiffRecord** rhs) {
+    if ((*lhs)->fWeightedPercent < (*rhs)->fWeightedPercent) {
+        return 1;
+    }
+    if ((*lhs)->fWeightedPercent > (*rhs)->fWeightedPercent) {
         return -1;
     }
     return 0;
@@ -219,23 +231,32 @@
     int totalMismatchR = 0;
     int totalMismatchG = 0;
     int totalMismatchB = 0;
+    // Accumulate fractionally different pixels, then divide out
+    // # of pixels at the end.
+    dr->fWeightedPercent = 0;
     for (int y = 0; y < h; y++) {
         for (int x = 0; x < w; x++) {
             SkPMColor c0 = *dr->fBaseBitmap.getAddr32(x, y);
             SkPMColor c1 = *dr->fComparisonBitmap.getAddr32(x, y);
             SkPMColor d = 0;
             d = diffFunction(c0, c1);
-            totalMismatchR += SkGetPackedR32(d);
-            totalMismatchG += SkGetPackedG32(d);
-            totalMismatchB += SkGetPackedB32(d);
-            if (SkGetPackedR32(d) > dr->fMaxMismatchR) {
-                dr->fMaxMismatchR = SkGetPackedR32(d);
+            uint32_t thisR = SkGetPackedR32(d);
+            uint32_t thisG = SkGetPackedG32(d);
+            uint32_t thisB = SkGetPackedB32(d);
+            totalMismatchR += thisR;
+            totalMismatchG += thisG;
+            totalMismatchB += thisB;
+            // In HSV, value is defined as max RGB component.
+            int value = MAX3(thisR, thisG, thisB);
+            dr->fWeightedPercent += ((float) value) / 255;
+            if (thisR > dr->fMaxMismatchR) {
+                dr->fMaxMismatchR = thisR;
             }
-            if (SkGetPackedG32(d) > dr->fMaxMismatchG) {
-                dr->fMaxMismatchG = SkGetPackedG32(d);
+            if (thisG > dr->fMaxMismatchG) {
+                dr->fMaxMismatchG = thisG;
             }
-            if (SkGetPackedB32(d) > dr->fMaxMismatchB) {
-                dr->fMaxMismatchB = SkGetPackedB32(d);
+            if (thisB > dr->fMaxMismatchB) {
+                dr->fMaxMismatchB = thisB;
             }
             if (!colors_match_thresholded(c0, c1, colorThreshold)) {
                 mismatchedPixels++;
@@ -245,10 +266,12 @@
             }
         }
     }
-    dr->fMetricValue = ((float) mismatchedPixels) / (w * h);
-    dr->fAverageMismatchR = ((float) totalMismatchR) / (w * h);
-    dr->fAverageMismatchG = ((float) totalMismatchG) / (w * h);
-    dr->fAverageMismatchB = ((float) totalMismatchB) / (w * h);
+    int pixelCount = w * h;
+    dr->fPercentDifference = ((float) mismatchedPixels) / pixelCount;
+    dr->fWeightedPercent /= pixelCount;
+    dr->fAverageMismatchR = ((float) totalMismatchR) / pixelCount;
+    dr->fAverageMismatchG = ((float) totalMismatchG) / pixelCount;
+    dr->fAverageMismatchB = ((float) totalMismatchB) / pixelCount;
 }
 
 /// Creates difference images, returns the number that have a 0 metric.
@@ -271,6 +294,9 @@
     SkString filename;
     int matchCount = 0;
     while (baseIterator.next(&filename)) {
+        if (filename.endsWith(".pdf")) {
+            continue;
+        }
         DiffRecord * drp = new DiffRecord (filename);
         if (!get_bitmaps(drp, baseDir, comparisonDir)) {
             continue;
@@ -287,7 +313,7 @@
         write_bitmap(outPath, drp->fDifferenceBitmap);
 
         differences->push(drp);
-        if (0 == drp->fMetricValue) {
+        if (0 == drp->fPercentDifference) {
             matchCount++;
         }
     }
@@ -349,10 +375,16 @@
 static void print_pixel_count (SkFILEWStream* stream,
                                const DiffRecord& diff) {
     stream->writeText("<br>(");
-    stream->writeDecAsText(diff.fMetricValue *
+    stream->writeDecAsText(diff.fPercentDifference *
                            diff.fBaseBitmap.width() *
                            diff.fBaseBitmap.height());
     stream->writeText(" pixels)");
+/*
+    stream->writeDecAsText(diff.fWeightedPercent *
+                           diff.fBaseBitmap.width() *
+                           diff.fBaseBitmap.height());
+    stream->writeText(" weighted pixels)");
+*/
 }
 
 static void print_label_cell (SkFILEWStream* stream,
@@ -361,11 +393,15 @@
     stream->writeText(diff.fFilename.c_str());
     stream->writeText("<br>");
     char metricBuf [20];
-    sprintf(metricBuf, "%12.4f%%", 100 * diff.fMetricValue);
+    sprintf(metricBuf, "%12.4f%%", 100 * diff.fPercentDifference);
     stream->writeText(metricBuf);
     stream->writeText(" of pixels differ");
+    stream->writeText("\n  (");
+    sprintf(metricBuf, "%12.4f%%", 100 * diff.fWeightedPercent);
+    stream->writeText(metricBuf);
+    stream->writeText(" weighted)");
     // Write the actual number of pixels that differ if it's < 1%
-    if (diff.fMetricValue < 0.01) {
+    if (diff.fPercentDifference < 0.01) {
         print_pixel_count(stream, diff);
     }
     stream->writeText("<br>Average color mismatch ");
@@ -401,7 +437,24 @@
                              const SkString& comparisonDir,
                              const SkString& outputDir) {
 
-    SkFILEWStream outputStream ("index.html");
+    const SkString localDir ("");
+    SkString outputPath (outputDir);
+    outputPath.append("index.html");
+    //SkFILEWStream outputStream ("index.html");
+    SkFILEWStream outputStream (outputPath.c_str());
+
+    // FIXME this doesn't work if there are '..' inside the outputDir
+    unsigned int ui;
+    SkString relativePath;
+    for (ui = 0; ui < outputDir.size(); ui++) {
+        if (outputDir[ui] == '/') {
+            relativePath.append("../");
+        }
+    }
+    SkString relativeBaseDir (relativePath);
+    SkString relativeComparisonDir (relativePath);
+    relativeBaseDir.append(baseDir);
+    relativeComparisonDir.append(comparisonDir);
 
     outputStream.writeText("<html>\n<body>\n");
     print_page_header(&outputStream, matchCount, colorThreshold, differences);
@@ -410,16 +463,17 @@
     int i;
     for (i = 0; i < differences.count(); i++) {
         DiffRecord* diff = differences[i];
-        if (0 == diff->fMetricValue) {
+        if (0 == diff->fPercentDifference) {
             continue;
         }
         int height = compute_image_height(diff->fBaseBitmap);
         outputStream.writeText("<tr>\n");
         print_label_cell(&outputStream, *diff);
-        print_image_cell(&outputStream, baseDir, diff->fFilename, height);
-        print_image_cell(&outputStream, outputDir, diff->fFilename, height);
-        print_image_cell(&outputStream, comparisonDir, diff->fFilename,
-                         height);
+        print_image_cell(&outputStream, relativeBaseDir,
+                         diff->fFilename, height);
+        print_image_cell(&outputStream, localDir, diff->fFilename, height);
+        print_image_cell(&outputStream, relativeComparisonDir,
+                         diff->fFilename, height);
         outputStream.writeText("</tr>\n");
         outputStream.flush();
     }
@@ -439,6 +493,8 @@
 "    -sortbymaxmismatch: sort by worst color channel mismatch,\n"
 "                        break ties with -sortbymismatch,\n"
 "        [default by fraction of pixels mismatching]\n");
+    SkDebugf(
+"    -weighted: sort by # pixels different weighted by color difference\n");
     SkDebugf("    baseDir: directory to read baseline images from\n");
     SkDebugf("    comparisonDir: directory to read comparison images from\n");
     SkDebugf("    outputDir: directory to write difference images to\n");
@@ -476,6 +532,10 @@
             sortProc = (SkQSortCompareProc) compare_diff_max_mismatches;
             continue;
         }
+        if (!strcmp(argv[i], "-weighted")) {
+            sortProc = (SkQSortCompareProc) compare_diff_weighted;
+            continue;
+        }
         if (!strcmp(argv[i], "-threshold")) {
             colorThreshold = atoi(argv[++i]);
             continue;