1// Aseprite
2// Copyright (C) 2018-2020 Igara Studio S.A.
3// Copyright (C) 2016-2018 David Capello
4//
5// This program is distributed under the terms of
6// the End-User License Agreement for Aseprite.
7
8#ifdef HAVE_CONFIG_H
9#include "config.h"
10#endif
11
12#include "app/cli/preview_cli_delegate.h"
13
14#include "app/cli/cli_open_file.h"
15#include "app/context.h"
16#include "app/doc.h"
17#include "app/doc_exporter.h"
18#include "app/file/file.h"
19#include "base/fs.h"
20#include "doc/layer.h"
21#include "doc/sprite.h"
22#include "fmt/format.h"
23#include "ver/info.h"
24
25#include <iostream>
26#include <memory>
27
28namespace app {
29
30void PreviewCliDelegate::showHelp(const AppOptions& options)
31{
32 std::cout << fmt::format("- Show {} CLI usage\n", get_app_name());
33}
34
35void PreviewCliDelegate::showVersion()
36{
37 std::cout << fmt::format("- Show {} version\n", get_app_name());
38}
39
40void PreviewCliDelegate::uiMode()
41{
42 std::cout << "- Run UI mode\n";
43}
44
45void PreviewCliDelegate::shellMode()
46{
47 std::cout << "- Run shell mode\n";
48}
49
50void PreviewCliDelegate::batchMode()
51{
52 std::cout << "- Exit\n";
53}
54
55void PreviewCliDelegate::beforeOpenFile(const CliOpenFile& cof)
56{
57 std::cout << "- Open file '" << cof.filename << "'\n";
58}
59
60void PreviewCliDelegate::afterOpenFile(const CliOpenFile& cof)
61{
62 if (!cof.document) {
63 std::cout << " - WARNING: File not found or error loading file\n";
64 return;
65 }
66
67 if (cof.listLayers)
68 std::cout << " - List layers\n";
69
70 if (cof.listTags)
71 std::cout << " - List tags\n";
72
73 if (cof.listSlices)
74 std::cout << " - List slices\n";
75
76 if (cof.oneFrame)
77 std::cout << " - One frame\n";
78
79 if (cof.allLayers)
80 std::cout << " - Make all layers visible\n";
81
82 showLayersFilter(cof);
83}
84
85void PreviewCliDelegate::saveFile(Context* ctx, const CliOpenFile& cof)
86{
87 ASSERT(cof.document);
88 ASSERT(cof.document->sprite());
89
90 std::cout << "- Save file '" << cof.filename << "'\n"
91 << " - Sprite: '" << cof.document->filename() << "'\n";
92
93 if (!cof.crop.isEmpty()) {
94 std::cout << " - Crop: "
95 << cof.crop.x << ","
96 << cof.crop.y << " "
97 << cof.crop.w << "x"
98 << cof.crop.h << "\n";
99 }
100
101 if (cof.trim) {
102 if (cof.trimByGrid)
103 std::cout << " - Trim by Grid\n";
104 else
105 std::cout << " - Trim\n";
106 }
107
108 if (cof.ignoreEmpty) {
109 std::cout << " - Ignore empty frames\n";
110 }
111
112 std::cout << " - Size: "
113 << cof.document->sprite()->width() << "x"
114 << cof.document->sprite()->height() << "\n";
115
116 showLayersFilter(cof);
117 std::cout << " - Visible Layer:\n";
118 showLayerVisibility(cof.document->sprite()->root(), " ");
119
120 if (cof.hasTag()) {
121 std::cout << " - Tag: '" << cof.tag << "'\n";
122 }
123
124 if (cof.hasSlice()) {
125 std::cout << " - Slice: '" << cof.slice << "'\n";
126 }
127
128 if (cof.hasFrameRange()) {
129 const auto& selFrames = cof.roi().selectedFrames();
130 if (!selFrames.empty()) {
131 if (selFrames.ranges() == 1)
132 std::cout << " - Frame range from "
133 << selFrames.firstFrame() << " to "
134 << selFrames.lastFrame() << "\n";
135 else {
136 std::cout << " - Specific frames:";
137 for (auto frame : selFrames)
138 std::cout << ' ' << frame;
139 std::cout << "\n";
140 }
141 }
142 }
143
144 if (!cof.filenameFormat.empty())
145 std::cout << " - Filename format: '" << cof.filenameFormat << "'\n";
146
147 std::unique_ptr<FileOp> fop(
148 FileOp::createSaveDocumentOperation(
149 ctx,
150 cof.roi(),
151 cof.filename,
152 cof.filenameFormat,
153 cof.ignoreEmpty));
154
155 if (fop) {
156 base::paths files;
157 fop->getFilenameList(files);
158 for (const auto& file : files) {
159 if (base::is_file(file))
160 std::cout << " - Overwrite file: '" << file << "'\n";
161 else
162 std::cout << " - Output file: '" << file << "'\n";
163 }
164 }
165 else
166 std::cout << " - No output\n";
167}
168
169void PreviewCliDelegate::loadPalette(Context* ctx,
170 const CliOpenFile& cof,
171 const std::string& filename)
172{
173 ASSERT(cof.document);
174 ASSERT(cof.document->sprite());
175
176 std::cout << "- Load palette:\n"
177 << " - Sprite: '" << cof.filename << "'\n"
178 << " - Palette: '" << filename << "'\n";
179}
180
181void PreviewCliDelegate::exportFiles(Context* ctx, DocExporter& exporter)
182{
183 std::string type = "None";
184 switch (exporter.spriteSheetType()) {
185 case SpriteSheetType::Horizontal: type = "Horizontal"; break;
186 case SpriteSheetType::Vertical: type = "Vertical"; break;
187 case SpriteSheetType::Rows: type = "Rows"; break;
188 case SpriteSheetType::Columns: type = "Columns"; break;
189 case SpriteSheetType::Packed: type = "Packed"; break;
190 }
191
192 gfx::Size size = exporter.calculateSheetSize();
193 std::cout << "- Export sprite sheet:\n"
194 << " - Type: " << type << "\n"
195 << " - Size: " << size.w << "x" << size.h << "\n";
196
197 if (!exporter.textureFilename().empty()) {
198 std::cout << " - Save texture file: '"
199 << exporter.textureFilename() << "'\n";
200 }
201
202 if (!exporter.dataFilename().empty()) {
203 std::string format = "Unknown";
204 switch (exporter.dataFormat()) {
205 case SpriteSheetDataFormat::JsonHash: format = "JSON Hash"; break;
206 case SpriteSheetDataFormat::JsonArray: format = "JSON Array"; break;
207 }
208 std::cout << " - Save data file: '" << exporter.dataFilename() << "'\n"
209 << " - Data format: " << format << "\n";
210
211 if (!exporter.filenameFormat().empty()) {
212 std::cout << " - Filename format for JSON items: '"
213 << exporter.filenameFormat() << "'\n";
214 }
215 }
216}
217
218#ifdef ENABLE_SCRIPTING
219int PreviewCliDelegate::execScript(const std::string& filename,
220 const Params& params)
221{
222 std::cout << "- Run script: '" << filename << "'\n";
223 if (!params.empty()) {
224 std::cout << " - With app.params = {\n";
225 for (const auto& kv : params)
226 std::cout << " " << kv.first << "=\"" << kv.second << "\",\n";
227 std::cout << " }\n";
228 }
229 return 0;
230}
231#endif // ENABLE_SCRIPTING
232
233void PreviewCliDelegate::showLayersFilter(const CliOpenFile& cof)
234{
235 if (!cof.includeLayers.empty()) {
236 std::cout << " - Include layers:";
237 for (const auto& filter : cof.includeLayers)
238 std::cout << ' ' << filter;
239 std::cout << "\n";
240 }
241
242 if (!cof.excludeLayers.empty()) {
243 std::cout << " - Exclude layers:";
244 for (const auto& filter : cof.excludeLayers)
245 std::cout << ' ' << filter;
246 std::cout << "\n";
247 }
248}
249
250void PreviewCliDelegate::showLayerVisibility(const doc::LayerGroup* group,
251 const std::string& indent)
252{
253 for (auto layer : group->layers()) {
254 if (!layer->isVisible())
255 continue;
256 std::cout << indent << "- " << layer->name() << "\n";
257 if (layer->isGroup())
258 showLayerVisibility(static_cast<const LayerGroup*>(layer),
259 indent + " ");
260 }
261}
262
263} // namespace app
264