1363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger/* 2363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger * Copyright 2012 Google Inc. 3363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger * 4363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger * Use of this source code is governed by a BSD-style license that can be 5363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger * found in the LICENSE file. 6363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger */ 7363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 8363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#include "skdiff.h" 9363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#include "SkBitmap.h" 10363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#include "SkColor.h" 11363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#include "SkColorPriv.h" 12363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#include "SkTypes.h" 13363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 14363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger/*static*/ char const * const DiffRecord::ResultNames[DiffRecord::kResultCount] = { 15363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "EqualBits", 16363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "EqualPixels", 17363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "DifferentPixels", 18363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "DifferentSizes", 19363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "CouldNotCompare", 20363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "Unknown", 21363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger}; 22363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 23363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek SollenbergerDiffRecord::Result DiffRecord::getResultByName(const char *name) { 24363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger for (int result = 0; result < DiffRecord::kResultCount; ++result) { 25363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (0 == strcmp(DiffRecord::ResultNames[result], name)) { 26363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger return static_cast<DiffRecord::Result>(result); 27363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 28363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 29363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger return DiffRecord::kResultCount; 30363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger} 31363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 32363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergerstatic char const * const ResultDescriptions[DiffRecord::kResultCount] = { 33363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "contain exactly the same bits", 34363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "contain the same pixel values, but not the same bits", 35363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "have identical dimensions but some differing pixels", 36363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "have differing dimensions", 37363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "could not be compared", 38363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "not compared yet", 39363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger}; 40363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 41363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergerconst char* DiffRecord::getResultDescription(DiffRecord::Result result) { 42363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger return ResultDescriptions[result]; 43363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger} 44363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 45363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger/*static*/ char const * const DiffResource::StatusNames[DiffResource::kStatusCount] = { 46363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "Decoded", 47363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "CouldNotDecode", 48363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 49363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "Read", 50363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "CouldNotRead", 51363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 52363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "Exists", 53363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "DoesNotExist", 54363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 55363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "Specified", 56363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "Unspecified", 57363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 58363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "Unknown", 59363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger}; 60363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 61363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek SollenbergerDiffResource::Status DiffResource::getStatusByName(const char *name) { 62363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger for (int status = 0; status < DiffResource::kStatusCount; ++status) { 63363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (0 == strcmp(DiffResource::StatusNames[status], name)) { 64363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger return static_cast<DiffResource::Status>(status); 65363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 66363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 67363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger return DiffResource::kStatusCount; 68363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger} 69363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 70363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergerstatic char const * const StatusDescriptions[DiffResource::kStatusCount] = { 71363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "decoded", 72363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "could not be decoded", 73363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 74363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "read", 75363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "could not be read", 76363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 77363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "found", 78363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "not found", 79363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 80363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "specified", 81363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "unspecified", 82363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 83363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger "unknown", 84363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger}; 85363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 86363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergerconst char* DiffResource::getStatusDescription(DiffResource::Status status) { 87363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger return StatusDescriptions[status]; 88363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger} 89363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 90363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergerbool DiffResource::isStatusFailed(DiffResource::Status status) { 91363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger return DiffResource::kCouldNotDecode_Status == status || 92363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger DiffResource::kCouldNotRead_Status == status || 93363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger DiffResource::kDoesNotExist_Status == status || 94363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger DiffResource::kUnspecified_Status == status || 95363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger DiffResource::kUnknown_Status == status; 96363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger} 97363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 98363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergerbool DiffResource::getMatchingStatuses(char* selector, bool statuses[kStatusCount]) { 99363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (!strcmp(selector, "any")) { 100363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger for (int statusIndex = 0; statusIndex < kStatusCount; ++statusIndex) { 101363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger statuses[statusIndex] = true; 102363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 103363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger return true; 104363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 105363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 106363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger for (int statusIndex = 0; statusIndex < kStatusCount; ++statusIndex) { 107363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger statuses[statusIndex] = false; 108363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 109363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 110363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger static const char kDelimiterChar = ','; 111363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger bool understood = true; 112363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger while (true) { 113363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger char* delimiterPtr = strchr(selector, kDelimiterChar); 114363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 115363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (delimiterPtr) { 116363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger *delimiterPtr = '\0'; 117363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 118363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 119363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (!strcmp(selector, "failed")) { 120363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger for (int statusIndex = 0; statusIndex < kStatusCount; ++statusIndex) { 121363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger Status status = static_cast<Status>(statusIndex); 122363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger statuses[statusIndex] |= isStatusFailed(status); 123363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 124363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } else { 125363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger Status status = getStatusByName(selector); 126363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (status == kStatusCount) { 127363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger understood = false; 128363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } else { 129363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger statuses[status] = true; 130363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 131363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 132363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 133363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (!delimiterPtr) { 134363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger break; 135363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 136363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 137363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger *delimiterPtr = kDelimiterChar; 138363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger selector = delimiterPtr + 1; 139363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 140363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger return understood; 141363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger} 142363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 143363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergerstatic inline bool colors_match_thresholded(SkPMColor c0, SkPMColor c1, const int threshold) { 144363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger int da = SkGetPackedA32(c0) - SkGetPackedA32(c1); 145363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger int dr = SkGetPackedR32(c0) - SkGetPackedR32(c1); 146363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger int dg = SkGetPackedG32(c0) - SkGetPackedG32(c1); 147363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger int db = SkGetPackedB32(c0) - SkGetPackedB32(c1); 148363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 149363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger return ((SkAbs32(da) <= threshold) && 150363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger (SkAbs32(dr) <= threshold) && 151363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger (SkAbs32(dg) <= threshold) && 152363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger (SkAbs32(db) <= threshold)); 153363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger} 154363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 155363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergerconst SkPMColor PMCOLOR_WHITE = SkPreMultiplyColor(SK_ColorWHITE); 156363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergerconst SkPMColor PMCOLOR_BLACK = SkPreMultiplyColor(SK_ColorBLACK); 157363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 158363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenbergervoid compute_diff(DiffRecord* dr, DiffMetricProc diffFunction, const int colorThreshold) { 159363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger const int w = dr->fComparison.fBitmap.width(); 160363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger const int h = dr->fComparison.fBitmap.height(); 161363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (w != dr->fBase.fBitmap.width() || h != dr->fBase.fBitmap.height()) { 162363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger dr->fResult = DiffRecord::kDifferentSizes_Result; 163363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger return; 164363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 165363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 166363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkAutoLockPixels alpDiff(dr->fDifference.fBitmap); 167363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkAutoLockPixels alpWhite(dr->fWhite.fBitmap); 168363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger int mismatchedPixels = 0; 169d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger int totalMismatchA = 0; 170363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger int totalMismatchR = 0; 171363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger int totalMismatchG = 0; 172363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger int totalMismatchB = 0; 173363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger 174363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // Accumulate fractionally different pixels, then divide out 175363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // # of pixels at the end. 176363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger dr->fWeightedFraction = 0; 177363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger for (int y = 0; y < h; y++) { 178363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger for (int x = 0; x < w; x++) { 179363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkPMColor c0 = *dr->fBase.fBitmap.getAddr32(x, y); 180363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkPMColor c1 = *dr->fComparison.fBitmap.getAddr32(x, y); 181363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger SkPMColor outputDifference = diffFunction(c0, c1); 182d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger uint32_t thisA = SkAbs32(SkGetPackedA32(c0) - SkGetPackedA32(c1)); 183d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger uint32_t thisR = SkAbs32(SkGetPackedR32(c0) - SkGetPackedR32(c1)); 184d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger uint32_t thisG = SkAbs32(SkGetPackedG32(c0) - SkGetPackedG32(c1)); 185d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger uint32_t thisB = SkAbs32(SkGetPackedB32(c0) - SkGetPackedB32(c1)); 186d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger totalMismatchA += thisA; 187363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger totalMismatchR += thisR; 188363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger totalMismatchG += thisG; 189363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger totalMismatchB += thisB; 190363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger // In HSV, value is defined as max RGB component. 191363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger int value = MAX3(thisR, thisG, thisB); 192363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger dr->fWeightedFraction += ((float) value) / 255; 193d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger if (thisA > dr->fMaxMismatchA) { 194d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger dr->fMaxMismatchA = thisA; 195d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger } 196363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (thisR > dr->fMaxMismatchR) { 197363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger dr->fMaxMismatchR = thisR; 198363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 199363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (thisG > dr->fMaxMismatchG) { 200363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger dr->fMaxMismatchG = thisG; 201363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 202363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (thisB > dr->fMaxMismatchB) { 203363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger dr->fMaxMismatchB = thisB; 204363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 205363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (!colors_match_thresholded(c0, c1, colorThreshold)) { 206363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger mismatchedPixels++; 207363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger *dr->fDifference.fBitmap.getAddr32(x, y) = outputDifference; 208363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger *dr->fWhite.fBitmap.getAddr32(x, y) = PMCOLOR_WHITE; 209363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } else { 210363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger *dr->fDifference.fBitmap.getAddr32(x, y) = 0; 211363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger *dr->fWhite.fBitmap.getAddr32(x, y) = PMCOLOR_BLACK; 212363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 213363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 214363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 215363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger if (0 == mismatchedPixels) { 216363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger dr->fResult = DiffRecord::kEqualPixels_Result; 217363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger return; 218363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger } 219363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger dr->fResult = DiffRecord::kDifferentPixels_Result; 220363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger int pixelCount = w * h; 221363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger dr->fFractionDifference = ((float) mismatchedPixels) / pixelCount; 222363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger dr->fWeightedFraction /= pixelCount; 223d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger dr->fTotalMismatchA = totalMismatchA; 224d686ac77c2c485c4a3302eda9c1de597a6f8c568Derek Sollenberger dr->fAverageMismatchA = ((float) totalMismatchA) / pixelCount; 225363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger dr->fAverageMismatchR = ((float) totalMismatchR) / pixelCount; 226363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger dr->fAverageMismatchG = ((float) totalMismatchG) / pixelCount; 227363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger dr->fAverageMismatchB = ((float) totalMismatchB) / pixelCount; 228363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger} 229