summaryrefslogtreecommitdiff
path: root/Userland
diff options
context:
space:
mode:
authorKarol Kosek <krkk@serenityos.org>2022-06-03 17:16:38 +0200
committerSam Atkins <atkinssj@gmail.com>2022-06-16 14:26:55 +0100
commit3d7838c5fbe0b4795f0b875a9fd995ed7e78779b (patch)
treee0ba7a5b1d823f5e0e4f8499d448b017e7021256 /Userland
parentc409881b5f86f8b353098757c0ef2dcf731f31ff (diff)
downloadserenity-3d7838c5fbe0b4795f0b875a9fd995ed7e78779b.zip
LibGfx: Implement SmoothPixels scaling mode
If you wanted to upscale an image, you had two options: - use Nearest Neighbor: it's probably a good choice. The image stays sharp.. unless you aren't using integer scales. - use Bilinear blending, but this on the other hand, doesn't handle upscaling well. It just blurs everything. But what if we could take the best of both of them and make the image sharp on integers and just blur it a little when needed? Well, there's Smooth Pixels! This mode is similar to the Bilinear Blend, with the main difference is that the blend ratio is multiplied by the current scale, so the blur on corners can be only 1px wide. From my testing this mode doesn't handles downscaling as good as the Bilinear blending though.
Diffstat (limited to 'Userland')
-rw-r--r--Userland/Libraries/LibGfx/Painter.cpp26
-rw-r--r--Userland/Libraries/LibGfx/Painter.h1
2 files changed, 26 insertions, 1 deletions
diff --git a/Userland/Libraries/LibGfx/Painter.cpp b/Userland/Libraries/LibGfx/Painter.cpp
index d6945795b5..a8bfa88be8 100644
--- a/Userland/Libraries/LibGfx/Painter.cpp
+++ b/Userland/Libraries/LibGfx/Painter.cpp
@@ -1100,7 +1100,7 @@ ALWAYS_INLINE static void do_draw_scaled_bitmap(Gfx::Bitmap& target, IntRect con
if (clipped_src_rect.is_empty())
return;
- if constexpr (scaling_mode == Painter::ScalingMode::NearestNeighbor) {
+ 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();
int vfactor = dst_rect.height() / int_src_rect.height();
@@ -1155,6 +1155,27 @@ ALWAYS_INLINE static void do_draw_scaled_bitmap(Gfx::Bitmap& target, IntRect con
auto bottom = bottom_left.interpolate(bottom_right, x_ratio);
src_pixel = top.interpolate(bottom, y_ratio);
+ } else if constexpr (scaling_mode == Painter::ScalingMode::SmoothPixels) {
+ auto scaled_x1 = clamp(desired_x >> 32, clipped_src_rect.left(), clipped_src_rect.right());
+ auto scaled_x0 = clamp(scaled_x1 - 1, clipped_src_rect.left(), clipped_src_rect.right());
+ auto scaled_y1 = clamp(desired_y >> 32, clipped_src_rect.top(), clipped_src_rect.bottom());
+ auto scaled_y0 = clamp(scaled_y1 - 1, clipped_src_rect.top(), clipped_src_rect.bottom());
+
+ float x_ratio = (desired_x & fractional_mask) / (float)shift;
+ float y_ratio = (desired_y & fractional_mask) / (float)shift;
+
+ float scaled_x_ratio = clamp(x_ratio * dst_rect.width() / (float)src_rect.width(), 0.0f, 1.0f);
+ float scaled_y_ratio = clamp(y_ratio * dst_rect.height() / (float)src_rect.height(), 0.0f, 1.0f);
+
+ auto top_left = get_pixel(source, scaled_x0, scaled_y0);
+ auto top_right = get_pixel(source, scaled_x1, scaled_y0);
+ auto bottom_left = get_pixel(source, scaled_x0, scaled_y1);
+ auto bottom_right = get_pixel(source, scaled_x1, scaled_y1);
+
+ auto top = top_left.interpolate(top_right, scaled_x_ratio);
+ auto bottom = bottom_left.interpolate(bottom_right, scaled_x_ratio);
+
+ src_pixel = top.interpolate(bottom, scaled_y_ratio);
} else {
auto scaled_x = clamp(desired_x >> 32, clipped_src_rect.left(), clipped_src_rect.right());
auto scaled_y = clamp(desired_y >> 32, clipped_src_rect.top(), clipped_src_rect.bottom());
@@ -1179,6 +1200,9 @@ ALWAYS_INLINE static void do_draw_scaled_bitmap(Gfx::Bitmap& target, IntRect con
case Painter::ScalingMode::NearestNeighbor:
do_draw_scaled_bitmap<has_alpha_channel, Painter::ScalingMode::NearestNeighbor>(target, dst_rect, clipped_rect, source, src_rect, get_pixel, opacity);
break;
+ case Painter::ScalingMode::SmoothPixels:
+ do_draw_scaled_bitmap<has_alpha_channel, Painter::ScalingMode::SmoothPixels>(target, dst_rect, clipped_rect, source, src_rect, get_pixel, opacity);
+ break;
case Painter::ScalingMode::BilinearBlend:
do_draw_scaled_bitmap<has_alpha_channel, Painter::ScalingMode::BilinearBlend>(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 9b5f0012dd..c0e385710d 100644
--- a/Userland/Libraries/LibGfx/Painter.h
+++ b/Userland/Libraries/LibGfx/Painter.h
@@ -36,6 +36,7 @@ public:
enum class ScalingMode {
NearestNeighbor,
+ SmoothPixels,
BilinearBlend,
};