浏览代码

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.
Davipb 4 年之前
父节点
当前提交
20b2c46019
共有 1 个文件被更改,包括 30 次插入3 次删除
  1. 30 3
      Userland/Applications/PixelPaint/Layer.cpp

+ 30 - 3
Userland/Applications/PixelPaint/Layer.cpp

@@ -92,9 +92,36 @@ void Layer::set_name(String name)
 
 
 RefPtr<Gfx::Bitmap> Layer::try_copy_bitmap(Selection const& selection) const
 RefPtr<Gfx::Bitmap> 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<int>(pixel.alpha());
+            auto selection_alpha = static_cast<int>(selection.get_selection_alpha(image_point));
+            auto new_alpha = (pixel_alpha * selection_alpha) / 0xFF;
+            pixel.set_alpha(static_cast<u8>(clamp(new_alpha, 0, 0xFF)));
+
+            result->set_pixel(result_point, pixel);
+        }
+    }
+
+    return result;
 }
 }
 
 
 }
 }