[aseprite] 40/134: Add more command line options to export or convert sprites
Tobias Hansen
thansen at moszumanska.debian.org
Sat Mar 14 17:10:01 UTC 2015
This is an automated email from the git hooks/post-receive script.
thansen pushed a commit to branch master
in repository aseprite.
commit ce962f4999e4b52dace5a4d263c96c2fbbf17e45
Author: David Capello <davidcapello at gmail.com>
Date: Thu Nov 6 21:04:32 2014 -0300
Add more command line options to export or convert sprites
Added --save-as, --scale, --split-layers, and --import-layer command line
options.
---
src/app/app.cpp | 190 +++++++++++++++++++++++++----------
src/app/app_menus.cpp | 5 +-
src/app/app_options.cpp | 59 +++++------
src/app/app_options.h | 52 +++++-----
src/app/commands/cmd_save_file.cpp | 2 +-
src/app/commands/cmd_save_file.h | 4 +
src/app/commands/cmd_sprite_size.cpp | 161 ++++++++++++++++-------------
src/app/commands/cmd_sprite_size.h | 72 +++++++++++++
src/app/document_exporter.cpp | 95 +++++++++++-------
src/app/document_exporter.h | 20 +++-
src/app/job.cpp | 47 +++++----
src/app/job.h | 2 +-
src/app/modules/gui.cpp | 3 +-
src/app/ui_context.cpp | 15 ++-
src/base/program_options.cpp | 4 +-
src/doc/documents.h | 1 +
16 files changed, 483 insertions(+), 249 deletions(-)
diff --git a/src/app/app.cpp b/src/app/app.cpp
index 009a7f3..bfc9a8f 100644
--- a/src/app/app.cpp
+++ b/src/app/app.cpp
@@ -1,5 +1,5 @@
/* Aseprite
- * Copyright (C) 2001-2013 David Capello
+ * Copyright (C) 2001-2014 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
@@ -25,6 +25,8 @@
#include "app/app_options.h"
#include "app/check_update.h"
#include "app/color_utils.h"
+#include "app/commands/cmd_save_file.h"
+#include "app/commands/cmd_sprite_size.h"
#include "app/commands/commands.h"
#include "app/commands/params.h"
#include "app/console.h"
@@ -133,14 +135,9 @@ void App::initialize(int argc, const char* argv[])
m_isShell = options.startShell();
m_legacy = new LegacyModules(isGui() ? REQUIRE_INTERFACE: 0);
- if (options.hasExporterParams()) {
+ if (options.hasExporterParams())
m_exporter.reset(new DocumentExporter);
- m_exporter->setDataFilename(options.data());
- m_exporter->setTextureFilename(options.sheet());
- m_exporter->setScale(options.scale());
- }
-
// Register well-known image file types.
FileFormatsManager::instance()->registerAllFormats();
@@ -181,14 +178,14 @@ void App::initialize(int argc, const char* argv[])
set_current_palette(NULL, true);
// Initialize GUI interface
- UIContext* context = UIContext::instance();
+ UIContext* ctx = UIContext::instance();
if (isGui()) {
PRINTF("GUI mode\n");
// Setup the GUI cursor and redraw screen
ui::set_use_native_cursors(
- context->settings()->experimental()->useNativeCursor());
+ ctx->settings()->experimental()->useNativeCursor());
jmouse_set_cursor(kArrowCursor);
@@ -214,30 +211,111 @@ void App::initialize(int argc, const char* argv[])
PRINTF("Processing options...\n");
// Open file specified in the command line
- {
+ if (!options.values().empty()) {
Console console;
- for (const auto& value : options.values()) {
- if (value.option() != NULL) // File names aren't associated to any option
- continue;
+ bool splitLayers = false;
+ std::string importLayer;
- const std::string& filename = value.value();
-
- // Load the sprite
- Document* document = load_document(context, filename.c_str());
- if (!document) {
- if (!isGui())
- console.printf("Error loading file \"%s\"\n", filename.c_str());
+ for (const auto& value : options.values()) {
+ const AppOptions::Option* opt = value.option();
+
+ // Special options/commands
+ if (opt) {
+ // --data <file.json>
+ if (opt == &options.data()) {
+ if (m_exporter)
+ m_exporter->setDataFilename(value.value());
+ }
+ // --sheet <file.png>
+ else if (opt == &options.sheet()) {
+ if (m_exporter)
+ m_exporter->setTextureFilename(value.value());
+ }
+ // --split-layers
+ else if (opt == &options.splitLayers()) {
+ splitLayers = true;
+ }
+ // --import-layer <layer-name>
+ else if (opt == &options.importLayer()) {
+ importLayer = value.value();
+ }
+ // --save-as <filename>
+ else if (opt == &options.saveAs()) {
+ Document* doc = NULL;
+ if (!ctx->documents().empty())
+ doc = dynamic_cast<Document*>(ctx->documents().lastAdded());
+
+ if (!doc) {
+ console.printf("A document is needed before --save-as argument\n");
+ }
+ else {
+ ctx->setActiveDocument(doc);
+
+ Command* command = CommandsModule::instance()->getCommandByName(CommandId::SaveFileCopyAs);
+ static_cast<SaveFileBaseCommand*>(command)->setFilename(value.value());
+ ctx->executeCommand(command);
+ }
+ }
+ // --scale <factor>
+ else if (opt == &options.scale()) {
+ Command* command = CommandsModule::instance()->getCommandByName(CommandId::SpriteSize);
+ double scale = strtod(value.value().c_str(), NULL);
+ static_cast<SpriteSizeCommand*>(command)->setScale(scale, scale);
+
+ // Scale all sprites
+ for (auto doc : ctx->documents()) {
+ ctx->setActiveDocument(doc);
+ ctx->executeCommand(command);
+ }
+ }
}
+ // File names aren't associated to any option
else {
- // Add the given file in the argument as a "recent file" only
- // if we are running in GUI mode. If the program is executed
- // in batch mode this is not desirable.
- if (isGui())
- getRecentFiles()->addRecentFile(filename.c_str());
-
- // Add the document to the exporter.
- if (m_exporter != NULL)
- m_exporter->addDocument(document);
+ const std::string& filename = value.value();
+
+ // Load the sprite
+ Document* doc = load_document(ctx, filename.c_str());
+ if (!doc) {
+ if (!isGui())
+ console.printf("Error loading file \"%s\"\n", filename.c_str());
+ }
+ else {
+ // Add the given file in the argument as a "recent file" only
+ // if we are running in GUI mode. If the program is executed
+ // in batch mode this is not desirable.
+ if (isGui())
+ getRecentFiles()->addRecentFile(filename.c_str());
+
+ if (m_exporter != NULL) {
+ if (!importLayer.empty()) {
+ std::vector<Layer*> layers;
+ Layer* foundLayer = NULL;
+ doc->sprite()->getLayersList(layers);
+ for (Layer* layer : layers) {
+ if (layer->name() == importLayer) {
+ foundLayer = layer;
+ break;
+ }
+ }
+ if (foundLayer)
+ m_exporter->addDocument(doc, foundLayer);
+ }
+ else if (splitLayers) {
+ std::vector<Layer*> layers;
+ doc->sprite()->getLayersList(layers);
+ for (auto layer : layers)
+ m_exporter->addDocument(doc, layer);
+ }
+ else
+ m_exporter->addDocument(doc);
+ }
+ }
+
+ if (!importLayer.empty())
+ importLayer.clear();
+
+ if (splitLayers)
+ splitLayers = false;
}
}
}
@@ -272,32 +350,10 @@ void App::run()
// Run the GUI main message loop
gui_run();
-
- // Destroy all documents in the UIContext.
- const doc::Documents& docs = m_modules->m_ui_context.documents();
- while (!docs.empty()) {
- doc::Document* doc = docs.back();
-
- // First we close the document. In this way we receive recent
- // notifications related to the document as an app::Document. If
- // we delete the document directly, we destroy the app::Document
- // too early, and then doc::~Document() call
- // DocumentsObserver::onRemoveDocument(). In this way, observers
- // could think that they have a fully created app::Document when
- // in reality it's a doc::Document (in the middle of a
- // destruction process).
- //
- // TODO: This problem is because we're extending doc::Document,
- // in the future, we should remove app::Document.
- doc->close();
- delete doc;
- }
-
- // Destroy the window.
- m_mainWindow.reset(NULL);
}
+
// Start shell to execute scripts.
- else if (m_isShell) {
+ if (m_isShell) {
m_systemConsole.prepareShell();
if (m_modules->m_scriptingEngine.supportEval()) {
@@ -308,6 +364,31 @@ void App::run()
std::cerr << "Your version of " PACKAGE " wasn't compiled with shell support.\n";
}
}
+
+ // Destroy all documents in the UIContext.
+ const doc::Documents& docs = m_modules->m_ui_context.documents();
+ while (!docs.empty()) {
+ doc::Document* doc = docs.back();
+
+ // First we close the document. In this way we receive recent
+ // notifications related to the document as an app::Document. If
+ // we delete the document directly, we destroy the app::Document
+ // too early, and then doc::~Document() call
+ // DocumentsObserver::onRemoveDocument(). In this way, observers
+ // could think that they have a fully created app::Document when
+ // in reality it's a doc::Document (in the middle of a
+ // destruction process).
+ //
+ // TODO: This problem is because we're extending doc::Document,
+ // in the future, we should remove app::Document.
+ doc->close();
+ delete doc;
+ }
+
+ if (isGui()) {
+ // Destroy the window.
+ m_mainWindow.reset(NULL);
+ }
}
// Finishes the Aseprite application.
@@ -410,7 +491,8 @@ void app_refresh_screen()
void app_rebuild_documents_tabs()
{
- App::instance()->getMainWindow()->getTabsBar()->updateTabsText();
+ if (App::instance()->isGui())
+ App::instance()->getMainWindow()->getTabsBar()->updateTabsText();
}
PixelFormat app_get_current_pixel_format()
diff --git a/src/app/app_menus.cpp b/src/app/app_menus.cpp
index 66cd5ef..6e1f32c 100644
--- a/src/app/app_menus.cpp
+++ b/src/app/app_menus.cpp
@@ -287,9 +287,10 @@ void AppMenus::applyShortcutToMenuitemsWithCommand(Menu* menu, Command* command,
Widget* child = *it;
if (child->getType() == kMenuItemWidget) {
- ASSERT(dynamic_cast<AppMenuItem*>(child) != NULL);
+ AppMenuItem* menuitem = dynamic_cast<AppMenuItem*>(child);
+ if (!menuitem)
+ continue;
- AppMenuItem* menuitem = static_cast<AppMenuItem*>(child);
Command* mi_command = menuitem->getCommand();
Params* mi_params = menuitem->getParams();
diff --git a/src/app/app_options.cpp b/src/app/app_options.cpp
index fb4e744..4f47f71 100644
--- a/src/app/app_options.cpp
+++ b/src/app/app_options.cpp
@@ -1,5 +1,5 @@
/* Aseprite
- * Copyright (C) 2001-2013 David Capello
+ * Copyright (C) 2001-2014 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
@@ -35,49 +35,37 @@ AppOptions::AppOptions(int argc, const char* argv[])
: m_exeName(base::get_file_name(argv[0]))
, m_startUI(true)
, m_startShell(false)
- , m_verbose(false)
- , m_scale(1.0)
+ , m_verboseEnabled(false)
+ , m_palette(m_po.add("palette").requiresValue("<filename>").description("Use a specific palette by default"))
+ , m_shell(m_po.add("shell").description("Start an interactive console to execute scripts"))
+ , m_batch(m_po.add("batch").description("Do not start the UI"))
+ , m_saveAs(m_po.add("save-as").requiresValue("<filename>").description("Save the last give document with other name/format"))
+ , m_scale(m_po.add("scale").requiresValue("<factor>").description("Scale all opened documents at the moment"))
+ , m_data(m_po.add("data").requiresValue("<filename.json>").description("File to store the sprite sheet metadata"))
+ , m_sheet(m_po.add("sheet").requiresValue("<filename.png>").description("Image file to save the texture"))
+ , m_splitLayers(m_po.add("split-layers").description("Import each layer of the next given sprite as\n a 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_verbose(m_po.add("verbose").description("Explain what is being done (in stderr or log file)"))
+ , m_help(m_po.add("help").mnemonic('?').description("Display this help and exits"))
+ , m_version(m_po.add("version").description("Output version information and exit"))
{
- Option& palette = m_po.add("palette").requiresValue("<filename>").description("Use a specific palette by default");
- Option& shell = m_po.add("shell").description("Start an interactive console to execute scripts");
- Option& batch = m_po.add("batch").description("Do not start the UI");
- // Option& dataFormat = m_po.add("format").requiresValue("<name>").description("Select the format for the sprite sheet data");
- Option& data = m_po.add("data").requiresValue("<filename>").description("File to store the sprite sheet metadata (.json file)");
- //Option& textureFormat = m_po.add("texture-format").requiresValue("<name>").description("Output texture format.");
- Option& sheet = m_po.add("sheet").requiresValue("<filename>").description("Image file to save the texture (.png)");
- //Option& scale = m_po.add("scale").requiresValue("<float>").description("");
- //Option& scaleMode = m_po.add("scale-mode").requiresValue("<mode>").description("Export the first given document to a JSON object");
- //Option& splitLayers = m_po.add("split-layers").description("Specifies that each layer of the given file should be saved as a different image in the sheet.");
- //Option& rotsprite = m_po.add("rotsprite").requiresValue("<angle1,angle2,...>").description("Specifies different angles to export the given image.");
- //Option& merge = m_po.add("merge").requiresValue("<datafiles>").description("Merge several sprite sheets in one.");
- Option& verbose = m_po.add("verbose").description("Explain what is being done (in stderr or a log file)");
- Option& help = m_po.add("help").mnemonic('?').description("Display this help and exits");
- Option& version = m_po.add("version").description("Output version information and exit");
-
try {
m_po.parse(argc, argv);
- m_verbose = m_po.enabled(verbose);
- m_paletteFileName = m_po.value_of(palette);
- m_startShell = m_po.enabled(shell);
- // m_dataFormat = m_po.value_of(dataFormat);
- m_data = m_po.value_of(data);
- // m_textureFormat = m_po.value_of(textureFormat);
- m_sheet = m_po.value_of(sheet);
- // if (scale.enabled())
- // m_scale = std::strtod(m_po.value_of(scale).c_str(), NULL);
- // m_scaleMode = m_po.value_of(scaleMode);
+ m_verboseEnabled = m_po.enabled(m_verbose);
+ m_paletteFileName = m_po.value_of(m_palette);
+ m_startShell = m_po.enabled(m_shell);
- if (m_po.enabled(help)) {
+ if (m_po.enabled(m_help)) {
showHelp();
m_startUI = false;
}
- else if (m_po.enabled(version)) {
+ else if (m_po.enabled(m_version)) {
showVersion();
m_startUI = false;
}
- if (m_po.enabled(shell) || m_po.enabled(batch)) {
+ if (m_po.enabled(m_shell) || m_po.enabled(m_batch)) {
m_startUI = false;
}
}
@@ -88,6 +76,13 @@ AppOptions::AppOptions(int argc, const char* argv[])
}
}
+bool AppOptions::hasExporterParams() const
+{
+ return
+ m_po.enabled(m_data) ||
+ m_po.enabled(m_sheet);
+}
+
void AppOptions::showHelp()
{
std::cout
diff --git a/src/app/app_options.h b/src/app/app_options.h
index 045869f..dc7523a 100644
--- a/src/app/app_options.h
+++ b/src/app/app_options.h
@@ -30,33 +30,31 @@ namespace app {
class AppOptions {
public:
+ typedef base::ProgramOptions PO;
+ typedef PO::Option Option;
+ typedef PO::ValueList ValueList;
+
AppOptions(int argc, const char* argv[]);
bool startUI() const { return m_startUI; }
bool startShell() const { return m_startShell; }
- bool verbose() const { return m_verbose; }
+ bool verbose() const { return m_verboseEnabled; }
const std::string& paletteFileName() const { return m_paletteFileName; }
- const base::ProgramOptions::ValueList& values() const {
+ const ValueList& values() const {
return m_po.values();
}
// Export options
- const std::string& dataFormat() const { return m_dataFormat; }
- const std::string& data() const { return m_data; }
- const std::string& textureFormat() const { return m_textureFormat; }
- const std::string& sheet() const { return m_sheet; }
- const double scale() const { return m_scale; }
- const std::string& scaleMode() const { return m_scaleMode; }
-
- bool hasExporterParams() {
- return
- !m_dataFormat.empty() ||
- !m_data.empty() ||
- !m_textureFormat.empty() ||
- !m_sheet.empty();
- }
+ const Option& saveAs() const { return m_saveAs; }
+ const Option& scale() const { return m_scale; }
+ const Option& data() const { return m_data; }
+ const Option& sheet() const { return m_sheet; }
+ const Option& splitLayers() const { return m_splitLayers; }
+ const Option& importLayer() const { return m_importLayer; }
+
+ bool hasExporterParams() const;
private:
void showHelp();
@@ -66,15 +64,23 @@ private:
base::ProgramOptions m_po;
bool m_startUI;
bool m_startShell;
- bool m_verbose;
+ bool m_verboseEnabled;
std::string m_paletteFileName;
- std::string m_dataFormat;
- std::string m_data;
- std::string m_textureFormat;
- std::string m_sheet;
- double m_scale;
- std::string m_scaleMode;
+ Option& m_palette;
+ Option& m_shell;
+ Option& m_batch;
+ Option& m_saveAs;
+ Option& m_scale;
+ Option& m_data;
+ Option& m_sheet;
+ Option& m_splitLayers;
+ Option& m_importLayer;
+
+ Option& m_verbose;
+ Option& m_help;
+ Option& m_version;
+
};
} // namespace app
diff --git a/src/app/commands/cmd_save_file.cpp b/src/app/commands/cmd_save_file.cpp
index 7d8320e..0defd78 100644
--- a/src/app/commands/cmd_save_file.cpp
+++ b/src/app/commands/cmd_save_file.cpp
@@ -100,7 +100,7 @@ static void save_document_in_background(Context* context, Document* document, bo
else if (fop_is_stop(fop)) {
document->impossibleToBackToSavedState();
}
- else {
+ else if (context->isUiAvailable()) {
App::instance()->getRecentFiles()->addRecentFile(document->filename().c_str());
if (mark_as_saved)
document->markAsSaved();
diff --git a/src/app/commands/cmd_save_file.h b/src/app/commands/cmd_save_file.h
index 8affee5..f400979 100644
--- a/src/app/commands/cmd_save_file.h
+++ b/src/app/commands/cmd_save_file.h
@@ -35,6 +35,10 @@ namespace app {
return m_selectedFilename;
}
+ void setFilename(const std::string& fn) {
+ m_filename = fn;
+ }
+
protected:
void onLoadParams(Params* params) override;
bool onEnabled(Context* context) override;
diff --git a/src/app/commands/cmd_sprite_size.cpp b/src/app/commands/cmd_sprite_size.cpp
index ab642e6..99cee9f 100644
--- a/src/app/commands/cmd_sprite_size.cpp
+++ b/src/app/commands/cmd_sprite_size.cpp
@@ -20,7 +20,9 @@
#include "config.h"
#endif
+#include "app/commands/cmd_sprite_size.h"
#include "app/commands/command.h"
+#include "app/commands/params.h"
#include "app/context_access.h"
#include "app/document_api.h"
#include "app/find_widget.h"
@@ -159,34 +161,48 @@ protected:
};
-class SpriteSizeCommand : public Command {
-public:
- SpriteSizeCommand();
- Command* clone() const override { return new SpriteSizeCommand(*this); }
-
-protected:
- bool onEnabled(Context* context);
- void onExecute(Context* context);
-
-private:
- void onLockRatioClick();
- void onWidthPxChange();
- void onHeightPxChange();
- void onWidthPercChange();
- void onHeightPercChange();
-
- CheckBox* m_lockRatio;
- Entry* m_widthPx;
- Entry* m_heightPx;
- Entry* m_widthPerc;
- Entry* m_heightPerc;
-};
-
SpriteSizeCommand::SpriteSizeCommand()
: Command("SpriteSize",
"Sprite Size",
CmdRecordableFlag)
{
+ m_width = 0;
+ m_height = 0;
+ m_scaleX = 1.0;
+ m_scaleY = 1.0;
+ m_resizeMethod = raster::algorithm::RESIZE_METHOD_NEAREST_NEIGHBOR;
+}
+
+Command* SpriteSizeCommand::clone() const
+{
+ return new SpriteSizeCommand(*this);
+}
+
+void SpriteSizeCommand::onLoadParams(Params* params)
+{
+ std::string width = params->get("width");
+ if (!width.empty()) {
+ m_width = std::strtol(width.c_str(), NULL, 10);
+ }
+ else
+ m_width = 0;
+
+ std::string height = params->get("height");
+ if (!height.empty()) {
+ m_height = std::strtol(height.c_str(), NULL, 10);
+ }
+ else
+ m_height = 0;
+
+ std::string resize_method = params->get("resize-method");
+ if (!resize_method.empty()) {
+ if (resize_method == "bilinear")
+ m_resizeMethod = raster::algorithm::RESIZE_METHOD_BILINEAR;
+ else
+ m_resizeMethod = raster::algorithm::RESIZE_METHOD_NEAREST_NEIGHBOR;
+ }
+ else
+ m_resizeMethod = raster::algorithm::RESIZE_METHOD_NEAREST_NEIGHBOR;
}
bool SpriteSizeCommand::onEnabled(Context* context)
@@ -197,58 +213,63 @@ bool SpriteSizeCommand::onEnabled(Context* context)
void SpriteSizeCommand::onExecute(Context* context)
{
- const ContextReader reader(UIContext::instance()); // TODO use the context in sprite size command
+ const ContextReader reader(context);
const Sprite* sprite(reader.sprite());
-
- // load the window widget
- base::UniquePtr<Window> window(app::load_widget<Window>("sprite_size.xml", "sprite_size"));
- m_widthPx = app::find_widget<Entry>(window, "width_px");
- m_heightPx = app::find_widget<Entry>(window, "height_px");
- m_widthPerc = app::find_widget<Entry>(window, "width_perc");
- m_heightPerc = app::find_widget<Entry>(window, "height_perc");
- m_lockRatio = app::find_widget<CheckBox>(window, "lock_ratio");
- ComboBox* method = app::find_widget<ComboBox>(window, "method");
- Widget* ok = app::find_widget<Widget>(window, "ok");
-
- m_widthPx->setTextf("%d", sprite->width());
- m_heightPx->setTextf("%d", sprite->height());
-
- m_lockRatio->Click.connect(Bind<void>(&SpriteSizeCommand::onLockRatioClick, this));
- m_widthPx->EntryChange.connect(Bind<void>(&SpriteSizeCommand::onWidthPxChange, this));
- m_heightPx->EntryChange.connect(Bind<void>(&SpriteSizeCommand::onHeightPxChange, this));
- m_widthPerc->EntryChange.connect(Bind<void>(&SpriteSizeCommand::onWidthPercChange, this));
- m_heightPerc->EntryChange.connect(Bind<void>(&SpriteSizeCommand::onHeightPercChange, this));
-
- method->addItem("Nearest-neighbor");
- method->addItem("Bilinear");
- method->setSelectedItemIndex(get_config_int("SpriteSize", "Method",
- raster::algorithm::RESIZE_METHOD_NEAREST_NEIGHBOR));
-
- window->remapWindow();
- window->centerWindow();
-
- load_window_pos(window, "SpriteSize");
- window->setVisible(true);
- window->openWindowInForeground();
- save_window_pos(window, "SpriteSize");
-
- if (window->getKiller() == ok) {
- int new_width = m_widthPx->getTextInt();
- int new_height = m_heightPx->getTextInt();
- ResizeMethod resize_method =
- (ResizeMethod)method->getSelectedItemIndex();
+ int new_width = (m_width ? m_width: sprite->width()*m_scaleX);
+ int new_height = (m_height ? m_height: sprite->height()*m_scaleY);
+ ResizeMethod resize_method = m_resizeMethod;
+
+ if (context->isUiAvailable()) {
+ // load the window widget
+ base::UniquePtr<Window> window(app::load_widget<Window>("sprite_size.xml", "sprite_size"));
+ m_widthPx = app::find_widget<Entry>(window, "width_px");
+ m_heightPx = app::find_widget<Entry>(window, "height_px");
+ m_widthPerc = app::find_widget<Entry>(window, "width_perc");
+ m_heightPerc = app::find_widget<Entry>(window, "height_perc");
+ m_lockRatio = app::find_widget<CheckBox>(window, "lock_ratio");
+ ComboBox* method = app::find_widget<ComboBox>(window, "method");
+ Widget* ok = app::find_widget<Widget>(window, "ok");
+
+ m_widthPx->setTextf("%d", new_width);
+ m_heightPx->setTextf("%d", new_height);
+
+ m_lockRatio->Click.connect(Bind<void>(&SpriteSizeCommand::onLockRatioClick, this));
+ m_widthPx->EntryChange.connect(Bind<void>(&SpriteSizeCommand::onWidthPxChange, this));
+ m_heightPx->EntryChange.connect(Bind<void>(&SpriteSizeCommand::onHeightPxChange, this));
+ m_widthPerc->EntryChange.connect(Bind<void>(&SpriteSizeCommand::onWidthPercChange, this));
+ m_heightPerc->EntryChange.connect(Bind<void>(&SpriteSizeCommand::onHeightPercChange, this));
+
+ method->addItem("Nearest-neighbor");
+ method->addItem("Bilinear");
+ method->setSelectedItemIndex(get_config_int("SpriteSize", "Method",
+ raster::algorithm::RESIZE_METHOD_NEAREST_NEIGHBOR));
+
+ window->remapWindow();
+ window->centerWindow();
+
+ load_window_pos(window, "SpriteSize");
+ window->setVisible(true);
+ window->openWindowInForeground();
+ save_window_pos(window, "SpriteSize");
+
+ if (window->getKiller() != ok)
+ return;
+
+ new_width = m_widthPx->getTextInt();
+ new_height = m_heightPx->getTextInt();
+ resize_method = (ResizeMethod)method->getSelectedItemIndex();
set_config_int("SpriteSize", "Method", resize_method);
+ }
- {
- SpriteSizeJob job(reader, new_width, new_height, resize_method);
- job.startJob();
- job.waitJob();
- }
-
- ContextWriter writer(reader);
- update_screen_for_document(writer.document());
+ {
+ SpriteSizeJob job(reader, new_width, new_height, resize_method);
+ job.startJob();
+ job.waitJob();
}
+
+ ContextWriter writer(reader);
+ update_screen_for_document(writer.document());
}
void SpriteSizeCommand::onLockRatioClick()
diff --git a/src/app/commands/cmd_sprite_size.h b/src/app/commands/cmd_sprite_size.h
new file mode 100644
index 0000000..11887c6
--- /dev/null
+++ b/src/app/commands/cmd_sprite_size.h
@@ -0,0 +1,72 @@
+/* Aseprite
+ * Copyright (C) 2001-2014 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef APP_COMMANDS_CMD_SPRITE_SIZE_H_INCLUDED
+#define APP_COMMANDS_CMD_SPRITE_SIZE_H_INCLUDED
+#pragma once
+
+#include "app/commands/command.h"
+#include "raster/algorithm/resize_image.h"
+
+#include <string>
+
+namespace ui {
+ class CheckBox;
+ class Entry;
+}
+
+namespace app {
+
+ class SpriteSizeCommand : public Command {
+ public:
+ SpriteSizeCommand();
+ Command* clone() const override;
+
+ void setScale(double x, double y) {
+ m_scaleX = x;
+ m_scaleY = y;
+ }
+
+ protected:
+ virtual void onLoadParams(Params* params) override;
+ virtual bool onEnabled(Context* context) override;
+ virtual void onExecute(Context* context) override;
+
+ private:
+ void onLockRatioClick();
+ void onWidthPxChange();
+ void onHeightPxChange();
+ void onWidthPercChange();
+ void onHeightPercChange();
+
+ ui::CheckBox* m_lockRatio;
+ ui::Entry* m_widthPx;
+ ui::Entry* m_heightPx;
+ ui::Entry* m_widthPerc;
+ ui::Entry* m_heightPerc;
+
+ int m_width;
+ int m_height;
+ double m_scaleX;
+ double m_scaleY;
+ raster::algorithm::ResizeMethod m_resizeMethod;
+ };
+
+} // namespace app
+
+#endif
diff --git a/src/app/document_exporter.cpp b/src/app/document_exporter.cpp
index e5c4626..0034748 100644
--- a/src/app/document_exporter.cpp
+++ b/src/app/document_exporter.cpp
@@ -35,6 +35,7 @@
#include "raster/image.h"
#include "raster/layer.h"
#include "raster/palette.h"
+#include "raster/primitives.h"
#include "raster/sprite.h"
#include "raster/stock.h"
@@ -48,16 +49,18 @@ namespace app {
class DocumentExporter::Sample {
public:
- Sample(Document* document, Sprite* sprite,
+ Sample(Document* document, Sprite* sprite, Layer* layer,
FrameNumber frame, const std::string& filename) :
m_document(document),
m_sprite(sprite),
+ m_layer(layer),
m_frame(frame),
m_filename(filename) {
}
Document* document() const { return m_document; }
Sprite* sprite() const { return m_sprite; }
+ Layer* layer() const { return m_layer; }
FrameNumber frame() const { return m_frame; }
std::string filename() const { return m_filename; }
const gfx::Size& originalSize() const { return m_originalSize; }
@@ -78,6 +81,7 @@ public:
private:
Document* m_document;
Sprite* m_sprite;
+ Layer* m_layer;
FrameNumber m_frame;
std::string m_filename;
gfx::Size m_originalSize;
@@ -117,27 +121,29 @@ class DocumentExporter::SimpleLayoutSamples :
public:
void layoutSamples(Samples& samples) override {
const Sprite* oldSprite = NULL;
+ const Layer* oldLayer = NULL;
gfx::Point framePt(0, 0);
- for (Samples::iterator it=samples.begin(), end=samples.end();
- it != end; ++it) {
- const Sprite* sprite = it->sprite();
+ for (auto& sample : samples) {
+ const Sprite* sprite = sample.sprite();
+ const Layer* layer = sample.layer();
gfx::Size size(sprite->width(), sprite->height());
- it->setOriginalSize(size);
- it->setTrimmedBounds(gfx::Rect(gfx::Point(0, 0), size));
- it->setInTextureBounds(gfx::Rect(framePt, size));
-
- // All frames of each sprite in one row.
- if (oldSprite != NULL && oldSprite != it->sprite()) {
+ // New sprite or layer, go to next row.
+ if (oldSprite && (oldSprite != sprite || oldLayer != layer)) {
framePt.x = 0;
framePt.y += size.h;
}
- else {
- framePt.x += size.w;
- }
- oldSprite = it->sprite();
+ 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;
+
+ oldSprite = sprite;
+ oldLayer = layer;
}
}
};
@@ -174,7 +180,8 @@ void DocumentExporter::exportSheet()
createEmptyTexture(samples));
Sprite* texture = textureDocument->sprite();
- Image* textureImage = static_cast<LayerImage*>(texture->folder()->getFirstLayer())
+ Image* textureImage = static_cast<LayerImage*>(
+ texture->folder()->getFirstLayer())
->getCel(FrameNumber(0))->image();
renderTexture(samples, textureImage);
@@ -193,15 +200,14 @@ void DocumentExporter::captureSamples(Samples& samples)
{
std::vector<char> buf(32);
- for (std::vector<Document*>::iterator
- it = m_documents.begin(),
- end = m_documents.end(); it != end; ++it) {
- Document* document = *it;
- Sprite* sprite = document->sprite();
-
+ for (auto& item : m_documents) {
+ Document* doc = item.doc;
+ Sprite* sprite = doc->sprite();
+ Layer* layer = item.layer;
+
for (FrameNumber frame=FrameNumber(0);
frame<sprite->totalFrames(); ++frame) {
- std::string filename = document->filename();
+ std::string filename = doc->filename();
if (sprite->totalFrames() > FrameNumber(1)) {
int frameNumWidth =
@@ -212,11 +218,16 @@ void DocumentExporter::captureSamples(Samples& samples)
std::string path = base::get_file_path(filename);
std::string title = base::get_file_title(filename);
+ if (layer) {
+ title += "-";
+ title += layer->name();
+ }
+
std::string ext = base::get_file_extension(filename);
filename = base::join_path(path, title + &buf[0] + "." + ext);
}
- samples.addSample(Sample(document, sprite, frame, filename));
+ samples.addSample(Sample(doc, sprite, layer, frame, filename));
}
}
}
@@ -268,21 +279,26 @@ void DocumentExporter::renderTexture(const Samples& samples, Image* textureImage
{
textureImage->clear(0);
- for (Samples::const_iterator
- it = samples.begin(),
- end = samples.end(); it != end; ++it) {
+ for (const auto& sample : samples) {
// Make the sprite compatible with the texture so the render()
// works correctly.
- if (it->sprite()->pixelFormat() != textureImage->pixelFormat()) {
- DocumentApi docApi(it->document(), NULL); // DocumentApi without undo
- docApi.setPixelFormat(it->sprite(), textureImage->pixelFormat(),
+ if (sample.sprite()->pixelFormat() != textureImage->pixelFormat()) {
+ DocumentApi docApi(sample.document(), NULL); // DocumentApi without undo
+ docApi.setPixelFormat(
+ sample.sprite(),
+ textureImage->pixelFormat(),
DITHERING_NONE);
}
- it->sprite()->render(textureImage,
- it->inTextureBounds().x - it->trimmedBounds().x,
- it->inTextureBounds().y - it->trimmedBounds().y,
- it->frame());
+ int x = sample.inTextureBounds().x - sample.trimmedBounds().x;
+ int y = sample.inTextureBounds().y - sample.trimmedBounds().y;
+
+ if (sample.layer()) {
+ layer_render(sample.layer(), textureImage, x, y, sample.frame());
+ }
+ else {
+ sample.sprite()->render(textureImage, x, y, sample.frame());
+ }
}
}
@@ -292,18 +308,19 @@ void DocumentExporter::createDataFile(const Samples& samples, std::ostream& os,
for (Samples::const_iterator
it = samples.begin(),
end = samples.end(); it != end; ) {
- gfx::Size srcSize = it->originalSize();
- gfx::Rect spriteSourceBounds = it->trimmedBounds();
- gfx::Rect frameBounds = it->inTextureBounds();
+ const Sample& sample = *it;
+ gfx::Size srcSize = sample.originalSize();
+ gfx::Rect spriteSourceBounds = sample.trimmedBounds();
+ gfx::Rect frameBounds = sample.inTextureBounds();
- os << " \"" << it->filename() << "\": {\n"
+ os << " \"" << sample.filename() << "\": {\n"
<< " \"frame\": { "
<< "\"x\": " << frameBounds.x << ", "
<< "\"y\": " << frameBounds.y << ", "
<< "\"w\": " << frameBounds.w << ", "
<< "\"h\": " << frameBounds.h << " },\n"
<< " \"rotated\": false,\n"
- << " \"trimmed\": " << (it->trimmed() ? "true": "false") << ",\n"
+ << " \"trimmed\": " << (sample.trimmed() ? "true": "false") << ",\n"
<< " \"spriteSourceSize\": { "
<< "\"x\": " << spriteSourceBounds.x << ", "
<< "\"y\": " << spriteSourceBounds.y << ", "
@@ -312,7 +329,7 @@ void DocumentExporter::createDataFile(const Samples& samples, std::ostream& os,
<< " \"sourceSize\": { "
<< "\"w\": " << srcSize.w << ", "
<< "\"h\": " << srcSize.h << " },\n"
- << " \"duration\": " << it->sprite()->getFrameDuration(it->frame()) << "\n"
+ << " \"duration\": " << sample.sprite()->getFrameDuration(sample.frame()) << "\n"
<< " }";
if (++it != samples.end())
diff --git a/src/app/document_exporter.h b/src/app/document_exporter.h
index 434478c..df7e097 100644
--- a/src/app/document_exporter.h
+++ b/src/app/document_exporter.h
@@ -29,6 +29,7 @@
namespace raster {
class Image;
+ class Layer;
}
namespace app {
@@ -53,7 +54,8 @@ namespace app {
DocumentExporter() :
m_dataFormat(DefaultDataFormat),
m_textureFormat(DefaultTextureFormat),
- m_scaleMode(DefaultScaleMode) {
+ m_scaleMode(DefaultScaleMode),
+ m_scale(1.0) {
}
void setDataFormat(DataFormat format) {
@@ -80,8 +82,8 @@ namespace app {
m_scaleMode = mode;
}
- void addDocument(Document* document) {
- m_documents.push_back(document);
+ void addDocument(Document* document, raster::Layer* layer = NULL) {
+ m_documents.push_back(Item(document, layer));
}
void exportSheet();
@@ -97,13 +99,23 @@ namespace app {
void renderTexture(const Samples& samples, raster::Image* textureImage);
void createDataFile(const Samples& samples, std::ostream& os, raster::Image* textureImage);
+ class Item {
+ public:
+ Document* doc;
+ raster::Layer* layer;
+ Item(Document* doc, raster::Layer* layer)
+ : doc(doc), layer(layer) {
+ }
+ };
+ typedef std::vector<Item> Items;
+
DataFormat m_dataFormat;
std::string m_dataFilename;
TextureFormat m_textureFormat;
std::string m_textureFilename;
double m_scale;
ScaleMode m_scaleMode;
- std::vector<Document*> m_documents;
+ Items m_documents;
DISABLE_COPYING(DocumentExporter);
};
diff --git a/src/app/job.cpp b/src/app/job.cpp
index 1ea0472..51640c7 100644
--- a/src/app/job.cpp
+++ b/src/app/job.cpp
@@ -22,6 +22,7 @@
#include "app/job.h"
+#include "app/app.h"
#include "app/ui/status_bar.h"
#include "base/mutex.h"
#include "base/scoped_lock.h"
@@ -34,7 +35,7 @@ static const int kMonitoringPeriod = 100;
namespace app {
-Job::Job(const char* job_name)
+Job::Job(const char* jobName)
{
m_mutex = NULL;
m_thread = NULL;
@@ -44,24 +45,29 @@ Job::Job(const char* job_name)
m_canceled_flag = false;
m_mutex = new base::mutex();
- m_progress = StatusBar::instance()->addProgress();
- m_alert_window = ui::Alert::create("%s<<Working...||&Cancel", job_name);
- m_timer.reset(new ui::Timer(kMonitoringPeriod, m_alert_window));
- m_timer->Tick.connect(&Job::onMonitoringTick, this);
- m_timer->start();
+ if (App::instance()->isGui()) {
+ m_progress = StatusBar::instance()->addProgress();
+ m_alert_window = ui::Alert::create("%s<<Working...||&Cancel", jobName);
+
+ m_timer.reset(new ui::Timer(kMonitoringPeriod, m_alert_window));
+ m_timer->Tick.connect(&Job::onMonitoringTick, this);
+ m_timer->start();
+ }
}
Job::~Job()
{
- ASSERT(!m_timer->isRunning());
- ASSERT(m_thread == NULL);
+ if (App::instance()->isGui()) {
+ ASSERT(!m_timer->isRunning());
+ ASSERT(m_thread == NULL);
- if (m_alert_window != NULL)
- m_alert_window->closeWindow(NULL);
+ if (m_alert_window != NULL)
+ m_alert_window->closeWindow(NULL);
- if (m_progress)
- delete m_progress;
+ if (m_progress)
+ delete m_progress;
+ }
if (m_mutex)
delete m_mutex;
@@ -70,19 +76,22 @@ Job::~Job()
void Job::startJob()
{
m_thread = new base::thread(&Job::thread_proc, this);
- m_alert_window->openWindowInForeground();
- // The job was canceled by the user?
- {
- base::scoped_lock hold(*m_mutex);
- if (!m_done_flag)
- m_canceled_flag = true;
+ if (m_alert_window) {
+ m_alert_window->openWindowInForeground();
+
+ // The job was canceled by the user?
+ {
+ base::scoped_lock hold(*m_mutex);
+ if (!m_done_flag)
+ m_canceled_flag = true;
+ }
}
}
void Job::waitJob()
{
- if (m_timer->isRunning())
+ if (m_timer && m_timer->isRunning())
m_timer->stop();
if (m_thread) {
diff --git a/src/app/job.h b/src/app/job.h
index 61fac80..a1067dc 100644
--- a/src/app/job.h
+++ b/src/app/job.h
@@ -34,7 +34,7 @@ namespace app {
class Job {
public:
- Job(const char* job_name);
+ Job(const char* jobName);
virtual ~Job();
// Starts the job calling onJob() event in another thread and
diff --git a/src/app/modules/gui.cpp b/src/app/modules/gui.cpp
index d307d07..f6617f9 100644
--- a/src/app/modules/gui.cpp
+++ b/src/app/modules/gui.cpp
@@ -228,7 +228,8 @@ void update_screen_for_document(Document* document)
// Well, change to the default palette.
if (set_current_palette(NULL, false)) {
// If the palette changes, refresh the whole screen.
- Manager::getDefault()->invalidate();
+ if (Manager::getDefault())
+ Manager::getDefault()->invalidate();
}
}
// With a document.
diff --git a/src/app/ui_context.cpp b/src/app/ui_context.cpp
index ba6cf86..13c46cd 100644
--- a/src/app/ui_context.cpp
+++ b/src/app/ui_context.cpp
@@ -22,6 +22,7 @@
#include "app/app.h"
#include "app/document.h"
+#include "app/document_location.h"
#include "app/modules/editors.h"
#include "app/settings/ui_settings_impl.h"
#include "app/ui/color_bar.h"
@@ -167,6 +168,10 @@ void UIContext::onRemoveDocument(doc::Document* doc)
{
Context::onRemoveDocument(doc);
+ // We don't destroy views in batch mode.
+ if (!isUiAvailable())
+ return;
+
Workspace* workspace = App::instance()->getMainWindow()->getWorkspace();
DocumentViews docViews;
@@ -190,8 +195,16 @@ void UIContext::onRemoveDocument(doc::Document* doc)
void UIContext::onGetActiveLocation(DocumentLocation* location) const
{
DocumentView* view = activeView();
- if (view)
+ if (view) {
view->getDocumentLocation(location);
+ }
+ // Default/dummy location (maybe for batch/command line mode)
+ else if (Document* doc = activeDocument()) {
+ location->document(doc);
+ location->sprite(doc->sprite());
+ location->layer(doc->sprite()->indexToLayer(LayerIndex(0)));
+ location->frame(FrameNumber(0));
+ }
}
} // namespace app
diff --git a/src/base/program_options.cpp b/src/base/program_options.cpp
index 1ef589a..addc4d7 100644
--- a/src/base/program_options.cpp
+++ b/src/base/program_options.cpp
@@ -192,8 +192,8 @@ std::ostream& operator<<(std::ostream& os, const base::ProgramOptions& po)
it=po.options().begin(), end=po.options().end(); it != end; ++it) {
const base::ProgramOptions::Option* option = *it;
size_t optionWidth =
- std::min<int>(26, 6+option->name().size()+1+
- (option->doesRequireValue() ? option->getValueName().size()+1: 0));
+ 6+option->name().size()+1+
+ (option->doesRequireValue() ? option->getValueName().size()+1: 0);
if (maxOptionWidth < optionWidth)
maxOptionWidth = optionWidth;
diff --git a/src/doc/documents.h b/src/doc/documents.h
index 248f8cd..f589dd7 100644
--- a/src/doc/documents.h
+++ b/src/doc/documents.h
@@ -35,6 +35,7 @@ namespace doc {
Document* front() const { return m_docs.front(); }
Document* back() const { return m_docs.back(); }
+ Document* lastAdded() const { return front(); }
int size() const { return m_docs.size(); }
bool empty() const { return m_docs.empty(); }
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-games/aseprite.git
More information about the Pkg-games-commits
mailing list