Add "Trim Sprite" to DocExporter/Export Sprite Sheet/--trim-sprite CLI

This commit is contained in:
David Capello 2019-10-22 21:27:15 -03:00
parent f375ced883
commit cd68a4fe0a
8 changed files with 74 additions and 41 deletions

View File

@ -59,7 +59,8 @@ AppOptions::AppOptions(int argc, const char* argv[])
, m_borderPadding(m_po.add("border-padding").requiresValue("<value>").description("Add padding on the texture borders")) , m_borderPadding(m_po.add("border-padding").requiresValue("<value>").description("Add padding on the texture borders"))
, m_shapePadding(m_po.add("shape-padding").requiresValue("<value>").description("Add padding between frames")) , m_shapePadding(m_po.add("shape-padding").requiresValue("<value>").description("Add padding between frames"))
, m_innerPadding(m_po.add("inner-padding").requiresValue("<value>").description("Add padding inside each frame")) , m_innerPadding(m_po.add("inner-padding").requiresValue("<value>").description("Add padding inside each frame"))
, m_trim(m_po.add("trim").description("Trim all images before exporting")) , m_trim(m_po.add("trim").description("Trim whole sprite for --save-as\nor individual frames for --sheet"))
, m_trimSprite(m_po.add("trim-sprite").description("Trim the whole sprite (for --save-as and --sheet)"))
, m_trimByGrid(m_po.add("trim-by-grid").description("Trim all images by its correspondent grid boundaries before exporting")) , m_trimByGrid(m_po.add("trim-by-grid").description("Trim all images by its correspondent grid boundaries before exporting"))
, m_crop(m_po.add("crop").requiresValue("x,y,width,height").description("Crop all the images to the given rectangle")) , m_crop(m_po.add("crop").requiresValue("x,y,width,height").description("Crop all the images to the given rectangle"))
, m_slice(m_po.add("slice").requiresValue("<name>").description("Crop the sprite to the given slice area")) , m_slice(m_po.add("slice").requiresValue("<name>").description("Crop the sprite to the given slice area"))

View File

@ -74,6 +74,7 @@ public:
const Option& shapePadding() const { return m_shapePadding; } const Option& shapePadding() const { return m_shapePadding; }
const Option& innerPadding() const { return m_innerPadding; } const Option& innerPadding() const { return m_innerPadding; }
const Option& trim() const { return m_trim; } const Option& trim() const { return m_trim; }
const Option& trimSprite() const { return m_trimSprite; }
const Option& trimByGrid() const { return m_trimByGrid; } const Option& trimByGrid() const { return m_trimByGrid; }
const Option& crop() const { return m_crop; } const Option& crop() const { return m_crop; }
const Option& slice() const { return m_slice; } const Option& slice() const { return m_slice; }
@ -135,6 +136,7 @@ private:
Option& m_shapePadding; Option& m_shapePadding;
Option& m_innerPadding; Option& m_innerPadding;
Option& m_trim; Option& m_trim;
Option& m_trimSprite;
Option& m_trimByGrid; Option& m_trimByGrid;
Option& m_crop; Option& m_crop;
Option& m_slice; Option& m_slice;

View File

@ -331,6 +331,12 @@ void CliProcessor::process(Context* ctx)
if (m_exporter) if (m_exporter)
m_exporter->setTrimCels(true); m_exporter->setTrimCels(true);
} }
// --trim-sprite
else if (opt == &m_options.trimSprite()) {
cof.trim = true;
if (m_exporter)
m_exporter->setTrimSprite(true);
}
// --trim-by-grid // --trim-by-grid
else if (opt == &m_options.trimByGrid()) { else if (opt == &m_options.trimByGrid()) {
cof.trim = cof.trimByGrid = true; cof.trim = cof.trimByGrid = true;

View File

@ -317,9 +317,6 @@ public:
fill_frames_combobox( fill_frames_combobox(
m_sprite, frames(), params.tag()); m_sprite, frames(), params.tag());
// TODO enable this when DocExporter support a global trim per sprite
trimSpriteEnabled()->setVisible(false);
openGenerated()->setSelected(params.openGenerated()); openGenerated()->setSelected(params.openGenerated());
trimSpriteEnabled()->setSelected(params.trimSprite()); trimSpriteEnabled()->setSelected(params.trimSprite());
trimEnabled()->setSelected(params.trim()); trimEnabled()->setSelected(params.trim());
@ -1121,6 +1118,7 @@ void ExportSpriteSheetCommand::onExecute(Context* context)
docPref.spriteSheet.borderPadding (params.borderPadding()); docPref.spriteSheet.borderPadding (params.borderPadding());
docPref.spriteSheet.shapePadding (params.shapePadding()); docPref.spriteSheet.shapePadding (params.shapePadding());
docPref.spriteSheet.innerPadding (params.innerPadding()); docPref.spriteSheet.innerPadding (params.innerPadding());
docPref.spriteSheet.trimSprite (params.trimSprite());
docPref.spriteSheet.trim (params.trim()); docPref.spriteSheet.trim (params.trim());
docPref.spriteSheet.trimByGrid (params.trimByGrid()); docPref.spriteSheet.trimByGrid (params.trimByGrid());
docPref.spriteSheet.extrude (params.extrude()); docPref.spriteSheet.extrude (params.extrude());

View File

@ -10,7 +10,6 @@
#endif #endif
#include "app/doc_api.h" #include "app/doc_api.h"
#include "app/snap_to_grid.h"
#include "app/cmd/add_cel.h" #include "app/cmd/add_cel.h"
#include "app/cmd/add_frame.h" #include "app/cmd/add_frame.h"
@ -48,6 +47,7 @@
#include "app/doc.h" #include "app/doc.h"
#include "app/doc_undo.h" #include "app/doc_undo.h"
#include "app/pref/preferences.h" #include "app/pref/preferences.h"
#include "app/snap_to_grid.h"
#include "app/transaction.h" #include "app/transaction.h"
#include "app/util/autocrop.h" #include "app/util/autocrop.h"
#include "doc/algorithm/flip_image.h" #include "doc/algorithm/flip_image.h"
@ -315,39 +315,7 @@ bool DocApi::cropCel(LayerImage* layer,
void DocApi::trimSprite(Sprite* sprite, const bool byGrid) void DocApi::trimSprite(Sprite* sprite, const bool byGrid)
{ {
gfx::Rect bounds; gfx::Rect bounds = get_trimmed_bounds(sprite, byGrid);
std::unique_ptr<Image> image_wrap(Image::create(sprite->spec()));
Image* image = image_wrap.get();
render::Render render;
for (frame_t frame(0); frame<sprite->totalFrames(); ++frame) {
render.renderSprite(image, sprite, frame);
gfx::Rect frameBounds;
doc::color_t refColor;
if (get_best_refcolor_for_trimming(image, refColor) &&
doc::algorithm::shrink_bounds(image, frameBounds, refColor)) {
bounds = bounds.createUnion(frameBounds);
}
// TODO merge this code with the code in DocExporter::captureSamples()
if (byGrid) {
Doc* doc = m_document;
const gfx::Rect& gridBounds = doc->sprite()->gridBounds();
gfx::Point posTopLeft =
snap_to_grid(gridBounds,
bounds.origin(),
PreferSnapTo::FloorGrid);
gfx::Point posBottomRight =
snap_to_grid(gridBounds,
bounds.point2(),
PreferSnapTo::CeilGrid);
bounds = gfx::Rect(posTopLeft, posBottomRight);
}
}
if (!bounds.isEmpty()) if (!bounds.isEmpty())
cropSprite(sprite, bounds); cropSprite(sprite, bounds);
} }

View File

@ -19,7 +19,7 @@
#include "app/filename_formatter.h" #include "app/filename_formatter.h"
#include "app/restore_visible_layers.h" #include "app/restore_visible_layers.h"
#include "app/snap_to_grid.h" #include "app/snap_to_grid.h"
#include "doc/images_map.h" #include "app/util/autocrop.h"
#include "base/convert_to.h" #include "base/convert_to.h"
#include "base/fs.h" #include "base/fs.h"
#include "base/fstream_path.h" #include "base/fstream_path.h"
@ -29,6 +29,7 @@
#include "doc/cel.h" #include "doc/cel.h"
#include "doc/image.h" #include "doc/image.h"
#include "doc/images_map.h" #include "doc/images_map.h"
#include "doc/images_map.h"
#include "doc/layer.h" #include "doc/layer.h"
#include "doc/palette.h" #include "doc/palette.h"
#include "doc/primitives.h" #include "doc/primitives.h"
@ -829,6 +830,10 @@ void DocExporter::captureSamples(Samples& samples,
(tag != nullptr)); // Has tag (tag != nullptr)); // Has tag
} }
gfx::Rect spriteBounds = sprite->bounds();
if (m_trimSprite)
spriteBounds = get_trimmed_bounds(sprite, m_trimByGrid);
frame_t outputFrame = 0; frame_t outputFrame = 0;
for (frame_t frame : item.getSelectedFrames()) { for (frame_t frame : item.getSelectedFrames()) {
if (token.canceled()) if (token.canceled())
@ -911,7 +916,7 @@ void DocExporter::captureSamples(Samples& samples,
else if (m_ignoreEmptyCels) else if (m_ignoreEmptyCels)
refColor = sprite->transparentColor(); refColor = sprite->transparentColor();
if (!algorithm::shrink_bounds(sampleRender.get(), frameBounds, refColor)) { if (!algorithm::shrink_bounds(sampleRender.get(), spriteBounds, frameBounds, refColor)) {
// If shrink_bounds() returns false, it's because the whole // If shrink_bounds() returns false, it's because the whole
// image is transparent (equal to the mask color). // image is transparent (equal to the mask color).
@ -950,7 +955,11 @@ void DocExporter::captureSamples(Samples& samples,
} }
sample.setTrimmedBounds(frameBounds); sample.setTrimmedBounds(frameBounds);
} }
else if (m_trimSprite)
sample.setTrimmedBounds(spriteBounds);
} }
else if (m_trimSprite)
sample.setTrimmedBounds(spriteBounds);
samples.addSample(sample); samples.addSample(sample);

View File

@ -9,12 +9,17 @@
#include "config.h" #include "config.h"
#endif #endif
#include "app/util/autocrop.h"
#include "app/snap_to_grid.h"
#include "doc/algorithm/shrink_bounds.h"
#include "doc/image.h" #include "doc/image.h"
#include "doc/mask.h" #include "doc/mask.h"
#include "doc/sprite.h" #include "doc/sprite.h"
#include "app/util/autocrop.h" #include "render/render.h"
#include <algorithm> #include <algorithm>
#include <memory>
namespace app { namespace app {
@ -254,4 +259,42 @@ bool get_best_refcolor_for_trimming(
return true; return true;
} }
gfx::Rect get_trimmed_bounds(
const doc::Sprite* sprite,
const bool byGrid)
{
gfx::Rect bounds;
std::unique_ptr<Image> image_wrap(Image::create(sprite->spec()));
Image* image = image_wrap.get();
render::Render render;
for (frame_t frame(0); frame<sprite->totalFrames(); ++frame) {
render.renderSprite(image, sprite, frame);
gfx::Rect frameBounds;
doc::color_t refColor;
if (get_best_refcolor_for_trimming(image, refColor) &&
doc::algorithm::shrink_bounds(image, frameBounds, refColor)) {
bounds = bounds.createUnion(frameBounds);
}
// TODO merge this code with the code in DocExporter::captureSamples()
if (byGrid) {
const gfx::Rect& gridBounds = sprite->gridBounds();
gfx::Point posTopLeft =
snap_to_grid(gridBounds,
bounds.origin(),
PreferSnapTo::FloorGrid);
gfx::Point posBottomRight =
snap_to_grid(gridBounds,
bounds.point2(),
PreferSnapTo::CeilGrid);
bounds = gfx::Rect(posTopLeft, posBottomRight);
}
}
return bounds;
}
} // namespace app } // namespace app

View File

@ -10,9 +10,11 @@
#pragma once #pragma once
#include "doc/color.h" #include "doc/color.h"
#include "gfx/rect.h"
namespace doc { namespace doc {
class Image; class Image;
class Sprite;
} }
namespace app { namespace app {
@ -29,6 +31,10 @@ namespace app {
doc::Image* image, doc::Image* image,
doc::color_t& refColor); doc::color_t& refColor);
gfx::Rect get_trimmed_bounds(
const doc::Sprite* sprite,
const bool byGrid);
} // namespace app } // namespace app
#endif #endif