blob: 881a02229acaa248f536c2798f15f2732400565b [file] [log] [blame]
/*
* Copyright 2025 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "tests/ComparePixels.h"
#include "include/core/SkColorSpace.h"
#include "include/core/SkPixmap.h"
#include "include/private/base/SkTemplates.h"
#include "src/core/SkAutoPixmapStorage.h"
#include "src/core/SkConvertPixels.h"
#include <cmath>
#include <utility>
[[nodiscard]] static bool convert_pixels(const SkPixmap& dst, const SkPixmap& src) {
return SkConvertPixels(dst.info(), dst.writable_addr(), dst.rowBytes(),
src.info(), src. addr(), src.rowBytes());
}
static bool compare_colors(int x, int y,
const float rgbaA[],
const float rgbaB[],
const float tolRGBA[4],
std::function<ComparePixmapsErrorReporter>& error) {
float diffs[4];
bool bad = false;
for (int i = 0; i < 4; ++i) {
diffs[i] = rgbaB[i] - rgbaA[i];
if (std::abs(diffs[i]) > std::abs(tolRGBA[i])) {
bad = true;
}
}
if (bad) {
error(x, y, diffs);
return false;
}
return true;
}
bool ComparePixels(const SkPixmap& a,
const SkPixmap& b,
const float tolRGBA[4],
std::function<ComparePixmapsErrorReporter>& error) {
if (a.dimensions() != b.dimensions()) {
static constexpr float kEmptyDiffs[4] = {};
error(-1, -1, kEmptyDiffs);
return false;
}
SkAlphaType floatAlphaType = a.alphaType();
// If one is premul and the other is unpremul we do the comparison in premul space.
if ((a.alphaType() == kPremul_SkAlphaType || b.alphaType() == kPremul_SkAlphaType) &&
(a.alphaType() == kUnpremul_SkAlphaType || b.alphaType() == kUnpremul_SkAlphaType)) {
floatAlphaType = kPremul_SkAlphaType;
}
sk_sp<SkColorSpace> floatCS;
if (SkColorSpace::Equals(a.colorSpace(), b.colorSpace())) {
floatCS = a.refColorSpace();
} else {
floatCS = SkColorSpace::MakeSRGBLinear();
}
SkImageInfo floatInfo = SkImageInfo::Make(a.dimensions(),
kRGBA_F32_SkColorType,
floatAlphaType,
std::move(floatCS));
SkAutoPixmapStorage floatA;
SkAutoPixmapStorage floatB;
floatA.alloc(floatInfo);
floatB.alloc(floatInfo);
SkAssertResult(convert_pixels(floatA, a));
SkAssertResult(convert_pixels(floatB, b));
SkASSERT(floatA.rowBytes() == floatB.rowBytes());
auto at = [rb = floatA.rowBytes()](const void* base, int x, int y) {
return SkTAddOffset<const float>(base, y*rb + x*sizeof(float)*4);
};
for (int y = 0; y < floatA.height(); ++y) {
for (int x = 0; x < floatA.width(); ++x) {
const float* rgbaA = at(floatA.addr(), x, y);
const float* rgbaB = at(floatB.addr(), x, y);
if (!compare_colors(x, y, rgbaA, rgbaB, tolRGBA, error)) {
return false;
}
}
}
return true;
}
bool CheckSolidPixels(const SkColor4f& col,
const SkPixmap& pixmap,
const float tolRGBA[4],
std::function<ComparePixmapsErrorReporter>& error) {
size_t floatBpp = SkColorTypeBytesPerPixel(kRGBA_F32_SkColorType);
// First convert 'col' to be compatible with 'pixmap'
SkAutoPixmapStorage colorPixmap;
{
sk_sp<SkColorSpace> srcCS = SkColorSpace::MakeSRGBLinear();
auto srcInfo = SkImageInfo::Make({1, 1},
kRGBA_F32_SkColorType,
kUnpremul_SkAlphaType,
std::move(srcCS));
SkPixmap srcPixmap(srcInfo, col.vec(), floatBpp);
SkImageInfo dstInfo =
srcInfo.makeAlphaType(pixmap.alphaType()).makeColorSpace(pixmap.refColorSpace());
colorPixmap.alloc(dstInfo);
SkAssertResult(convert_pixels(colorPixmap, srcPixmap));
}
size_t floatRowBytes = floatBpp * pixmap.width();
std::unique_ptr<char[]> floatB(new char[floatRowBytes * pixmap.height()]);
// Then convert 'pixmap' to F32_RGBA
SkAutoPixmapStorage f32Pixmap;
f32Pixmap.alloc(pixmap.info().makeColorType(kRGBA_F32_SkColorType));
SkAssertResult(convert_pixels(f32Pixmap, pixmap));
for (int y = 0; y < f32Pixmap.height(); ++y) {
for (int x = 0; x < f32Pixmap.width(); ++x) {
auto rgbaA = SkTAddOffset<const float>(f32Pixmap.addr(),
f32Pixmap.rowBytes()*y + floatBpp*x);
auto rgbaB = static_cast<const float*>(colorPixmap.addr());
if (!compare_colors(x, y, rgbaA, rgbaB, tolRGBA, error)) {
return false;
}
}
}
return true;
}