mirror of
https://github.com/aseprite/aseprite.git
synced 2025-01-26 03:35:23 +00:00
Merge branch '1.0'
Conflicts: src/app/commands/cmd_undo.cpp src/app/document_exporter.cpp src/app/document_exporter.h
This commit is contained in:
commit
0aedc7c74e
@ -1,5 +1,5 @@
|
||||
/* Aseprite
|
||||
* Copyright (C) 2001-2014 David Capello
|
||||
* Copyright (C) 2001-2015 David Capello
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -219,6 +219,7 @@ void App::initialize(const AppOptions& options)
|
||||
PRINTF("Processing options...\n");
|
||||
|
||||
bool ignoreEmpty = false;
|
||||
bool trim = false;
|
||||
|
||||
// Open file specified in the command line
|
||||
if (!options.values().empty()) {
|
||||
@ -273,6 +274,10 @@ void App::initialize(const AppOptions& options)
|
||||
else if (opt == &options.ignoreEmpty()) {
|
||||
ignoreEmpty = true;
|
||||
}
|
||||
// --trim
|
||||
else if (opt == &options.trim()) {
|
||||
trim = true;
|
||||
}
|
||||
// --filename-format
|
||||
else if (opt == &options.filenameFormat()) {
|
||||
filenameFormat = value.value();
|
||||
@ -291,7 +296,10 @@ void App::initialize(const AppOptions& options)
|
||||
|
||||
std::string format = filenameFormat;
|
||||
|
||||
Command* command = CommandsModule::instance()->getCommandByName(CommandId::SaveFileCopyAs);
|
||||
Command* saveAsCommand = CommandsModule::instance()->getCommandByName(CommandId::SaveFileCopyAs);
|
||||
Command* trimCommand = CommandsModule::instance()->getCommandByName(CommandId::AutocropSprite);
|
||||
Command* undoCommand = CommandsModule::instance()->getCommandByName(CommandId::Undo);
|
||||
|
||||
if (splitLayersSaveAs) {
|
||||
std::vector<Layer*> layers;
|
||||
doc->sprite()->getLayersList(layers);
|
||||
@ -314,10 +322,21 @@ void App::initialize(const AppOptions& options)
|
||||
fmt = filename_formatter(format,
|
||||
value.value(), show->name(), -1, false);
|
||||
|
||||
// TODO --trim command with --save-as doesn't make too
|
||||
// much sense as we lost the trim rectangle
|
||||
// information (e.g. we don't have sheet .json) Also,
|
||||
// we should trim each frame individually (a process
|
||||
// that can be done only in fop_operate()).
|
||||
if (trim)
|
||||
ctx->executeCommand(trimCommand);
|
||||
|
||||
Params params;
|
||||
params.set("filename", fn.c_str());
|
||||
params.set("filename-format", fmt.c_str());
|
||||
ctx->executeCommand(command, ¶ms);
|
||||
ctx->executeCommand(saveAsCommand, ¶ms);
|
||||
|
||||
if (trim) // Undo trim command
|
||||
ctx->executeCommand(undoCommand);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -330,10 +349,16 @@ void App::initialize(const AppOptions& options)
|
||||
layer->setVisible(layer->name() == importLayerSaveAs);
|
||||
}
|
||||
|
||||
if (trim)
|
||||
ctx->executeCommand(trimCommand);
|
||||
|
||||
Params params;
|
||||
params.set("filename", value.value().c_str());
|
||||
params.set("filename-format", format.c_str());
|
||||
ctx->executeCommand(command, ¶ms);
|
||||
ctx->executeCommand(saveAsCommand, ¶ms);
|
||||
|
||||
if (trim) // Undo trim command
|
||||
ctx->executeCommand(undoCommand);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -406,12 +431,15 @@ void App::initialize(const AppOptions& options)
|
||||
}
|
||||
|
||||
// Export
|
||||
if (m_exporter != NULL) {
|
||||
if (m_exporter) {
|
||||
PRINTF("Exporting sheet...\n");
|
||||
|
||||
if (ignoreEmpty)
|
||||
m_exporter->setIgnoreEmptyCels(true);
|
||||
|
||||
if (trim)
|
||||
m_exporter->setTrimCels(true);
|
||||
|
||||
m_exporter->exportSheet();
|
||||
m_exporter.reset(NULL);
|
||||
}
|
||||
|
@ -49,6 +49,7 @@ AppOptions::AppOptions(int argc, const char* argv[])
|
||||
, m_splitLayers(m_po.add("split-layers").description("Import each layer of the next given sprite as\na separated image in the sheet"))
|
||||
, m_importLayer(m_po.add("import-layer").requiresValue("<name>").description("Import just one layer of the next given sprite"))
|
||||
, m_ignoreEmpty(m_po.add("ignore-empty").description("Do not export empty frames/cels"))
|
||||
, m_trim(m_po.add("trim").description("Trim all images before exporting"))
|
||||
, m_filenameFormat(m_po.add("filename-format").requiresValue("<fmt>").description("Special format to generate filenames"))
|
||||
, m_verbose(m_po.add("verbose").description("Explain what is being done"))
|
||||
, m_help(m_po.add("help").mnemonic('?').description("Display this help and exits"))
|
||||
|
@ -57,6 +57,7 @@ public:
|
||||
const Option& splitLayers() const { return m_splitLayers; }
|
||||
const Option& importLayer() const { return m_importLayer; }
|
||||
const Option& ignoreEmpty() const { return m_ignoreEmpty; }
|
||||
const Option& trim() const { return m_trim; }
|
||||
const Option& filenameFormat() const { return m_filenameFormat; }
|
||||
|
||||
bool hasExporterParams() const;
|
||||
@ -85,6 +86,7 @@ private:
|
||||
Option& m_splitLayers;
|
||||
Option& m_importLayer;
|
||||
Option& m_ignoreEmpty;
|
||||
Option& m_trim;
|
||||
Option& m_filenameFormat;
|
||||
|
||||
Option& m_verbose;
|
||||
|
@ -105,8 +105,9 @@ void UndoCommand::onExecute(Context* context)
|
||||
}
|
||||
}
|
||||
|
||||
StatusBar::instance()
|
||||
->showTip(1000, "%s %s",
|
||||
StatusBar* statusbar = StatusBar::instance();
|
||||
if (statusbar)
|
||||
statusbar->showTip(1000, "%s %s",
|
||||
(m_type == Undo ? "Undid": "Redid"),
|
||||
(m_type == Undo ?
|
||||
undo->nextUndoLabel().c_str():
|
||||
|
@ -59,7 +59,10 @@ public:
|
||||
m_sprite(sprite),
|
||||
m_layer(layer),
|
||||
m_frame(frame),
|
||||
m_filename(filename) {
|
||||
m_filename(filename),
|
||||
m_originalSize(sprite->width(), sprite->height()),
|
||||
m_trimmedBounds(0, 0, sprite->width(), sprite->height()),
|
||||
m_inTextureBounds(0, 0, sprite->width(), sprite->height()) {
|
||||
}
|
||||
|
||||
Document* document() const { return m_document; }
|
||||
@ -128,37 +131,39 @@ public:
|
||||
const Layer* oldLayer = NULL;
|
||||
|
||||
gfx::Point framePt(0, 0);
|
||||
gfx::Size rowSize(0, 0);
|
||||
|
||||
for (auto& sample : samples) {
|
||||
const Sprite* sprite = sample.sprite();
|
||||
const Layer* layer = sample.layer();
|
||||
gfx::Size size(sprite->width(), sprite->height());
|
||||
gfx::Size size = sample.trimmedBounds().getSize();
|
||||
|
||||
if (oldSprite) {
|
||||
// If the user didn't specified a width for the texture, we put
|
||||
// each sprite/layer in a different row.
|
||||
if (width == 0) {
|
||||
// New sprite or layer, go to next row.
|
||||
if (oldSprite != sprite || oldLayer != layer) {
|
||||
framePt.x = 0;
|
||||
framePt.y += oldSprite->height(); // We're skipping the previous sprite height
|
||||
}
|
||||
}
|
||||
// When a texture width is specified, we can put different
|
||||
// sprites/layers in each row until we reach the texture
|
||||
// right-border.
|
||||
else if (framePt.x+size.w > width) {
|
||||
framePt.x = 0;
|
||||
framePt.y += oldSprite->height();
|
||||
// TODO framePt.y+size.h > height ?
|
||||
// If the user didn't specify a width for the texture, we put
|
||||
// each sprite/layer in a different row.
|
||||
if (width == 0) {
|
||||
// New sprite or layer, go to next row.
|
||||
if (oldSprite != sprite || oldLayer != layer) {
|
||||
framePt.x = 0;
|
||||
framePt.y += rowSize.h;
|
||||
rowSize = size;
|
||||
}
|
||||
}
|
||||
// When a texture width is specified, we can put different
|
||||
// sprites/layers in each row until we reach the texture
|
||||
// right-border.
|
||||
else if (framePt.x+size.w > width) {
|
||||
framePt.x = 0;
|
||||
framePt.y += rowSize.h;
|
||||
rowSize = size;
|
||||
}
|
||||
}
|
||||
|
||||
sample.setOriginalSize(size);
|
||||
sample.setTrimmedBounds(gfx::Rect(gfx::Point(0, 0), size));
|
||||
sample.setInTextureBounds(gfx::Rect(framePt, size));
|
||||
|
||||
// Next frame position.
|
||||
framePt.x += size.w;
|
||||
rowSize = rowSize.createUnion(size);
|
||||
|
||||
oldSprite = sprite;
|
||||
oldLayer = layer;
|
||||
@ -172,15 +177,8 @@ public:
|
||||
void layoutSamples(Samples& samples, int& width, int& height) override {
|
||||
gfx::PackingRects pr;
|
||||
|
||||
for (auto& sample : samples) {
|
||||
const Sprite* sprite = sample.sprite();
|
||||
gfx::Size size(sprite->width(), sprite->height());
|
||||
|
||||
sample.setOriginalSize(size);
|
||||
sample.setTrimmedBounds(gfx::Rect(gfx::Point(0, 0), size));
|
||||
|
||||
pr.add(size);
|
||||
}
|
||||
for (auto& sample : samples)
|
||||
pr.add(sample.trimmedBounds().getSize());
|
||||
|
||||
if (width == 0 || height == 0) {
|
||||
gfx::Size sz = pr.bestFit();
|
||||
@ -208,6 +206,7 @@ DocumentExporter::DocumentExporter()
|
||||
, m_scale(1.0)
|
||||
, m_scaleMode(DefaultScaleMode)
|
||||
, m_ignoreEmptyCels(false)
|
||||
, m_trimCels(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -266,7 +265,6 @@ void DocumentExporter::exportSheet()
|
||||
|
||||
void DocumentExporter::captureSamples(Samples& samples)
|
||||
{
|
||||
ImageBufferPtr checkEmptyImageBuf;
|
||||
std::vector<char> buf(32);
|
||||
|
||||
for (auto& item : m_documents) {
|
||||
@ -298,29 +296,38 @@ void DocumentExporter::captureSamples(Samples& samples)
|
||||
|
||||
Sample sample(doc, sprite, layer, frame, filename);
|
||||
|
||||
if (m_ignoreEmptyCels) {
|
||||
if (m_ignoreEmptyCels || m_trimCels) {
|
||||
if (layer && layer->isImage() && !layer->cel(frame)) {
|
||||
// Empty cel this sample completely
|
||||
continue;
|
||||
}
|
||||
|
||||
base::UniquePtr<Image> checkEmptyImage(
|
||||
base::UniquePtr<Image> sampleRender(
|
||||
Image::create(sprite->pixelFormat(),
|
||||
sprite->width(),
|
||||
sprite->height(),
|
||||
checkEmptyImageBuf));
|
||||
m_sampleRenderBuf));
|
||||
|
||||
checkEmptyImage->setMaskColor(sprite->transparentColor());
|
||||
clear_image(checkEmptyImage, sprite->transparentColor());
|
||||
renderSample(sample, checkEmptyImage, 0, 0);
|
||||
sampleRender->setMaskColor(sprite->transparentColor());
|
||||
clear_image(sampleRender, sprite->transparentColor());
|
||||
renderSample(sample, sampleRender);
|
||||
|
||||
gfx::Rect frameBounds;
|
||||
if (!algorithm::shrink_bounds(checkEmptyImage, frameBounds,
|
||||
sprite->transparentColor())) {
|
||||
doc::color_t refColor;
|
||||
|
||||
if (m_trimCels)
|
||||
refColor = get_pixel(sampleRender, 0, 0);
|
||||
else if (m_ignoreEmptyCels)
|
||||
refColor = sprite->transparentColor();
|
||||
|
||||
if (!algorithm::shrink_bounds(sampleRender, frameBounds, refColor)) {
|
||||
// If shrink_bounds returns false, it's because the whole
|
||||
// image is transparent (equal to the mask color).
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m_trimCels)
|
||||
sample.setTrimmedBounds(frameBounds);
|
||||
}
|
||||
|
||||
samples.addSample(sample);
|
||||
@ -385,10 +392,7 @@ void DocumentExporter::renderTexture(const Samples& samples, Image* textureImage
|
||||
DitheringMethod::NONE).execute(UIContext::instance());
|
||||
}
|
||||
|
||||
int x = sample.inTextureBounds().x - sample.trimmedBounds().x;
|
||||
int y = sample.inTextureBounds().y - sample.trimmedBounds().y;
|
||||
|
||||
renderSample(sample, textureImage, x, y);
|
||||
renderSample(sample, textureImage);
|
||||
}
|
||||
}
|
||||
|
||||
@ -443,17 +447,18 @@ void DocumentExporter::createDataFile(const Samples& samples, std::ostream& os,
|
||||
<< "}\n";
|
||||
}
|
||||
|
||||
void DocumentExporter::renderSample(const Sample& sample, doc::Image* dst, int x, int y)
|
||||
void DocumentExporter::renderSample(const Sample& sample, doc::Image* dst)
|
||||
{
|
||||
render::Render render;
|
||||
gfx::Clip clip(
|
||||
sample.inTextureBounds().x,
|
||||
sample.inTextureBounds().y, sample.trimmedBounds());
|
||||
|
||||
if (sample.layer()) {
|
||||
render.renderLayer(dst, sample.layer(), sample.frame(),
|
||||
gfx::Clip(x, y, sample.sprite()->bounds()));
|
||||
render.renderLayer(dst, sample.layer(), sample.frame(), clip);
|
||||
}
|
||||
else {
|
||||
render.renderSprite(dst, sample.sprite(), sample.frame(),
|
||||
gfx::Clip(x, y, sample.sprite()->bounds()));
|
||||
render.renderSprite(dst, sample.sprite(), sample.frame(), clip);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* Aseprite
|
||||
* Copyright (C) 2001-2014 David Capello
|
||||
* Copyright (C) 2001-2015 David Capello
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -21,11 +21,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "base/disable_copying.h"
|
||||
#include "doc/image_buffer.h"
|
||||
#include "gfx/fwd.h"
|
||||
|
||||
#include <iosfwd>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace doc {
|
||||
class Image;
|
||||
@ -93,6 +94,10 @@ namespace app {
|
||||
m_ignoreEmptyCels = ignore;
|
||||
}
|
||||
|
||||
void setTrimCels(bool trim) {
|
||||
m_trimCels = trim;
|
||||
}
|
||||
|
||||
void setFilenameFormat(const std::string& format) {
|
||||
m_filenameFormat = format;
|
||||
}
|
||||
@ -114,7 +119,7 @@ namespace app {
|
||||
Document* createEmptyTexture(const Samples& samples);
|
||||
void renderTexture(const Samples& samples, doc::Image* textureImage);
|
||||
void createDataFile(const Samples& samples, std::ostream& os, doc::Image* textureImage);
|
||||
void renderSample(const Sample& sample, doc::Image* dst, int x, int y);
|
||||
void renderSample(const Sample& sample, doc::Image* dst);
|
||||
|
||||
class Item {
|
||||
public:
|
||||
@ -136,8 +141,10 @@ namespace app {
|
||||
double m_scale;
|
||||
ScaleMode m_scaleMode;
|
||||
bool m_ignoreEmptyCels;
|
||||
bool m_trimCels;
|
||||
Items m_documents;
|
||||
std::string m_filenameFormat;
|
||||
doc::ImageBufferPtr m_sampleRenderBuf;
|
||||
|
||||
DISABLE_COPYING(DocumentExporter);
|
||||
};
|
||||
|
@ -86,11 +86,11 @@ namespace app {
|
||||
double progress; // Progress (1.0 is ready).
|
||||
IFileOpProgress* progressInterface;
|
||||
std::string error; // Error string.
|
||||
bool done : 1; // True if the operation finished.
|
||||
bool stop : 1; // Force the break of the operation.
|
||||
bool oneframe : 1; // Load just one frame (in formats
|
||||
// that support animation like
|
||||
// GIF/FLI/ASE).
|
||||
bool done; // True if the operation finished.
|
||||
bool stop; // Force the break of the operation.
|
||||
bool oneframe; // Load just one frame (in formats
|
||||
// that support animation like
|
||||
// GIF/FLI/ASE).
|
||||
|
||||
// Data for sequences.
|
||||
struct {
|
||||
|
@ -386,12 +386,14 @@ bool UISettingsImpl::getAutoSelectLayer()
|
||||
|
||||
app::Color UISettingsImpl::getFgColor()
|
||||
{
|
||||
return ColorBar::instance()->getFgColor();
|
||||
ColorBar* colorbar = ColorBar::instance();
|
||||
return colorbar ? colorbar->getFgColor(): app::Color::fromMask();
|
||||
}
|
||||
|
||||
app::Color UISettingsImpl::getBgColor()
|
||||
{
|
||||
return ColorBar::instance()->getBgColor();
|
||||
ColorBar* colorbar = ColorBar::instance();
|
||||
return colorbar ? colorbar->getBgColor(): app::Color::fromMask();
|
||||
}
|
||||
|
||||
tools::Tool* UISettingsImpl::getCurrentTool()
|
||||
|
Loading…
x
Reference in New Issue
Block a user