mirror of
https://github.com/aseprite/aseprite.git
synced 2025-04-09 18:44:46 +00:00
Support --ignore-empty for --save-as (fix #551)
This commit is contained in:
parent
e13d424ced
commit
c657038b1a
@ -92,6 +92,9 @@ void DefaultCliDelegate::saveFile(Context* ctx, const CliOpenFile& cof)
|
|||||||
params.set("slice", cof.slice.c_str());
|
params.set("slice", cof.slice.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cof.ignoreEmpty)
|
||||||
|
params.set("ignoreEmpty", "true");
|
||||||
|
|
||||||
ctx->executeCommand(saveAsCommand, params);
|
ctx->executeCommand(saveAsCommand, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,6 +98,10 @@ void PreviewCliDelegate::saveFile(Context* ctx, const CliOpenFile& cof)
|
|||||||
std::cout << " - Trim\n";
|
std::cout << " - Trim\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cof.ignoreEmpty) {
|
||||||
|
std::cout << " - Ignore empty frames\n";
|
||||||
|
}
|
||||||
|
|
||||||
std::cout << " - Size: "
|
std::cout << " - Size: "
|
||||||
<< cof.document->sprite()->width() << "x"
|
<< cof.document->sprite()->width() << "x"
|
||||||
<< cof.document->sprite()->height() << "\n";
|
<< cof.document->sprite()->height() << "\n";
|
||||||
@ -136,7 +140,8 @@ void PreviewCliDelegate::saveFile(Context* ctx, const CliOpenFile& cof)
|
|||||||
ctx,
|
ctx,
|
||||||
cof.roi(),
|
cof.roi(),
|
||||||
cof.filename,
|
cof.filename,
|
||||||
cof.filenameFormat));
|
cof.filenameFormat,
|
||||||
|
cof.ignoreEmpty));
|
||||||
|
|
||||||
if (fop) {
|
if (fop) {
|
||||||
base::paths files;
|
base::paths files;
|
||||||
|
@ -89,6 +89,7 @@ SaveFileBaseCommand::SaveFileBaseCommand(const char* id, CommandFlags flags)
|
|||||||
: Command(id, flags)
|
: Command(id, flags)
|
||||||
{
|
{
|
||||||
m_useUI = true;
|
m_useUI = true;
|
||||||
|
m_ignoreEmpty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveFileBaseCommand::onLoadParams(const Params& params)
|
void SaveFileBaseCommand::onLoadParams(const Params& params)
|
||||||
@ -113,6 +114,9 @@ void SaveFileBaseCommand::onLoadParams(const Params& params)
|
|||||||
|
|
||||||
std::string useUI = params.get("useUI");
|
std::string useUI = params.get("useUI");
|
||||||
m_useUI = (useUI.empty() || (useUI == "true"));
|
m_useUI = (useUI.empty() || (useUI == "true"));
|
||||||
|
|
||||||
|
std::string ignoreEmpty = params.get("ignoreEmpty");
|
||||||
|
m_ignoreEmpty = (ignoreEmpty == "true");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if there is a current sprite to save.
|
// Returns true if there is a current sprite to save.
|
||||||
@ -194,7 +198,8 @@ void SaveFileBaseCommand::saveDocumentInBackground(
|
|||||||
context,
|
context,
|
||||||
roi,
|
roi,
|
||||||
filename,
|
filename,
|
||||||
m_filenameFormat));
|
m_filenameFormat,
|
||||||
|
m_ignoreEmpty));
|
||||||
if (!fop)
|
if (!fop)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -45,6 +45,7 @@ namespace app {
|
|||||||
doc::SelectedFrames m_selFrames;
|
doc::SelectedFrames m_selFrames;
|
||||||
bool m_adjustFramesByFrameTag;
|
bool m_adjustFramesByFrameTag;
|
||||||
bool m_useUI;
|
bool m_useUI;
|
||||||
|
bool m_ignoreEmpty;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace app
|
} // namespace app
|
||||||
|
@ -104,7 +104,8 @@ int save_document(Context* context, Doc* document)
|
|||||||
FileOp::createSaveDocumentOperation(
|
FileOp::createSaveDocumentOperation(
|
||||||
context,
|
context,
|
||||||
FileOpROI(document, "", "", SelectedFrames(), false),
|
FileOpROI(document, "", "", SelectedFrames(), false),
|
||||||
document->filename(), ""));
|
document->filename(), "",
|
||||||
|
false));
|
||||||
if (!fop)
|
if (!fop)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@ -317,7 +318,8 @@ done:;
|
|||||||
FileOp* FileOp::createSaveDocumentOperation(const Context* context,
|
FileOp* FileOp::createSaveDocumentOperation(const Context* context,
|
||||||
const FileOpROI& roi,
|
const FileOpROI& roi,
|
||||||
const std::string& filename,
|
const std::string& filename,
|
||||||
const std::string& filenameFormatArg)
|
const std::string& filenameFormatArg,
|
||||||
|
const bool ignoreEmptyFrames)
|
||||||
{
|
{
|
||||||
std::unique_ptr<FileOp> fop(
|
std::unique_ptr<FileOp> fop(
|
||||||
new FileOp(FileOpSave, const_cast<Context*>(context)));
|
new FileOp(FileOpSave, const_cast<Context*>(context)));
|
||||||
@ -325,6 +327,7 @@ FileOp* FileOp::createSaveDocumentOperation(const Context* context,
|
|||||||
// Document to save
|
// Document to save
|
||||||
fop->m_document = const_cast<Doc*>(roi.document());
|
fop->m_document = const_cast<Doc*>(roi.document());
|
||||||
fop->m_roi = roi;
|
fop->m_roi = roi;
|
||||||
|
fop->m_ignoreEmpty = ignoreEmptyFrames;
|
||||||
|
|
||||||
// Get the extension of the filename (in lower case)
|
// Get the extension of the filename (in lower case)
|
||||||
LOG("FILE: Saving document \"%s\"\n", filename.c_str());
|
LOG("FILE: Saving document \"%s\"\n", filename.c_str());
|
||||||
@ -744,31 +747,42 @@ void FileOp::operate(IFileOpProgress* progress)
|
|||||||
render.renderSprite(m_seq.image.get(), sprite, frame);
|
render.renderSprite(m_seq.image.get(), sprite, frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup the palette.
|
bool save = true;
|
||||||
sprite->palette(frame)->copyColorsTo(m_seq.palette);
|
|
||||||
|
|
||||||
// Setup the filename to be used.
|
// Check if we have to ignore empty frames
|
||||||
m_filename = m_seq.filename_list[outputFrame];
|
if (m_ignoreEmpty &&
|
||||||
|
!sprite->isOpaque() &&
|
||||||
// Make directories
|
doc::is_empty_image(m_seq.image.get())) {
|
||||||
{
|
save = false;
|
||||||
std::string dir = base::get_file_path(m_filename);
|
|
||||||
try {
|
|
||||||
if (!base::is_directory(dir))
|
|
||||||
base::make_all_directories(dir);
|
|
||||||
}
|
|
||||||
catch (const std::exception& ex) {
|
|
||||||
// Ignore errors and make the delegate fail
|
|
||||||
setError("Error creating directory \"%s\"\n%s",
|
|
||||||
dir.c_str(), ex.what());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call the "save" procedure... did it fail?
|
if (save) {
|
||||||
if (!m_format->save(this)) {
|
// Setup the palette.
|
||||||
setError("Error saving frame %d in the file \"%s\"\n",
|
sprite->palette(frame)->copyColorsTo(m_seq.palette);
|
||||||
outputFrame+1, m_filename.c_str());
|
|
||||||
break;
|
// Setup the filename to be used.
|
||||||
|
m_filename = m_seq.filename_list[outputFrame];
|
||||||
|
|
||||||
|
// Make directories
|
||||||
|
{
|
||||||
|
std::string dir = base::get_file_path(m_filename);
|
||||||
|
try {
|
||||||
|
if (!base::is_directory(dir))
|
||||||
|
base::make_all_directories(dir);
|
||||||
|
}
|
||||||
|
catch (const std::exception& ex) {
|
||||||
|
// Ignore errors and make the delegate fail
|
||||||
|
setError("Error creating directory \"%s\"\n%s",
|
||||||
|
dir.c_str(), ex.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call the "save" procedure... did it fail?
|
||||||
|
if (!m_format->save(this)) {
|
||||||
|
setError("Error saving frame %d in the file \"%s\"\n",
|
||||||
|
outputFrame+1, m_filename.c_str());
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_seq.progress_offset += m_seq.progress_fraction;
|
m_seq.progress_offset += m_seq.progress_fraction;
|
||||||
@ -1153,6 +1167,7 @@ FileOp::FileOp(FileOpType type, Context* context)
|
|||||||
, m_done(false)
|
, m_done(false)
|
||||||
, m_stop(false)
|
, m_stop(false)
|
||||||
, m_oneframe(false)
|
, m_oneframe(false)
|
||||||
|
, m_ignoreEmpty(false)
|
||||||
, m_preserveColorProfile(
|
, m_preserveColorProfile(
|
||||||
Preferences::instance().color.manage())
|
Preferences::instance().color.manage())
|
||||||
, m_embeddedColorProfile(false)
|
, m_embeddedColorProfile(false)
|
||||||
|
@ -105,7 +105,8 @@ namespace app {
|
|||||||
static FileOp* createSaveDocumentOperation(const Context* context,
|
static FileOp* createSaveDocumentOperation(const Context* context,
|
||||||
const FileOpROI& roi,
|
const FileOpROI& roi,
|
||||||
const std::string& filename,
|
const std::string& filename,
|
||||||
const std::string& filenameFormat);
|
const std::string& filenameFormat,
|
||||||
|
const bool ignoreEmptyFrames);
|
||||||
|
|
||||||
~FileOp();
|
~FileOp();
|
||||||
|
|
||||||
@ -196,6 +197,7 @@ namespace app {
|
|||||||
bool m_oneframe; // Load just one frame (in formats
|
bool m_oneframe; // Load just one frame (in formats
|
||||||
// that support animation like
|
// that support animation like
|
||||||
// GIF/FLI/ASE).
|
// GIF/FLI/ASE).
|
||||||
|
bool m_ignoreEmpty;
|
||||||
|
|
||||||
// Return if we've to save/embed the color space of the document
|
// Return if we've to save/embed the color space of the document
|
||||||
// in the file.
|
// in the file.
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
// Aseprite Document Library
|
// Aseprite Document Library
|
||||||
|
// Copyright (c) 2018 Igara Studio S.A.
|
||||||
// Copyright (c) 2001-2016 David Capello
|
// Copyright (c) 2001-2016 David Capello
|
||||||
//
|
//
|
||||||
// This file is released under the terms of the MIT license.
|
// This file is released under the terms of the MIT license.
|
||||||
@ -295,6 +296,19 @@ void fill_ellipse(Image* image, int x1, int y1, int x2, int y2, color_t color)
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
template<typename ImageTraits>
|
||||||
|
bool is_plain_image_templ(const Image* img, const color_t color)
|
||||||
|
{
|
||||||
|
const LockImageBits<ImageTraits> bits(img);
|
||||||
|
typename LockImageBits<ImageTraits>::const_iterator it, end;
|
||||||
|
for (it=bits.begin(), end=bits.end(); it!=end; ++it) {
|
||||||
|
if (*it != color)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ASSERT(it == end);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename ImageTraits>
|
template<typename ImageTraits>
|
||||||
int count_diff_between_images_templ(const Image* i1, const Image* i2)
|
int count_diff_between_images_templ(const Image* i1, const Image* i2)
|
||||||
{
|
{
|
||||||
@ -316,6 +330,25 @@ int count_diff_between_images_templ(const Image* i1, const Image* i2)
|
|||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
|
bool is_plain_image(const Image* img, color_t c)
|
||||||
|
{
|
||||||
|
switch (img->pixelFormat()) {
|
||||||
|
case IMAGE_RGB: return is_plain_image_templ<RgbTraits>(img, c);
|
||||||
|
case IMAGE_GRAYSCALE: return is_plain_image_templ<GrayscaleTraits>(img, c);
|
||||||
|
case IMAGE_INDEXED: return is_plain_image_templ<IndexedTraits>(img, c);
|
||||||
|
case IMAGE_BITMAP: return is_plain_image_templ<BitmapTraits>(img, c);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_empty_image(const Image* img)
|
||||||
|
{
|
||||||
|
color_t c = 0; // alpha = 0
|
||||||
|
if (img->colorMode() == ColorMode::INDEXED)
|
||||||
|
c = img->maskColor();
|
||||||
|
return is_plain_image(img, 0);
|
||||||
|
}
|
||||||
|
|
||||||
int count_diff_between_images(const Image* i1, const Image* i2)
|
int count_diff_between_images(const Image* i1, const Image* i2)
|
||||||
{
|
{
|
||||||
if ((i1->pixelFormat() != i2->pixelFormat()) ||
|
if ((i1->pixelFormat() != i2->pixelFormat()) ||
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
// Aseprite Document Library
|
// Aseprite Document Library
|
||||||
|
// Copyright (c) 2018 Igara Studio S.A.
|
||||||
// Copyright (c) 2001-2016 David Capello
|
// Copyright (c) 2001-2016 David Capello
|
||||||
//
|
//
|
||||||
// This file is released under the terms of the MIT license.
|
// This file is released under the terms of the MIT license.
|
||||||
@ -39,6 +40,9 @@ namespace doc {
|
|||||||
void draw_ellipse(Image* image, int x1, int y1, int x2, int y2, color_t c);
|
void draw_ellipse(Image* image, int x1, int y1, int x2, int y2, color_t c);
|
||||||
void fill_ellipse(Image* image, int x1, int y1, int x2, int y2, color_t c);
|
void fill_ellipse(Image* image, int x1, int y1, int x2, int y2, color_t c);
|
||||||
|
|
||||||
|
bool is_plain_image(const Image* img, color_t c);
|
||||||
|
bool is_empty_image(const Image* img);
|
||||||
|
|
||||||
int count_diff_between_images(const Image* i1, const Image* i2);
|
int count_diff_between_images(const Image* i1, const Image* i2);
|
||||||
|
|
||||||
void remap_image(Image* image, const Remap& remap);
|
void remap_image(Image* image, const Remap& remap);
|
||||||
|
@ -149,16 +149,21 @@ void Sprite::setColorSpace(const gfx::ColorSpacePtr& colorSpace)
|
|||||||
cel->image()->setColorSpace(colorSpace);
|
cel->image()->setColorSpace(colorSpace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Sprite::isOpaque() const
|
||||||
|
{
|
||||||
|
Layer* bg = backgroundLayer();
|
||||||
|
return (bg && bg->isVisible());
|
||||||
|
}
|
||||||
|
|
||||||
bool Sprite::needAlpha() const
|
bool Sprite::needAlpha() const
|
||||||
{
|
{
|
||||||
switch (pixelFormat()) {
|
switch (pixelFormat()) {
|
||||||
case IMAGE_RGB:
|
case IMAGE_RGB:
|
||||||
case IMAGE_GRAYSCALE: {
|
case IMAGE_GRAYSCALE:
|
||||||
Layer* bg = backgroundLayer();
|
return !isOpaque();
|
||||||
return (!bg || !bg->isVisible());
|
default:
|
||||||
}
|
return false;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Sprite::supportAlpha() const
|
bool Sprite::supportAlpha() const
|
||||||
|
@ -84,6 +84,9 @@ namespace doc {
|
|||||||
void setSize(int width, int height);
|
void setSize(int width, int height);
|
||||||
void setColorSpace(const gfx::ColorSpacePtr& colorSpace);
|
void setColorSpace(const gfx::ColorSpacePtr& colorSpace);
|
||||||
|
|
||||||
|
// Returns true if the sprite has a background layer and it's visible
|
||||||
|
bool isOpaque() const;
|
||||||
|
|
||||||
// Returns true if the rendered images will contain alpha values less
|
// Returns true if the rendered images will contain alpha values less
|
||||||
// than 255. Only RGBA and Grayscale images without background needs
|
// than 255. Only RGBA and Grayscale images without background needs
|
||||||
// alpha channel in the render.
|
// alpha channel in the render.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user