blob: 6cd62dec682386e0fbab12eab20c73a3aaaa3ad9 [file] [log] [blame] [edit]
#include "SkImage.h"
#include "SkPixmap.h"
#include "SkStream.h"
#include "image_cmp.hpp"
#include <algorithm>
#include <assert.h>
#include <cstdint>
#include <vector>
static int byte0(uint32_t p) { return (p >> 0) & 0xFF; }
static int byte1(uint32_t p) { return (p >> 8) & 0xFF; }
static int byte2(uint32_t p) { return (p >> 16) & 0xFF; }
static int byte3(uint32_t p) { return (p >> 24) & 0xFF; }
static uint32_t pack(unsigned a, unsigned b, unsigned c, unsigned d)
{
return (a << 24) | (b << 16) | (c << 8) | (d << 0);
}
static ImageCmp pixmap_cmp(const SkPixmap& pa, const SkPixmap& pb)
{
assert(pa.width() == pb.width());
assert(pa.height() == pb.height());
size_t pixcount = pa.width() * pa.height();
int maxdiff = 0;
size_t rgb_diffcount = 0;
size_t pixel_diffcount = 0;
for (int y = 0; y < pa.height(); ++y)
{
const uint32_t* row0 = pa.addr32(0, y);
const uint32_t* row1 = pb.addr32(0, y);
for (int x = 0; x < pa.width(); ++x)
{
const uint32_t p0 = row0[x];
const uint32_t p1 = row1[x];
if (p0 == p1)
{
continue;
}
// Find the max diff in this pixel's r,g,b,a.
int rgb_diff = std::abs(byte0(p0) - byte0(p1));
rgb_diff = std::max(rgb_diff, std::abs(byte1(p0) - byte1(p1)));
rgb_diff = std::max(rgb_diff, std::abs(byte2(p0) - byte2(p1)));
rgb_diff = std::max(rgb_diff, std::abs(byte3(p0) - byte3(p1)));
maxdiff = std::max(maxdiff, rgb_diff);
rgb_diffcount += rgb_diff;
if (rgb_diff != 0)
{
++pixel_diffcount;
}
}
}
return ImageCmp::diff(maxdiff,
(float)rgb_diffcount / (pixcount * 255),
pixel_diffcount);
}
ImageCmp image_cmp(sk_sp<SkImage> a, sk_sp<SkImage> b)
{
if (a->width() != b->width() || a->height() != b->height())
{
return ImageCmp::dimensionMismatch();
}
// ensure we can peek at the pixels
a = a->makeRasterImage();
b = b->makeRasterImage();
SkPixmap pa, pb;
if (!a->peekPixels(&pa) || !b->peekPixels(&pb))
{
return ImageCmp::failedToLoad();
}
return pixmap_cmp(pa, pb);
}
uint32_t compute_diff0(uint32_t p0, uint32_t p1)
{
auto a = std::abs(byte0(p0) - byte0(p1));
auto b = std::abs(byte1(p0) - byte1(p1));
auto c = std::abs(byte2(p0) - byte2(p1));
return pack(0xFF, a, b, c);
}
uint32_t compute_diff1(uint32_t p0, uint32_t p1)
{
auto d = p0 == p1 ? 0 : 0xFF;
return pack(0xFF, d, d, d);
}
sk_sp<SkImage> make_diff_image(sk_sp<SkImage> a,
sk_sp<SkImage> b,
uint32_t (*compute_diff)(uint32_t a, uint32_t b))
{
// ensure we can peek at the pixels
a = a->makeRasterImage();
b = b->makeRasterImage();
SkPixmap pa, pb;
if (!a->peekPixels(&pa) || !b->peekPixels(&pb))
{
throw "failed to peek";
}
const auto info = SkImageInfo::MakeN32Premul(pa.width(), pa.height());
std::vector<uint32_t> pixels(pa.width() * pa.height());
auto df = SkPixmap(info, pixels.data(), pa.width() * sizeof(uint32_t));
for (int y = 0; y < df.height(); ++y)
{
for (int x = 0; x < df.width(); ++x)
{
*df.writable_addr32(x, y) =
compute_diff(*pa.addr32(x, y), *pb.addr32(x, y));
}
}
return SkImage::MakeRasterCopy(df);
}