LibGfx: Replace Bitmap::visually_equals() with ::diff()

This produces more granural information on the actual pixel errors
present between two bitmaps. It now also asserts that both bitmaps are
the same size, since we should never compare two differently sized
bitmaps anyway.
This commit is contained in:
Jelle Raaijmakers 2025-07-16 09:04:19 +02:00 committed by Tim Ledbetter
commit 0f642ecb5c
Notes: github-actions[bot] 2025-07-17 12:00:38 +00:00
3 changed files with 55 additions and 8 deletions

View file

@ -228,21 +228,47 @@ ErrorOr<BackingStore> Bitmap::allocate_backing_store(BitmapFormat format, IntSiz
return BackingStore { data, pitch, data_size_in_bytes };
}
bool Bitmap::visually_equals(Bitmap const& other) const
Bitmap::DiffResult Bitmap::diff(Bitmap const& other) const
{
auto own_width = width();
auto own_height = height();
if (other.width() != own_width || other.height() != own_height)
return false;
VERIFY(own_width == other.width() && own_height == other.height());
DiffResult result;
for (auto y = 0; y < own_height; ++y) {
for (auto x = 0; x < own_width; ++x) {
if (get_pixel(x, y) != other.get_pixel(x, y))
return false;
auto own_pixel = get_pixel(x, y);
auto other_pixel = other.get_pixel(x, y);
if (own_pixel == other_pixel)
continue;
++result.pixel_error_count;
u8 red_error = abs(static_cast<int>(own_pixel.red()) - other_pixel.red());
u8 green_error = abs(static_cast<int>(own_pixel.green()) - other_pixel.green());
u8 blue_error = abs(static_cast<int>(own_pixel.blue()) - other_pixel.blue());
u8 alpha_error = abs(static_cast<int>(own_pixel.alpha()) - other_pixel.alpha());
result.total_red_error += red_error;
result.total_green_error += green_error;
result.total_blue_error += blue_error;
result.total_alpha_error += alpha_error;
result.maximum_red_error = max(result.maximum_red_error, red_error);
result.maximum_green_error = max(result.maximum_green_error, green_error);
result.maximum_blue_error = max(result.maximum_blue_error, blue_error);
result.maximum_alpha_error = max(result.maximum_alpha_error, alpha_error);
}
}
return true;
result.identical = result.pixel_error_count == 0;
result.total_error = result.total_red_error + result.total_green_error + result.total_blue_error + result.total_alpha_error;
u8 maximum_red_green_error = max(result.maximum_red_error, result.maximum_green_error);
u8 maximum_blue_alpha_error = max(result.maximum_blue_error, result.maximum_alpha_error);
result.maximum_error = max(maximum_red_green_error, maximum_blue_alpha_error);
return result;
}
void Bitmap::set_alpha_type_destructive(AlphaType alpha_type)

View file

@ -137,7 +137,28 @@ public:
[[nodiscard]] Core::AnonymousBuffer& anonymous_buffer() { return m_buffer; }
[[nodiscard]] Core::AnonymousBuffer const& anonymous_buffer() const { return m_buffer; }
[[nodiscard]] bool visually_equals(Bitmap const&) const;
struct DiffResult {
bool identical { false };
// Cumulative channel differences.
u64 total_red_error { 0 };
u64 total_green_error { 0 };
u64 total_blue_error { 0 };
u64 total_alpha_error { 0 };
u64 total_error { 0 };
// Maximum channel differences.
u8 maximum_red_error { 0 };
u8 maximum_green_error { 0 };
u8 maximum_blue_error { 0 };
u8 maximum_alpha_error { 0 };
u8 maximum_error { 0 };
// Number of pixels with errors.
u64 pixel_error_count { 0 };
};
[[nodiscard]] DiffResult diff(Bitmap const&) const;
[[nodiscard]] AlphaType alpha_type() const { return m_alpha_type; }
void set_alpha_type_destructive(AlphaType);