mirror of
https://github.com/aseprite/aseprite.git
synced 2024-10-03 13:32:27 +00:00
Add "Trim Sprite" to DocExporter/Export Sprite Sheet/--trim-sprite CLI
This commit is contained in:
parent
f375ced883
commit
cd68a4fe0a
@ -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"))
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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());
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user