| #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); |
| } |