123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- /*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
- #include "include/core/SkBitmap.h"
- #include "include/core/SkColor.h"
- #include "include/core/SkColorPriv.h"
- #include "include/core/SkTypes.h"
- #include "tools/skdiff/skdiff.h"
- /*static*/ char const * const DiffRecord::ResultNames[DiffRecord::kResultCount] = {
- "EqualBits",
- "EqualPixels",
- "DifferentPixels",
- "DifferentSizes",
- "CouldNotCompare",
- "Unknown",
- };
- DiffRecord::Result DiffRecord::getResultByName(const char *name) {
- for (int result = 0; result < DiffRecord::kResultCount; ++result) {
- if (0 == strcmp(DiffRecord::ResultNames[result], name)) {
- return static_cast<DiffRecord::Result>(result);
- }
- }
- return DiffRecord::kResultCount;
- }
- static char const * const ResultDescriptions[DiffRecord::kResultCount] = {
- "contain exactly the same bits",
- "contain the same pixel values, but not the same bits",
- "have identical dimensions but some differing pixels",
- "have differing dimensions",
- "could not be compared",
- "not compared yet",
- };
- const char* DiffRecord::getResultDescription(DiffRecord::Result result) {
- return ResultDescriptions[result];
- }
- /*static*/ char const * const DiffResource::StatusNames[DiffResource::kStatusCount] = {
- "Decoded",
- "CouldNotDecode",
- "Read",
- "CouldNotRead",
- "Exists",
- "DoesNotExist",
- "Specified",
- "Unspecified",
- "Unknown",
- };
- DiffResource::Status DiffResource::getStatusByName(const char *name) {
- for (int status = 0; status < DiffResource::kStatusCount; ++status) {
- if (0 == strcmp(DiffResource::StatusNames[status], name)) {
- return static_cast<DiffResource::Status>(status);
- }
- }
- return DiffResource::kStatusCount;
- }
- static char const * const StatusDescriptions[DiffResource::kStatusCount] = {
- "decoded",
- "could not be decoded",
- "read",
- "could not be read",
- "found",
- "not found",
- "specified",
- "unspecified",
- "unknown",
- };
- const char* DiffResource::getStatusDescription(DiffResource::Status status) {
- return StatusDescriptions[status];
- }
- bool DiffResource::isStatusFailed(DiffResource::Status status) {
- return DiffResource::kCouldNotDecode_Status == status ||
- DiffResource::kCouldNotRead_Status == status ||
- DiffResource::kDoesNotExist_Status == status ||
- DiffResource::kUnspecified_Status == status ||
- DiffResource::kUnknown_Status == status;
- }
- bool DiffResource::getMatchingStatuses(char* selector, bool statuses[kStatusCount]) {
- if (!strcmp(selector, "any")) {
- for (int statusIndex = 0; statusIndex < kStatusCount; ++statusIndex) {
- statuses[statusIndex] = true;
- }
- return true;
- }
- for (int statusIndex = 0; statusIndex < kStatusCount; ++statusIndex) {
- statuses[statusIndex] = false;
- }
- static const char kDelimiterChar = ',';
- bool understood = true;
- while (true) {
- char* delimiterPtr = strchr(selector, kDelimiterChar);
- if (delimiterPtr) {
- *delimiterPtr = '\0';
- }
- if (!strcmp(selector, "failed")) {
- for (int statusIndex = 0; statusIndex < kStatusCount; ++statusIndex) {
- Status status = static_cast<Status>(statusIndex);
- statuses[statusIndex] |= isStatusFailed(status);
- }
- } else {
- Status status = getStatusByName(selector);
- if (status == kStatusCount) {
- understood = false;
- } else {
- statuses[status] = true;
- }
- }
- if (!delimiterPtr) {
- break;
- }
- *delimiterPtr = kDelimiterChar;
- selector = delimiterPtr + 1;
- }
- return understood;
- }
- static inline bool colors_match_thresholded(SkPMColor c0, SkPMColor c1, const int threshold) {
- int da = SkGetPackedA32(c0) - SkGetPackedA32(c1);
- int dr = SkGetPackedR32(c0) - SkGetPackedR32(c1);
- int dg = SkGetPackedG32(c0) - SkGetPackedG32(c1);
- int db = SkGetPackedB32(c0) - SkGetPackedB32(c1);
- return ((SkAbs32(da) <= threshold) &&
- (SkAbs32(dr) <= threshold) &&
- (SkAbs32(dg) <= threshold) &&
- (SkAbs32(db) <= threshold));
- }
- const SkPMColor PMCOLOR_WHITE = SkPreMultiplyColor(SK_ColorWHITE);
- const SkPMColor PMCOLOR_BLACK = SkPreMultiplyColor(SK_ColorBLACK);
- void compute_diff(DiffRecord* dr, DiffMetricProc diffFunction, const int colorThreshold) {
- const int w = dr->fComparison.fBitmap.width();
- const int h = dr->fComparison.fBitmap.height();
- if (w != dr->fBase.fBitmap.width() || h != dr->fBase.fBitmap.height()) {
- dr->fResult = DiffRecord::kDifferentSizes_Result;
- return;
- }
- int mismatchedPixels = 0;
- int totalMismatchA = 0;
- int totalMismatchR = 0;
- int totalMismatchG = 0;
- int totalMismatchB = 0;
- // Accumulate fractionally different pixels, then divide out
- // # of pixels at the end.
- dr->fWeightedFraction = 0;
- for (int y = 0; y < h; y++) {
- for (int x = 0; x < w; x++) {
- SkPMColor c0 = *dr->fBase.fBitmap.getAddr32(x, y);
- SkPMColor c1 = *dr->fComparison.fBitmap.getAddr32(x, y);
- SkPMColor outputDifference = diffFunction(c0, c1);
- uint32_t thisA = SkAbs32(SkGetPackedA32(c0) - SkGetPackedA32(c1));
- uint32_t thisR = SkAbs32(SkGetPackedR32(c0) - SkGetPackedR32(c1));
- uint32_t thisG = SkAbs32(SkGetPackedG32(c0) - SkGetPackedG32(c1));
- uint32_t thisB = SkAbs32(SkGetPackedB32(c0) - SkGetPackedB32(c1));
- totalMismatchA += thisA;
- totalMismatchR += thisR;
- totalMismatchG += thisG;
- totalMismatchB += thisB;
- // In HSV, value is defined as max RGB component.
- int value = MAX3(thisR, thisG, thisB);
- dr->fWeightedFraction += ((float) value) / 255;
- if (thisA > dr->fMaxMismatchA) {
- dr->fMaxMismatchA = thisA;
- }
- if (thisR > dr->fMaxMismatchR) {
- dr->fMaxMismatchR = thisR;
- }
- if (thisG > dr->fMaxMismatchG) {
- dr->fMaxMismatchG = thisG;
- }
- if (thisB > dr->fMaxMismatchB) {
- dr->fMaxMismatchB = thisB;
- }
- if (!colors_match_thresholded(c0, c1, colorThreshold)) {
- mismatchedPixels++;
- *dr->fDifference.fBitmap.getAddr32(x, y) = outputDifference;
- *dr->fWhite.fBitmap.getAddr32(x, y) = PMCOLOR_WHITE;
- } else {
- *dr->fDifference.fBitmap.getAddr32(x, y) = 0;
- *dr->fWhite.fBitmap.getAddr32(x, y) = PMCOLOR_BLACK;
- }
- }
- }
- if (0 == mismatchedPixels) {
- dr->fResult = DiffRecord::kEqualPixels_Result;
- return;
- }
- dr->fResult = DiffRecord::kDifferentPixels_Result;
- int pixelCount = w * h;
- dr->fFractionDifference = ((float) mismatchedPixels) / pixelCount;
- dr->fWeightedFraction /= pixelCount;
- dr->fTotalMismatchA = totalMismatchA;
- dr->fAverageMismatchA = ((float) totalMismatchA) / pixelCount;
- dr->fAverageMismatchR = ((float) totalMismatchR) / pixelCount;
- dr->fAverageMismatchG = ((float) totalMismatchG) / pixelCount;
- dr->fAverageMismatchB = ((float) totalMismatchB) / pixelCount;
- }
|