From 4bf587811f4a90cf22b6118a55f72f3c16f1f45f Mon Sep 17 00:00:00 2001 From: jack gleeson Date: Mon, 10 Oct 2022 12:54:06 -0700 Subject: [PATCH] PixelPaint+LibGfx: Allow resizing images and layers This PR adds resize ability to PixelPaint as per issue 11862. The previous behaviour was to always rescale the canvas when resizing an image. This adds a checkbox to toggle between rescaling, and resizing which blits the existing canvas to the top left of the new, resized canvas. As part of this, a new ScalingMode is added to LibGfx - None. --- Userland/Applications/PixelPaint/Layer.cpp | 13 +++++++++++-- .../Applications/PixelPaint/ResizeImageDialog.cpp | 6 ++++++ .../Applications/PixelPaint/ResizeImageDialog.gml | 8 +++++++- .../Applications/PixelPaint/ResizeImageDialog.h | 2 ++ Userland/Libraries/LibGfx/Painter.cpp | 8 ++++++++ Userland/Libraries/LibGfx/Painter.h | 1 + 6 files changed, 35 insertions(+), 3 deletions(-) diff --git a/Userland/Applications/PixelPaint/Layer.cpp b/Userland/Applications/PixelPaint/Layer.cpp index 6a8c38cb90..87d6221549 100644 --- a/Userland/Applications/PixelPaint/Layer.cpp +++ b/Userland/Applications/PixelPaint/Layer.cpp @@ -230,7 +230,11 @@ void Layer::resize(Gfx::IntSize const& new_size, Gfx::IntPoint const& new_locati auto dst = Gfx::Bitmap::try_create(Gfx::BitmapFormat::BGRA8888, new_size).release_value_but_fixme_should_propagate_errors(); Gfx::Painter painter(dst); - painter.draw_scaled_bitmap(dst_rect, *m_content_bitmap, src_rect, 1.0f, scaling_mode); + if (scaling_mode == Gfx::Painter::ScalingMode::None) { + painter.blit(src_rect.top_left(), *m_content_bitmap, src_rect, 1.0f); + } else { + painter.draw_scaled_bitmap(dst_rect, *m_content_bitmap, src_rect, 1.0f, scaling_mode); + } m_content_bitmap = move(dst); } @@ -239,7 +243,12 @@ void Layer::resize(Gfx::IntSize const& new_size, Gfx::IntPoint const& new_locati auto dst = Gfx::Bitmap::try_create(Gfx::BitmapFormat::BGRA8888, new_size).release_value_but_fixme_should_propagate_errors(); Gfx::Painter painter(dst); - painter.draw_scaled_bitmap(dst_rect, *m_mask_bitmap, src_rect, 1.0f, scaling_mode); + if (scaling_mode == Gfx::Painter::ScalingMode::None) { + painter.blit(src_rect.top_left(), *m_content_bitmap, src_rect, 1.0f); + } else { + painter.draw_scaled_bitmap(dst_rect, *m_mask_bitmap, src_rect, 1.0f, scaling_mode); + } + m_mask_bitmap = move(dst); } diff --git a/Userland/Applications/PixelPaint/ResizeImageDialog.cpp b/Userland/Applications/PixelPaint/ResizeImageDialog.cpp index 9fa8151269..643658e65a 100644 --- a/Userland/Applications/PixelPaint/ResizeImageDialog.cpp +++ b/Userland/Applications/PixelPaint/ResizeImageDialog.cpp @@ -70,10 +70,12 @@ ResizeImageDialog::ResizeImageDialog(Gfx::IntSize const& suggested_size, GUI::Wi auto nearest_neighbor_radio = main_widget.find_descendant_of_type_named("nearest_neighbor_radio"); auto smooth_pixels_radio = main_widget.find_descendant_of_type_named("smooth_pixels_radio"); auto bilinear_radio = main_widget.find_descendant_of_type_named("bilinear_radio"); + auto resize_canvas_radio = main_widget.find_descendant_of_type_named("resize_canvas"); VERIFY(nearest_neighbor_radio); VERIFY(smooth_pixels_radio); VERIFY(bilinear_radio); + VERIFY(resize_canvas_radio); m_scaling_mode = Gfx::Painter::ScalingMode::NearestNeighbor; if (bilinear_radio->is_checked()) { @@ -92,6 +94,10 @@ ResizeImageDialog::ResizeImageDialog(Gfx::IntSize const& suggested_size, GUI::Wi if (is_checked) m_scaling_mode = Gfx::Painter::ScalingMode::BilinearBlend; }; + resize_canvas_radio->on_checked = [this](bool is_checked) { + if (is_checked) + m_scaling_mode = Gfx::Painter::ScalingMode::None; + }; auto ok_button = main_widget.find_descendant_of_type_named("ok_button"); auto cancel_button = main_widget.find_descendant_of_type_named("cancel_button"); diff --git a/Userland/Applications/PixelPaint/ResizeImageDialog.gml b/Userland/Applications/PixelPaint/ResizeImageDialog.gml index 990f6ea634..fa743b49ec 100644 --- a/Userland/Applications/PixelPaint/ResizeImageDialog.gml +++ b/Userland/Applications/PixelPaint/ResizeImageDialog.gml @@ -1,7 +1,7 @@ @GUI::Widget { fill_with_background_color: true min_width: 260 - min_height: 210 + min_height: 260 layout: @GUI::VerticalBoxLayout { margins: [4] } @@ -92,6 +92,12 @@ text: "Bilinear" autosize: true } + + @GUI::RadioButton { + name: "resize_canvas" + text: "Resize Canvas (None)" + autosize: true + } } @GUI::Widget { diff --git a/Userland/Applications/PixelPaint/ResizeImageDialog.h b/Userland/Applications/PixelPaint/ResizeImageDialog.h index 17887128e0..b74ae3d037 100644 --- a/Userland/Applications/PixelPaint/ResizeImageDialog.h +++ b/Userland/Applications/PixelPaint/ResizeImageDialog.h @@ -17,6 +17,7 @@ class ResizeImageDialog final : public GUI::Dialog { public: Gfx::IntSize const& desired_size() const { return m_desired_size; } Gfx::Painter::ScalingMode scaling_mode() const { return m_scaling_mode; } + bool should_rescale() const { return m_rescale_image; } private: ResizeImageDialog(Gfx::IntSize const& starting_size, GUI::Window* parent_window); @@ -24,6 +25,7 @@ private: Gfx::IntSize m_desired_size; Gfx::Painter::ScalingMode m_scaling_mode; float m_starting_aspect_ratio; + bool m_rescale_image; }; } diff --git a/Userland/Libraries/LibGfx/Painter.cpp b/Userland/Libraries/LibGfx/Painter.cpp index bfd566709b..9773b58fc3 100644 --- a/Userland/Libraries/LibGfx/Painter.cpp +++ b/Userland/Libraries/LibGfx/Painter.cpp @@ -1248,6 +1248,9 @@ ALWAYS_INLINE static void do_draw_scaled_bitmap(Gfx::Bitmap& target, IntRect con case Painter::ScalingMode::BilinearBlend: do_draw_scaled_bitmap(target, dst_rect, clipped_rect, source, src_rect, get_pixel, opacity); break; + case Painter::ScalingMode::None: + do_draw_scaled_bitmap(target, dst_rect, clipped_rect, source, src_rect, get_pixel, opacity); + break; } } @@ -1262,6 +1265,11 @@ void Painter::draw_scaled_bitmap(IntRect const& a_dst_rect, Gfx::Bitmap const& s if (scale() == source.scale() && a_src_rect == int_src_rect && a_dst_rect.size() == int_src_rect.size()) return blit(a_dst_rect.location(), source, int_src_rect, opacity); + if (scaling_mode == ScalingMode::None) { + IntRect clipped_draw_rect { (int)a_src_rect.location().x(), (int)a_src_rect.location().y(), a_dst_rect.size().width(), a_dst_rect.size().height() }; + return blit(a_dst_rect.location(), source, clipped_draw_rect, opacity); + } + auto dst_rect = to_physical(a_dst_rect); auto src_rect = a_src_rect * source.scale(); auto clipped_rect = dst_rect.intersected(clip_rect() * scale()); diff --git a/Userland/Libraries/LibGfx/Painter.h b/Userland/Libraries/LibGfx/Painter.h index 3405d0befd..845978ce1b 100644 --- a/Userland/Libraries/LibGfx/Painter.h +++ b/Userland/Libraries/LibGfx/Painter.h @@ -38,6 +38,7 @@ public: NearestNeighbor, SmoothPixels, BilinearBlend, + None, }; void clear_rect(IntRect const&, Color);