Add the logic side to export the selection only (fix #645)

This commit is contained in:
David Capello 2022-08-12 20:11:25 -03:00
parent 3c3d2dafe6
commit a13423bd70
7 changed files with 57 additions and 12 deletions

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2019-2022 Igara Studio S.A.
// Copyright (C) 2016-2017 David Capello
//
// This program is distributed under the terms of
@ -47,6 +47,7 @@ FileOpROI CliOpenFile::roi() const
selFrames.insert(fromFrame, toFrame);
return FileOpROI(document,
gfx::Rect(),
slice,
tag,
selFrames,

View File

@ -37,6 +37,7 @@
#include "base/fs.h"
#include "base/scoped_value.h"
#include "base/thread.h"
#include "doc/mask.h"
#include "doc/sprite.h"
#include "doc/tag.h"
#include "fmt/format.h"
@ -204,7 +205,12 @@ void SaveFileBaseCommand::saveDocumentInBackground(
}
}
FileOpROI roi(document, params().slice(), params().tag(),
gfx::Rect bounds;
if (params().bounds.isSet())
bounds = params().bounds();
FileOpROI roi(document, bounds,
params().slice(), params().tag(),
m_selFrames, m_adjustFramesByTag);
std::unique_ptr<FileOp> fop(
@ -346,6 +352,7 @@ void SaveFileCopyAsCommand::onExecute(Context* context)
std::string frames = kAllFrames;
bool applyPixelRatio = false;
double scale = params().scale();
gfx::Rect bounds = params().bounds();
doc::AniDir aniDirValue = params().aniDir();
bool isForTwitter = false;
@ -382,6 +389,13 @@ void SaveFileCopyAsCommand::onExecute(Context* context)
if (params().scale.isSet()) win.setResizeScale(scale);
if (params().aniDir.isSet()) win.setAniDir(aniDirValue);
if (params().slice.isSet()) win.setArea(params().slice());
else if (params().bounds.isSet() &&
doc->isMaskVisible() &&
doc->mask()->bounds() == params().bounds()) {
win.setArea(kSelectedCanvas);
}
win.remapWindow();
load_window_pos(&win, "ExportFile");
again:;
@ -410,6 +424,9 @@ void SaveFileCopyAsCommand::onExecute(Context* context)
layers = win.layersValue();
frames = win.framesValue();
scale = win.resizeValue();
params().slice(win.areaValue()); // Set slice
if (win.areaValue() == kSelectedCanvas && doc->isMaskVisible())
bounds = doc->mask()->bounds();
applyPixelRatio = win.applyPixelRatio();
aniDirValue = win.aniDirValue();
isForTwitter = win.isForTwitter();
@ -480,8 +497,10 @@ void SaveFileCopyAsCommand::onExecute(Context* context)
m_adjustFramesByTag = false;
}
// Set ani dir
// Set other parameters
params().aniDir(aniDirValue);
if (!bounds.isEmpty())
params().bounds(bounds);
// TODO This should be set as options for the specific encoder
GifEncoderDurationFix fixGif(isForTwitter);

View File

@ -14,6 +14,7 @@
#include "doc/anidir.h"
#include "doc/selected_frames.h"
#include "gfx/point.h"
#include "gfx/rect.h"
#include <string>
@ -31,6 +32,7 @@ namespace app {
Param<doc::frame_t> toFrame { this, 0, { "toFrame", "to-frame" } };
Param<bool> ignoreEmpty { this, false, "ignoreEmpty" };
Param<double> scale { this, 1.0, "scale" };
Param<gfx::Rect> bounds { this, gfx::Rect(), "bounds" };
};
class SaveFileBaseCommand : public CommandWithNewParams<SaveFileParams> {

View File

@ -65,9 +65,9 @@ public:
ASSERT(m_doc && m_sprite);
}
void setSliceBounds(const gfx::Rect& sliceBounds) {
m_spec.setWidth(sliceBounds.w * m_scale.x);
m_spec.setHeight(sliceBounds.h * m_scale.y);
void setSpecSize(const gfx::Size& size) {
m_spec.setWidth(size.w * m_scale.x);
m_spec.setHeight(size.h * m_scale.y);
}
void setUnscaledImage(const doc::frame_t frame,
@ -234,7 +234,7 @@ int save_document(Context* context, Doc* document)
std::unique_ptr<FileOp> fop(
FileOp::createSaveDocumentOperation(
context,
FileOpROI(document, "", "", SelectedFrames(), false),
FileOpROI(document, gfx::Rect(), "", "", SelectedFrames(), false),
document->filename(), "",
false));
if (!fop)
@ -270,11 +270,13 @@ FileOpROI::FileOpROI()
}
FileOpROI::FileOpROI(const Doc* doc,
const gfx::Rect& bounds,
const std::string& sliceName,
const std::string& tagName,
const doc::SelectedFrames& selFrames,
const bool adjustByTag)
: m_document(doc)
, m_bounds(bounds)
, m_slice(nullptr)
, m_tag(nullptr)
, m_selFrames(selFrames)
@ -917,23 +919,35 @@ void FileOp::operate(IFileOpProgress* progress)
frame_t outputFrame = 0;
for (frame_t frame : m_roi.selectedFrames()) {
// Draw the "frame" in "m_seq.image"
gfx::Rect bounds;
// Export bounds of specific slice
if (m_roi.slice()) {
const SliceKey* key = m_roi.slice()->getByFrame(frame);
if (!key || key->isEmpty())
continue; // Skip frame because there is no slice key
bounds = key->bounds();
}
// Export specific bounds
else if (!m_roi.bounds().isEmpty()) {
bounds = m_roi.bounds();
}
// Draw the "frame" in "m_seq.image" with the given bounds
// (bounds can be the selection bounds or a slice key bounds)
if (!bounds.isEmpty()) {
if (m_abstractImage)
m_abstractImage->setSliceBounds(key->bounds());
m_abstractImage->setSpecSize(bounds.size());
m_seq.image.reset(
Image::create(sprite->pixelFormat(),
key->bounds().w,
key->bounds().h));
bounds.w,
bounds.h));
render.renderSprite(
m_seq.image.get(), sprite, frame,
gfx::Clip(gfx::Point(0, 0), key->bounds()));
gfx::Clip(gfx::Point(0, 0), bounds));
}
else {
render.renderSprite(m_seq.image.get(), sprite, frame);

View File

@ -72,12 +72,14 @@ namespace app {
public:
FileOpROI();
FileOpROI(const Doc* doc,
const gfx::Rect& bounds,
const std::string& sliceName,
const std::string& tagName,
const doc::SelectedFrames& selFrames,
const bool adjustByTag);
const Doc* document() const { return m_document; }
const gfx::Rect& bounds() const { return m_bounds; }
doc::Slice* slice() const { return m_slice; }
doc::Tag* tag() const { return m_tag; }
doc::frame_t fromFrame() const { return m_selFrames.firstFrame(); }
@ -90,6 +92,7 @@ namespace app {
private:
const Doc* m_document;
gfx::Rect m_bounds;
doc::Slice* m_slice;
doc::Tag* m_tag;
doc::SelectedFrames m_selFrames;

View File

@ -153,6 +153,11 @@ void ExportFileWindow::setResizeScale(double scale)
resize()->setValue(fmt::format("{:.2f}", 100.0 * scale));
}
void ExportFileWindow::setArea(const std::string& areaValue)
{
area()->setValue(areaValue);
}
void ExportFileWindow::setAniDir(const doc::AniDir aniDir)
{
anidir()->setSelectedItemIndex(int(aniDir));

View File

@ -37,6 +37,7 @@ namespace app {
void setOutputFilename(const std::string& pathAndFilename);
void setResizeScale(const double scale);
void setArea(const std::string& area);
void setAniDir(const doc::AniDir aniDir);
obs::signal<std::string()> SelectOutputFile;