From df304401178dc4e82edccdbe6e7a7a7d12eecfe9 Mon Sep 17 00:00:00 2001 From: FrHun <28605587+frhun@users.noreply.github.com> Date: Sun, 4 Dec 2022 21:23:53 +0100 Subject: LibGfx: Add NearestFractional scaling type to painter This is useful for cases where you want to avoid scaling artifacts. --- Userland/Libraries/LibGfx/Painter.cpp | 15 +++++++++++++-- Userland/Libraries/LibGfx/Painter.h | 1 + 2 files changed, 14 insertions(+), 2 deletions(-) (limited to 'Userland') diff --git a/Userland/Libraries/LibGfx/Painter.cpp b/Userland/Libraries/LibGfx/Painter.cpp index f14b267854..a736004f02 100644 --- a/Userland/Libraries/LibGfx/Painter.cpp +++ b/Userland/Libraries/LibGfx/Painter.cpp @@ -1150,6 +1150,8 @@ void Painter::blit(IntPoint position, Gfx::Bitmap const& source, IntRect const& template ALWAYS_INLINE static void do_draw_integer_scaled_bitmap(Gfx::Bitmap& target, IntRect const& dst_rect, IntRect const& src_rect, Gfx::Bitmap const& source, int hfactor, int vfactor, GetPixel get_pixel, float opacity) { + int x_limit = min(target.physical_width() - 1, dst_rect.right()); + int y_limit = min(target.physical_height() - 1, dst_rect.bottom()); bool has_opacity = opacity != 1.0f; for (int y = 0; y < src_rect.height(); ++y) { int dst_y = dst_rect.y() + y * vfactor; @@ -1157,10 +1159,10 @@ ALWAYS_INLINE static void do_draw_integer_scaled_bitmap(Gfx::Bitmap& target, Int auto src_pixel = get_pixel(source, x + src_rect.left(), y + src_rect.top()); if (has_opacity) src_pixel.set_alpha(src_pixel.alpha() * opacity); - for (int yo = 0; yo < vfactor; ++yo) { + for (int yo = 0; yo < vfactor && dst_y + yo <= y_limit; ++yo) { auto* scanline = (Color*)target.scanline(dst_y + yo); int dst_x = dst_rect.x() + x * hfactor; - for (int xo = 0; xo < hfactor; ++xo) { + for (int xo = 0; xo < hfactor && dst_x + xo <= x_limit; ++xo) { if constexpr (has_alpha_channel) scanline[dst_x + xo] = scanline[dst_x + xo].blend(src_pixel); else @@ -1179,6 +1181,12 @@ ALWAYS_INLINE static void do_draw_scaled_bitmap(Gfx::Bitmap& target, IntRect con if (clipped_src_rect.is_empty()) return; + if (scaling_mode == Painter::ScalingMode::NearestFractional) { + int hfactor = (dst_rect.width() + int_src_rect.width() - 1) / int_src_rect.width(); + int vfactor = (dst_rect.height() + int_src_rect.height() - 1) / int_src_rect.height(); + return do_draw_integer_scaled_bitmap(target, dst_rect, int_src_rect, source, hfactor, vfactor, get_pixel, opacity); + } + if constexpr (scaling_mode == Painter::ScalingMode::NearestNeighbor || scaling_mode == Painter::ScalingMode::SmoothPixels) { if (dst_rect == clipped_rect && int_src_rect == src_rect && !(dst_rect.width() % int_src_rect.width()) && !(dst_rect.height() % int_src_rect.height())) { int hfactor = dst_rect.width() / int_src_rect.width(); @@ -1280,6 +1288,9 @@ template ALWAYS_INLINE static void do_draw_scaled_bitmap(Gfx::Bitmap& target, IntRect const& dst_rect, IntRect const& clipped_rect, Gfx::Bitmap const& source, FloatRect const& src_rect, GetPixel get_pixel, float opacity, Painter::ScalingMode scaling_mode) { switch (scaling_mode) { + case Painter::ScalingMode::NearestFractional: + do_draw_scaled_bitmap(target, dst_rect, clipped_rect, source, src_rect, get_pixel, opacity); + break; case Painter::ScalingMode::NearestNeighbor: do_draw_scaled_bitmap(target, dst_rect, clipped_rect, source, src_rect, get_pixel, opacity); break; diff --git a/Userland/Libraries/LibGfx/Painter.h b/Userland/Libraries/LibGfx/Painter.h index 1669386b36..f78886ab09 100644 --- a/Userland/Libraries/LibGfx/Painter.h +++ b/Userland/Libraries/LibGfx/Painter.h @@ -37,6 +37,7 @@ public: }; enum class ScalingMode { + NearestFractional, NearestNeighbor, SmoothPixels, BilinearBlend, -- cgit v1.2.3