From 0f3252a80befc77aed785929ae09ece749c88266 Mon Sep 17 00:00:00 2001 From: David Capello Date: Tue, 17 May 2016 12:59:48 -0300 Subject: [PATCH] Add CopyMerged command (Ctrl+Shift+C) (fix #824) --- data/gui.xml | 4 +- src/app/CMakeLists.txt | 1 + src/app/commands/cmd_copy_merged.cpp | 51 ++++++++++++++++++++++ src/app/commands/commands_list.h | 1 + src/app/util/clipboard.cpp | 18 +++++--- src/app/util/clipboard.h | 2 + src/app/util/new_image_from_mask.cpp | 64 +++++++++++++++++++--------- src/app/util/new_image_from_mask.h | 6 ++- 8 files changed, 118 insertions(+), 29 deletions(-) create mode 100644 src/app/commands/cmd_copy_merged.cpp diff --git a/data/gui.xml b/data/gui.xml index 5fb3f329b..8132e0e5e 100644 --- a/data/gui.xml +++ b/data/gui.xml @@ -12,7 +12,7 @@ - + @@ -35,6 +35,7 @@ + @@ -530,6 +531,7 @@ + diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index 15be8fc5d..58750f8d1 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -180,6 +180,7 @@ add_library(app-lib commands/cmd_color_quantization.cpp commands/cmd_copy.cpp commands/cmd_copy_cel.cpp + commands/cmd_copy_merged.cpp commands/cmd_crop.cpp commands/cmd_cut.cpp commands/cmd_deselect_mask.cpp diff --git a/src/app/commands/cmd_copy_merged.cpp b/src/app/commands/cmd_copy_merged.cpp new file mode 100644 index 000000000..ad4a78f26 --- /dev/null +++ b/src/app/commands/cmd_copy_merged.cpp @@ -0,0 +1,51 @@ +// Aseprite +// Copyright (C) 2016 David Capello +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "app/commands/command.h" +#include "app/context_access.h" +#include "app/util/clipboard.h" + +namespace app { + +class CopyMergedCommand : public Command { +public: + CopyMergedCommand(); + Command* clone() const override { return new CopyMergedCommand(*this); } + +protected: + bool onEnabled(Context* ctx) override; + void onExecute(Context* ctx) override; +}; + +CopyMergedCommand::CopyMergedCommand() + : Command("CopyMerged", + "Copy Merged", + CmdUIOnlyFlag) +{ +} + +bool CopyMergedCommand::onEnabled(Context* ctx) +{ + return ctx->checkFlags(ContextFlags::ActiveDocumentIsReadable); +} + +void CopyMergedCommand::onExecute(Context* ctx) +{ + ContextReader reader(ctx); + clipboard::copy_merged(reader); +} + +Command* CommandFactory::createCopyMergedCommand() +{ + return new CopyMergedCommand; +} + +} // namespace app diff --git a/src/app/commands/commands_list.h b/src/app/commands/commands_list.h index 5bd933ef4..3447df22b 100644 --- a/src/app/commands/commands_list.h +++ b/src/app/commands/commands_list.h @@ -25,6 +25,7 @@ FOR_EACH_COMMAND(ColorQuantization) FOR_EACH_COMMAND(ConvolutionMatrix) FOR_EACH_COMMAND(Copy) FOR_EACH_COMMAND(CopyCel) +FOR_EACH_COMMAND(CopyMerged) FOR_EACH_COMMAND(CropSprite) FOR_EACH_COMMAND(Cut) FOR_EACH_COMMAND(DeselectMask) diff --git a/src/app/util/clipboard.cpp b/src/app/util/clipboard.cpp index e4b2f5ab3..96cb5f477 100644 --- a/src/app/util/clipboard.cpp +++ b/src/app/util/clipboard.cpp @@ -157,20 +157,17 @@ static void set_clipboard_image(Image* image, clipboard_range.invalidate(); } -static bool copy_from_document(const Site& site) +static bool copy_from_document(const Site& site, bool merged = false) { const app::Document* document = static_cast(site.document()); + ASSERT(document); - ASSERT(document != NULL); - ASSERT(document->isMaskVisible()); - - Image* image = new_image_from_mask(site); + const Mask* mask = document->mask(); + Image* image = new_image_from_mask(site, mask, merged); if (!image) return false; - const Mask* mask = document->mask(); const Palette* pal = document->sprite()->palette(site.frame()); - set_clipboard_image( image, (mask ? new Mask(*mask): nullptr), @@ -250,6 +247,13 @@ void copy(const ContextReader& reader) } } +void copy_merged(const ContextReader& reader) +{ + ASSERT(reader.document() != NULL); + + copy_from_document(*reader.site(), true); +} + void copy_range(const ContextReader& reader, const DocumentRange& range) { ASSERT(reader.document() != NULL); diff --git a/src/app/util/clipboard.h b/src/app/util/clipboard.h index 755a1e6f9..a117bb1a9 100644 --- a/src/app/util/clipboard.h +++ b/src/app/util/clipboard.h @@ -21,6 +21,7 @@ namespace doc { } namespace app { + class Document; class ContextReader; class ContextWriter; class DocumentRange; @@ -51,6 +52,7 @@ namespace app { void clear_content(); void cut(ContextWriter& context); void copy(const ContextReader& context); + void copy_merged(const ContextReader& context); void copy_range(const ContextReader& context, const DocumentRange& range); void copy_image(const Image* image, const Mask* mask, const Palette* palette); void copy_palette(const Palette* palette, const PalettePicks& picks); diff --git a/src/app/util/new_image_from_mask.cpp b/src/app/util/new_image_from_mask.cpp index d54362c16..a836a73bc 100644 --- a/src/app/util/new_image_from_mask.cpp +++ b/src/app/util/new_image_from_mask.cpp @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2001-2015 David Capello +// Copyright (C) 2001-2016 David Capello // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License version 2 as @@ -15,7 +15,9 @@ #include "base/unique_ptr.h" #include "doc/image_impl.h" #include "doc/mask.h" +#include "doc/primitives.h" #include "doc/site.h" +#include "render/render.h" namespace app { @@ -27,45 +29,69 @@ Image* new_image_from_mask(const Site& site) return new_image_from_mask(site, srcMask); } -doc::Image* new_image_from_mask(const doc::Site& site, const doc::Mask* srcMask) +doc::Image* new_image_from_mask(const doc::Site& site, + const doc::Mask* srcMask, + bool merged) { const Sprite* srcSprite = site.sprite(); - const Image* srcMaskBitmap = srcMask->bitmap(); - const gfx::Rect& srcBounds = srcMask->bounds(); + const Image* srcMaskBitmap = (srcMask ? srcMask->bitmap(): nullptr); + gfx::Rect srcBounds = (srcMask ? srcMask->bounds(): srcSprite->bounds()); int x, y, u, v, getx, gety; - const Image *src = site.image(&x, &y); ASSERT(srcSprite); - ASSERT(srcMask); - ASSERT(srcMaskBitmap); base::UniquePtr dst(Image::create(srcSprite->pixelFormat(), srcBounds.w, srcBounds.h)); if (!dst) return nullptr; // Clear the new image - dst->setMaskColor(src ? src->maskColor(): srcSprite->transparentColor()); + dst->setMaskColor(srcSprite->transparentColor()); clear_image(dst, dst->maskColor()); + const Image* src = nullptr; + if (merged) { + render::Render render; + render.renderSprite(dst, srcSprite, site.frame(), + gfx::Clip(0, 0, srcBounds)); + + src = dst; + } + else { + src = site.image(&x, &y); + } + // Copy the masked zones if (src) { - const LockImageBits maskBits(srcMaskBitmap, gfx::Rect(0, 0, srcBounds.w, srcBounds.h)); - LockImageBits::const_iterator mask_it = maskBits.begin(); + if (srcMaskBitmap) { + // Copy active layer with mask + const LockImageBits maskBits(srcMaskBitmap, gfx::Rect(0, 0, srcBounds.w, srcBounds.h)); + LockImageBits::const_iterator mask_it = maskBits.begin(); - for (v=0; v= 0) && (getx < src->width()) && - (gety >= 0) && (gety < src->height())) - dst->putPixel(u, v, src->getPixel(getx, gety)); + if ((getx >= 0) && (getx < src->width()) && + (gety >= 0) && (gety < src->height())) + dst->putPixel(u, v, src->getPixel(getx, gety)); + } + } + else { + if (!*mask_it) { + dst->putPixel(u, v, dst->maskColor()); + } + } } } } + else if (src != dst) { + copy_image(dst, src, -srcBounds.x, -srcBounds.y); + } } return dst.release(); diff --git a/src/app/util/new_image_from_mask.h b/src/app/util/new_image_from_mask.h index ea8d66ee2..e95cfc25d 100644 --- a/src/app/util/new_image_from_mask.h +++ b/src/app/util/new_image_from_mask.h @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2001-2015 David Capello +// Copyright (C) 2001-2016 David Capello // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License version 2 as @@ -18,7 +18,9 @@ namespace doc { namespace app { doc::Image* new_image_from_mask(const doc::Site& site); - doc::Image* new_image_from_mask(const doc::Site& site, const doc::Mask* mask); + doc::Image* new_image_from_mask(const doc::Site& site, + const doc::Mask* mask, + bool merged = false); } // namespace app