1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // WARNING! This file is copied from third_party/skia/tools/skpdiff and slightly
6 // modified to be compilable outside Skia and suit chromium style. Some comments
8 // TODO(elizavetai): remove this file and reuse the original one in Skia
10 #include "chrome/browser/chromeos/login/screenshot_testing/SkDiffPixelsMetric.h"
11 #include "third_party/skia/include/core/SkBitmap.h"
13 bool SkDifferentPixelsMetric::diff(
16 const SkImageDiffer::BitmapsToCreate
& bitmapsToCreate
,
17 SkImageDiffer::Result
* result
) {
18 // Ensure the images are comparable
19 if (baseline
->width() != test
->width() ||
20 baseline
->height() != test
->height() || baseline
->width() <= 0 ||
21 baseline
->height() <= 0 || baseline
->colorType() != test
->colorType()) {
22 DCHECK(baseline
->width() == test
->width());
23 DCHECK(baseline
->height() == test
->height());
24 DCHECK(baseline
->width() > 0);
25 DCHECK(baseline
->height() > 0);
26 DCHECK(baseline
->colorType() == test
->colorType());
30 int width
= baseline
->width();
31 int height
= baseline
->height();
36 // Prepare any bitmaps we will be filling in
37 if (bitmapsToCreate
.alphaMask
) {
38 result
->poiAlphaMask
.allocPixels(SkImageInfo::MakeA8(width
, height
));
39 result
->poiAlphaMask
.eraseARGB(SK_AlphaOPAQUE
, 0, 0, 0);
41 if (bitmapsToCreate
.rgbDiff
) {
42 result
->rgbDiffBitmap
.allocPixels(SkImageInfo::Make(
43 width
, height
, baseline
->colorType(), kPremul_SkAlphaType
));
44 result
->rgbDiffBitmap
.eraseARGB(SK_AlphaTRANSPARENT
, 0, 0, 0);
46 if (bitmapsToCreate
.whiteDiff
) {
47 result
->whiteDiffBitmap
.allocPixels(
48 SkImageInfo::MakeN32Premul(width
, height
));
49 result
->whiteDiffBitmap
.eraseARGB(SK_AlphaOPAQUE
, 0, 0, 0);
52 // Prepare the pixels for comparison
54 baseline
->lockPixels();
56 for (int y
= 0; y
< height
; y
++) {
57 // Grab a row from each image for easy comparison
58 // TODO(epoger): The code below already assumes 4 bytes per pixel, so I
60 // we could just call getAddr32() to save a little time.
61 // OR, if we want to play it safe, call ComputeBytesPerPixel instead
62 // of assuming 4 bytes per pixel.
63 uint32_t* baselineRow
= static_cast<uint32_t*>(baseline
->getAddr(0, y
));
64 uint32_t* testRow
= static_cast<uint32_t*>(test
->getAddr(0, y
));
65 for (int x
= 0; x
< width
; x
++) {
66 // Compare one pixel at a time so each differing pixel can be noted
67 // TODO(epoger): This loop looks like a good place to work on performance,
68 // but we should run the code through a profiler to be sure.
69 uint32_t baselinePixel
= baselineRow
[x
];
70 uint32_t testPixel
= testRow
[x
];
71 if (baselinePixel
!= testPixel
) {
74 int redDiff
= abs(static_cast<int>(SkColorGetR(baselinePixel
) -
75 SkColorGetR(testPixel
)));
76 if (redDiff
> maxRedDiff
) {
79 int greenDiff
= abs(static_cast<int>(SkColorGetG(baselinePixel
) -
80 SkColorGetG(testPixel
)));
81 if (greenDiff
> maxGreenDiff
) {
82 maxGreenDiff
= greenDiff
;
84 int blueDiff
= abs(static_cast<int>(SkColorGetB(baselinePixel
) -
85 SkColorGetB(testPixel
)));
86 if (blueDiff
> maxBlueDiff
) {
87 maxBlueDiff
= blueDiff
;
90 if (bitmapsToCreate
.alphaMask
) {
91 *result
->poiAlphaMask
.getAddr8(x
, y
) = SK_AlphaTRANSPARENT
;
93 if (bitmapsToCreate
.rgbDiff
) {
94 *result
->rgbDiffBitmap
.getAddr32(x
, y
) =
95 SkColorSetRGB(redDiff
, greenDiff
, blueDiff
);
97 if (bitmapsToCreate
.whiteDiff
) {
98 *result
->whiteDiffBitmap
.getAddr32(x
, y
) = SK_ColorWHITE
;
103 test
->unlockPixels();
104 baseline
->unlockPixels();
106 result
->maxRedDiff
= maxRedDiff
;
107 result
->maxGreenDiff
= maxGreenDiff
;
108 result
->maxBlueDiff
= maxBlueDiff
;
110 if (bitmapsToCreate
.alphaMask
) {
111 result
->poiAlphaMask
.unlockPixels();
113 if (bitmapsToCreate
.rgbDiff
) {
114 result
->rgbDiffBitmap
.unlockPixels();
116 if (bitmapsToCreate
.whiteDiff
) {
117 result
->whiteDiffBitmap
.unlockPixels();
120 // Calculates the percentage of identical pixels
121 result
->result
= 1.0 - ((double)result
->poiCount
/ (width
* height
));