Skip to content

Commit

Permalink
Support --ignore-empty for --save-as (fix #551)
Browse files Browse the repository at this point in the history
  • Loading branch information
dacap committed Nov 7, 2018
1 parent e13d424 commit c657038
Show file tree
Hide file tree
Showing 10 changed files with 107 additions and 31 deletions.
3 changes: 3 additions & 0 deletions src/app/cli/default_cli_delegate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ void DefaultCliDelegate::saveFile(Context* ctx, const CliOpenFile& cof)
params.set("slice", cof.slice.c_str());
}

if (cof.ignoreEmpty)
params.set("ignoreEmpty", "true");

ctx->executeCommand(saveAsCommand, params);
}

Expand Down
7 changes: 6 additions & 1 deletion src/app/cli/preview_cli_delegate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ void PreviewCliDelegate::saveFile(Context* ctx, const CliOpenFile& cof)
std::cout << " - Trim\n";
}

if (cof.ignoreEmpty) {
std::cout << " - Ignore empty frames\n";
}

std::cout << " - Size: "
<< cof.document->sprite()->width() << "x"
<< cof.document->sprite()->height() << "\n";
Expand Down Expand Up @@ -136,7 +140,8 @@ void PreviewCliDelegate::saveFile(Context* ctx, const CliOpenFile& cof)
ctx,
cof.roi(),
cof.filename,
cof.filenameFormat));
cof.filenameFormat,
cof.ignoreEmpty));

if (fop) {
base::paths files;
Expand Down
7 changes: 6 additions & 1 deletion src/app/commands/cmd_save_file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ SaveFileBaseCommand::SaveFileBaseCommand(const char* id, CommandFlags flags)
: Command(id, flags)
{
m_useUI = true;
m_ignoreEmpty = false;
}

void SaveFileBaseCommand::onLoadParams(const Params& params)
Expand All @@ -113,6 +114,9 @@ void SaveFileBaseCommand::onLoadParams(const Params& params)

std::string useUI = params.get("useUI");
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.
Expand Down Expand Up @@ -194,7 +198,8 @@ void SaveFileBaseCommand::saveDocumentInBackground(
context,
roi,
filename,
m_filenameFormat));
m_filenameFormat,
m_ignoreEmpty));
if (!fop)
return;

Expand Down
1 change: 1 addition & 0 deletions src/app/commands/cmd_save_file.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ namespace app {
doc::SelectedFrames m_selFrames;
bool m_adjustFramesByFrameTag;
bool m_useUI;
bool m_ignoreEmpty;
};

} // namespace app
Expand Down
61 changes: 38 additions & 23 deletions src/app/file/file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@ int save_document(Context* context, Doc* document)
FileOp::createSaveDocumentOperation(
context,
FileOpROI(document, "", "", SelectedFrames(), false),
document->filename(), ""));
document->filename(), "",
false));
if (!fop)
return -1;

Expand Down Expand Up @@ -317,14 +318,16 @@ done:;
FileOp* FileOp::createSaveDocumentOperation(const Context* context,
const FileOpROI& roi,
const std::string& filename,
const std::string& filenameFormatArg)
const std::string& filenameFormatArg,
const bool ignoreEmptyFrames)
{
std::unique_ptr<FileOp> fop(
new FileOp(FileOpSave, const_cast<Context*>(context)));

// Document to save
fop->m_document = const_cast<Doc*>(roi.document());
fop->m_roi = roi;
fop->m_ignoreEmpty = ignoreEmptyFrames;

// Get the extension of the filename (in lower case)
LOG("FILE: Saving document \"%s\"\n", filename.c_str());
Expand Down Expand Up @@ -744,31 +747,42 @@ void FileOp::operate(IFileOpProgress* progress)
render.renderSprite(m_seq.image.get(), sprite, frame);
}

// Setup the palette.
sprite->palette(frame)->copyColorsTo(m_seq.palette);
bool save = true;

// Setup the filename to be used.
m_filename = m_seq.filename_list[outputFrame];
// Check if we have to ignore empty frames
if (m_ignoreEmpty &&
!sprite->isOpaque() &&
doc::is_empty_image(m_seq.image.get())) {
save = false;
}

// Make directories
{
std::string dir = base::get_file_path(m_filename);
try {
if (!base::is_directory(dir))
base::make_all_directories(dir);
if (save) {
// Setup the palette.
sprite->palette(frame)->copyColorsTo(m_seq.palette);

// 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());
}
}
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;
// 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;
Expand Down Expand Up @@ -1153,6 +1167,7 @@ FileOp::FileOp(FileOpType type, Context* context)
, m_done(false)
, m_stop(false)
, m_oneframe(false)
, m_ignoreEmpty(false)
, m_preserveColorProfile(
Preferences::instance().color.manage())
, m_embeddedColorProfile(false)
Expand Down
4 changes: 3 additions & 1 deletion src/app/file/file.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ namespace app {
static FileOp* createSaveDocumentOperation(const Context* context,
const FileOpROI& roi,
const std::string& filename,
const std::string& filenameFormat);
const std::string& filenameFormat,
const bool ignoreEmptyFrames);

~FileOp();

Expand Down Expand Up @@ -196,6 +197,7 @@ namespace app {
bool m_oneframe; // Load just one frame (in formats
// that support animation like
// GIF/FLI/ASE).
bool m_ignoreEmpty;

// Return if we've to save/embed the color space of the document
// in the file.
Expand Down
33 changes: 33 additions & 0 deletions src/doc/primitives.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Aseprite Document Library
// Copyright (c) 2018 Igara Studio S.A.
// Copyright (c) 2001-2016 David Capello
//
// This file is released under the terms of the MIT license.
Expand Down Expand Up @@ -295,6 +296,19 @@ void fill_ellipse(Image* image, int x1, int y1, int x2, int y2, color_t color)

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>
int count_diff_between_images_templ(const Image* i1, const Image* i2)
{
Expand All @@ -316,6 +330,25 @@ int count_diff_between_images_templ(const Image* i1, const Image* i2)

} // 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)
{
if ((i1->pixelFormat() != i2->pixelFormat()) ||
Expand Down
4 changes: 4 additions & 0 deletions src/doc/primitives.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Aseprite Document Library
// Copyright (c) 2018 Igara Studio S.A.
// Copyright (c) 2001-2016 David Capello
//
// This file is released under the terms of the MIT license.
Expand Down Expand Up @@ -39,6 +40,9 @@ namespace doc {
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);

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);

void remap_image(Image* image, const Remap& remap);
Expand Down
15 changes: 10 additions & 5 deletions src/doc/sprite.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,16 +149,21 @@ void Sprite::setColorSpace(const gfx::ColorSpacePtr& colorSpace)
cel->image()->setColorSpace(colorSpace);
}

bool Sprite::isOpaque() const
{
Layer* bg = backgroundLayer();
return (bg && bg->isVisible());
}

bool Sprite::needAlpha() const
{
switch (pixelFormat()) {
case IMAGE_RGB:
case IMAGE_GRAYSCALE: {
Layer* bg = backgroundLayer();
return (!bg || !bg->isVisible());
}
case IMAGE_GRAYSCALE:
return !isOpaque();
default:
return false;
}
return false;
}

bool Sprite::supportAlpha() const
Expand Down
3 changes: 3 additions & 0 deletions src/doc/sprite.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ namespace doc {
void setSize(int width, int height);
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
// than 255. Only RGBA and Grayscale images without background needs
// alpha channel in the render.
Expand Down

0 comments on commit c657038

Please sign in to comment.