summaryrefslogtreecommitdiff
path: root/Userland/Applications/PixelPaint
diff options
context:
space:
mode:
Diffstat (limited to 'Userland/Applications/PixelPaint')
-rw-r--r--Userland/Applications/PixelPaint/Image.cpp20
-rw-r--r--Userland/Applications/PixelPaint/Image.h2
-rw-r--r--Userland/Applications/PixelPaint/Layer.cpp46
-rw-r--r--Userland/Applications/PixelPaint/Layer.h2
-rw-r--r--Userland/Applications/PixelPaint/MainWidget.cpp13
5 files changed, 83 insertions, 0 deletions
diff --git a/Userland/Applications/PixelPaint/Image.cpp b/Userland/Applications/PixelPaint/Image.cpp
index 5832fefdd7..98bc5760a2 100644
--- a/Userland/Applications/PixelPaint/Image.cpp
+++ b/Userland/Applications/PixelPaint/Image.cpp
@@ -530,6 +530,26 @@ void Image::crop(Gfx::IntRect const& cropped_rect)
did_change_rect(cropped_rect);
}
+Optional<Gfx::IntRect> Image::nonempty_content_bounding_rect() const
+{
+ if (m_layers.is_empty())
+ return {};
+
+ Optional<Gfx::IntRect> bounding_rect;
+ for (auto& layer : m_layers) {
+ auto layer_content_rect_in_layer_coordinates = layer.nonempty_content_bounding_rect();
+ if (!layer_content_rect_in_layer_coordinates.has_value())
+ continue;
+ auto layer_content_rect_in_image_coordinates = layer_content_rect_in_layer_coordinates.value().translated(layer.location());
+ if (!bounding_rect.has_value())
+ bounding_rect = layer_content_rect_in_image_coordinates;
+ else
+ bounding_rect = bounding_rect->united(layer_content_rect_in_image_coordinates);
+ }
+
+ return bounding_rect;
+}
+
void Image::resize(Gfx::IntSize const& new_size, Gfx::Painter::ScalingMode scaling_mode)
{
float scale_x = 1.0f;
diff --git a/Userland/Applications/PixelPaint/Image.h b/Userland/Applications/PixelPaint/Image.h
index 91ca62612b..c5b5dd49e8 100644
--- a/Userland/Applications/PixelPaint/Image.h
+++ b/Userland/Applications/PixelPaint/Image.h
@@ -99,6 +99,8 @@ public:
void crop(Gfx::IntRect const& rect);
void resize(Gfx::IntSize const& new_size, Gfx::Painter::ScalingMode scaling_mode);
+ Optional<Gfx::IntRect> nonempty_content_bounding_rect() const;
+
Color color_at(Gfx::IntPoint const& point) const;
private:
diff --git a/Userland/Applications/PixelPaint/Layer.cpp b/Userland/Applications/PixelPaint/Layer.cpp
index df74c14bc0..307d724a30 100644
--- a/Userland/Applications/PixelPaint/Layer.cpp
+++ b/Userland/Applications/PixelPaint/Layer.cpp
@@ -269,4 +269,50 @@ void Layer::set_edit_mode(Layer::EditMode mode)
m_edit_mode = mode;
}
+Optional<Gfx::IntRect> Layer::nonempty_content_bounding_rect() const
+{
+ Optional<int> min_content_y;
+ Optional<int> min_content_x;
+ Optional<int> max_content_y;
+ Optional<int> max_content_x;
+
+ for (int y = 0; y < m_content_bitmap->height(); ++y) {
+ for (int x = 0; x < m_content_bitmap->width(); ++x) {
+ auto color = m_content_bitmap->get_pixel(x, y);
+ if (color.alpha() == 0)
+ continue;
+
+ if (!min_content_x.has_value())
+ min_content_x = x;
+ else
+ min_content_x = min(*min_content_x, x);
+
+ if (!min_content_y.has_value())
+ min_content_y = y;
+ else
+ min_content_y = min(*min_content_y, y);
+
+ if (!max_content_x.has_value())
+ max_content_x = x;
+ else
+ max_content_x = max(*max_content_x, x);
+
+ if (!max_content_y.has_value())
+ max_content_y = y;
+ else
+ max_content_y = max(*max_content_y, y);
+ }
+ }
+
+ if (!min_content_x.has_value())
+ return {};
+
+ return Gfx::IntRect {
+ *min_content_x,
+ *min_content_y,
+ *max_content_x - *min_content_x + 1,
+ *max_content_y - *min_content_y + 1
+ };
+}
+
}
diff --git a/Userland/Applications/PixelPaint/Layer.h b/Userland/Applications/PixelPaint/Layer.h
index ab24d66cb3..a2996e24c0 100644
--- a/Userland/Applications/PixelPaint/Layer.h
+++ b/Userland/Applications/PixelPaint/Layer.h
@@ -61,6 +61,8 @@ public:
void resize(Gfx::IntRect const& new_rect, Gfx::Painter::ScalingMode scaling_mode);
void resize(Gfx::IntSize const& new_size, Gfx::IntPoint const& new_location, Gfx::Painter::ScalingMode scaling_mode);
+ Optional<Gfx::IntRect> nonempty_content_bounding_rect() const;
+
ErrorOr<void> try_set_bitmaps(NonnullRefPtr<Gfx::Bitmap> content, RefPtr<Gfx::Bitmap> mask);
void did_modify_bitmap(Gfx::IntRect const& = {});
diff --git a/Userland/Applications/PixelPaint/MainWidget.cpp b/Userland/Applications/PixelPaint/MainWidget.cpp
index 958f8dcb2d..f3de3a0f3d 100644
--- a/Userland/Applications/PixelPaint/MainWidget.cpp
+++ b/Userland/Applications/PixelPaint/MainWidget.cpp
@@ -560,6 +560,19 @@ void MainWidget::initialize_menubar(GUI::Window& window)
editor->did_complete_action("Crop Image to Selection"sv);
}));
+ m_image_menu->add_action(GUI::Action::create(
+ "&Crop Image to Content", g_icon_bag.crop, [&](auto&) {
+ auto* editor = current_image_editor();
+ VERIFY(editor);
+
+ auto content_bounding_rect = editor->image().nonempty_content_bounding_rect();
+ if (!content_bounding_rect.has_value())
+ return;
+
+ editor->image().crop(content_bounding_rect.value());
+ editor->did_complete_action("Crop Image to Content"sv);
+ }));
+
m_layer_menu = window.add_menu("&Layer");
m_layer_menu->add_action(GUI::Action::create(
"New &Layer...", { Mod_Ctrl | Mod_Shift, Key_N }, g_icon_bag.new_layer, [&](auto&) {