From 20b2c46019552894dba84cd9802cad42cedac8c7 Mon Sep 17 00:00:00 2001 From: Davipb Date: Sun, 20 Jun 2021 10:59:21 -0300 Subject: [PATCH] PixelPaint: Allow copying arbitrary selections This replaces the naive copy algorithm that only supported rectangular and 100% opaque selections with a more general approach that supports any shape and alpha value. Note that we now make a brand new bitmap with a hardcoded format instead of just cropping the layer's existing bitmap. This is done to ensure that the final clipboard image will have an alpha channel. --- Userland/Applications/PixelPaint/Layer.cpp | 33 ++++++++++++++++++++-- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/Userland/Applications/PixelPaint/Layer.cpp b/Userland/Applications/PixelPaint/Layer.cpp index 7aa59bcc92..1db8722640 100644 --- a/Userland/Applications/PixelPaint/Layer.cpp +++ b/Userland/Applications/PixelPaint/Layer.cpp @@ -92,9 +92,36 @@ void Layer::set_name(String name) RefPtr Layer::try_copy_bitmap(Selection const& selection) const { - auto bounding_rect = selection.bounding_rect().translated(-m_location); - // FIXME: This needs to be smarter once we add more complex selections. - return m_bitmap->cropped(bounding_rect); + auto selection_rect = selection.bounding_rect(); + + auto result = Gfx::Bitmap::create(Gfx::BitmapFormat::BGRA8888, selection_rect.size()); + VERIFY(result->has_alpha_channel()); + + for (int y = selection_rect.top(); y <= selection_rect.bottom(); y++) { + for (int x = selection_rect.left(); x <= selection_rect.right(); x++) { + + Gfx::IntPoint image_point { x, y }; + auto layer_point = image_point - m_location; + auto result_point = image_point - selection_rect.top_left(); + + if (!m_bitmap->physical_rect().contains(layer_point)) { + result->set_pixel(result_point, Gfx::Color::Transparent); + continue; + } + + auto pixel = m_bitmap->get_pixel(layer_point); + + // Widen to int before multiplying to avoid overflow issues + auto pixel_alpha = static_cast(pixel.alpha()); + auto selection_alpha = static_cast(selection.get_selection_alpha(image_point)); + auto new_alpha = (pixel_alpha * selection_alpha) / 0xFF; + pixel.set_alpha(static_cast(clamp(new_alpha, 0, 0xFF))); + + result->set_pixel(result_point, pixel); + } + } + + return result; } }