blob: a43022bbecaf26a08e635b736e3d142d5f0707c4 [file]
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <cmath>
#include "base/functional/callback.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkColor.h"
namespace {
// Calculates how different two colors are, by comparing how far apart each of
// the RGBA channels are (in terms of percentages) and averaging that across all
// channels.
float ColorPercentDiff(SkColor color1, SkColor color2) {
float diff_red =
std::abs(static_cast<float>(SkColorGetR(color1)) - SkColorGetR(color2)) /
255.0f;
float diff_green =
std::abs(static_cast<float>(SkColorGetG(color1)) - SkColorGetG(color2)) /
255.0f;
float diff_blue =
std::abs(static_cast<float>(SkColorGetB(color1)) - SkColorGetB(color2)) /
255.0f;
float diff_alpha =
std::abs(static_cast<float>(SkColorGetA(color1)) - SkColorGetA(color2)) /
255.0f;
return (diff_red + diff_green + diff_blue + diff_alpha) / 4.0f;
}
bool HasMoreThanTenPercentImageDiffSync(SkBitmap before, SkBitmap after) {
const bool before_empty = before.empty();
const bool after_empty = after.empty();
if (before_empty && after_empty) {
return false;
}
if (before_empty || after_empty) {
return true;
}
if (before.width() != after.width() || before.height() != after.height()) {
return true;
}
if (before.colorType() != after.colorType()) {
return true;
}
float difference = 0;
float num_pixels = static_cast<float>(before.height()) * before.width();
if (num_pixels == 0) {
return false;
}
// 10% of the total pixels that form the image
const float max_allowed_pixel_difference = 0.10f * num_pixels;
for (int y = 0; y < before.height(); ++y) {
for (int x = 0; x < before.width(); ++x) {
difference +=
ColorPercentDiff(before.getColor(x, y), after.getColor(x, y));
if (difference >= max_allowed_pixel_difference) {
return true;
}
}
}
return false;
}
} // namespace
namespace web_app {
void CheckImageDiffMoreThanTenPercent(SkBitmap before,
SkBitmap after,
base::OnceCallback<void(bool)> callback) {
base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE, {base::TaskPriority::USER_VISIBLE},
base::BindOnce(&HasMoreThanTenPercentImageDiffSync, std::move(before),
std::move(after)),
std::move(callback));
}
} // namespace web_app