Pārlūkot izejas kodu

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.
jack gleeson 2 gadi atpakaļ
vecāks
revīzija
4bf587811f

+ 11 - 2
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();
         auto dst = Gfx::Bitmap::try_create(Gfx::BitmapFormat::BGRA8888, new_size).release_value_but_fixme_should_propagate_errors();
         Gfx::Painter painter(dst);
         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);
         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();
         auto dst = Gfx::Bitmap::try_create(Gfx::BitmapFormat::BGRA8888, new_size).release_value_but_fixme_should_propagate_errors();
         Gfx::Painter painter(dst);
         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);
         m_mask_bitmap = move(dst);
     }
     }
 
 

+ 6 - 0
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<GUI::RadioButton>("nearest_neighbor_radio");
     auto nearest_neighbor_radio = main_widget.find_descendant_of_type_named<GUI::RadioButton>("nearest_neighbor_radio");
     auto smooth_pixels_radio = main_widget.find_descendant_of_type_named<GUI::RadioButton>("smooth_pixels_radio");
     auto smooth_pixels_radio = main_widget.find_descendant_of_type_named<GUI::RadioButton>("smooth_pixels_radio");
     auto bilinear_radio = main_widget.find_descendant_of_type_named<GUI::RadioButton>("bilinear_radio");
     auto bilinear_radio = main_widget.find_descendant_of_type_named<GUI::RadioButton>("bilinear_radio");
+    auto resize_canvas_radio = main_widget.find_descendant_of_type_named<GUI::RadioButton>("resize_canvas");
 
 
     VERIFY(nearest_neighbor_radio);
     VERIFY(nearest_neighbor_radio);
     VERIFY(smooth_pixels_radio);
     VERIFY(smooth_pixels_radio);
     VERIFY(bilinear_radio);
     VERIFY(bilinear_radio);
+    VERIFY(resize_canvas_radio);
 
 
     m_scaling_mode = Gfx::Painter::ScalingMode::NearestNeighbor;
     m_scaling_mode = Gfx::Painter::ScalingMode::NearestNeighbor;
     if (bilinear_radio->is_checked()) {
     if (bilinear_radio->is_checked()) {
@@ -92,6 +94,10 @@ ResizeImageDialog::ResizeImageDialog(Gfx::IntSize const& suggested_size, GUI::Wi
         if (is_checked)
         if (is_checked)
             m_scaling_mode = Gfx::Painter::ScalingMode::BilinearBlend;
             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<GUI::Button>("ok_button");
     auto ok_button = main_widget.find_descendant_of_type_named<GUI::Button>("ok_button");
     auto cancel_button = main_widget.find_descendant_of_type_named<GUI::Button>("cancel_button");
     auto cancel_button = main_widget.find_descendant_of_type_named<GUI::Button>("cancel_button");

+ 7 - 1
Userland/Applications/PixelPaint/ResizeImageDialog.gml

@@ -1,7 +1,7 @@
 @GUI::Widget {
 @GUI::Widget {
     fill_with_background_color: true
     fill_with_background_color: true
     min_width: 260
     min_width: 260
-    min_height: 210
+    min_height: 260
     layout: @GUI::VerticalBoxLayout {
     layout: @GUI::VerticalBoxLayout {
         margins: [4]
         margins: [4]
     }
     }
@@ -92,6 +92,12 @@
             text: "Bilinear"
             text: "Bilinear"
             autosize: true
             autosize: true
         }
         }
+
+        @GUI::RadioButton {
+            name: "resize_canvas"
+            text: "Resize Canvas (None)"
+            autosize: true
+        }
     }
     }
 
 
     @GUI::Widget {
     @GUI::Widget {

+ 2 - 0
Userland/Applications/PixelPaint/ResizeImageDialog.h

@@ -17,6 +17,7 @@ class ResizeImageDialog final : public GUI::Dialog {
 public:
 public:
     Gfx::IntSize const& desired_size() const { return m_desired_size; }
     Gfx::IntSize const& desired_size() const { return m_desired_size; }
     Gfx::Painter::ScalingMode scaling_mode() const { return m_scaling_mode; }
     Gfx::Painter::ScalingMode scaling_mode() const { return m_scaling_mode; }
+    bool should_rescale() const { return m_rescale_image; }
 
 
 private:
 private:
     ResizeImageDialog(Gfx::IntSize const& starting_size, GUI::Window* parent_window);
     ResizeImageDialog(Gfx::IntSize const& starting_size, GUI::Window* parent_window);
@@ -24,6 +25,7 @@ private:
     Gfx::IntSize m_desired_size;
     Gfx::IntSize m_desired_size;
     Gfx::Painter::ScalingMode m_scaling_mode;
     Gfx::Painter::ScalingMode m_scaling_mode;
     float m_starting_aspect_ratio;
     float m_starting_aspect_ratio;
+    bool m_rescale_image;
 };
 };
 
 
 }
 }

+ 8 - 0
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:
     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);
         do_draw_scaled_bitmap<has_alpha_channel, Painter::ScalingMode::BilinearBlend>(target, dst_rect, clipped_rect, source, src_rect, get_pixel, opacity);
         break;
         break;
+    case Painter::ScalingMode::None:
+        do_draw_scaled_bitmap<has_alpha_channel, Painter::ScalingMode::None>(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())
     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);
         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 dst_rect = to_physical(a_dst_rect);
     auto src_rect = a_src_rect * source.scale();
     auto src_rect = a_src_rect * source.scale();
     auto clipped_rect = dst_rect.intersected(clip_rect() * scale());
     auto clipped_rect = dst_rect.intersected(clip_rect() * scale());

+ 1 - 0
Userland/Libraries/LibGfx/Painter.h

@@ -38,6 +38,7 @@ public:
         NearestNeighbor,
         NearestNeighbor,
         SmoothPixels,
         SmoothPixels,
         BilinearBlend,
         BilinearBlend,
+        None,
     };
     };
 
 
     void clear_rect(IntRect const&, Color);
     void clear_rect(IntRect const&, Color);