2015-02-12 12:16:25 -03:00
|
|
|
// Aseprite
|
2016-03-17 10:31:33 -03:00
|
|
|
// Copyright (C) 2001-2016 David Capello
|
2015-02-12 12:16:25 -03:00
|
|
|
//
|
2016-08-26 17:02:58 -03:00
|
|
|
// This program is distributed under the terms of
|
|
|
|
// the End-User License Agreement for Aseprite.
|
2007-09-18 23:57:02 +00:00
|
|
|
|
2013-08-05 21:20:19 -03:00
|
|
|
#ifdef HAVE_CONFIG_H
|
2007-09-18 23:57:02 +00:00
|
|
|
#include "config.h"
|
2013-08-05 21:20:19 -03:00
|
|
|
#endif
|
2007-09-18 23:57:02 +00:00
|
|
|
|
2013-10-14 19:58:11 -03:00
|
|
|
#include "app/file/file.h"
|
|
|
|
|
2013-08-05 21:20:19 -03:00
|
|
|
#include "app/console.h"
|
2014-07-19 22:01:39 -03:00
|
|
|
#include "app/context.h"
|
2013-08-05 21:20:19 -03:00
|
|
|
#include "app/document.h"
|
|
|
|
#include "app/file/file_format.h"
|
|
|
|
#include "app/file/file_formats_manager.h"
|
|
|
|
#include "app/file/format_options.h"
|
2014-09-21 13:42:46 -03:00
|
|
|
#include "app/file/split_filename.h"
|
2015-01-25 22:36:32 -03:00
|
|
|
#include "app/filename_formatter.h"
|
2013-08-05 21:20:19 -03:00
|
|
|
#include "app/modules/gui.h"
|
|
|
|
#include "app/modules/palettes.h"
|
2013-10-14 19:58:11 -03:00
|
|
|
#include "app/ui/status_bar.h"
|
|
|
|
#include "base/fs.h"
|
|
|
|
#include "base/mutex.h"
|
|
|
|
#include "base/path.h"
|
|
|
|
#include "base/scoped_lock.h"
|
|
|
|
#include "base/shared_ptr.h"
|
|
|
|
#include "base/string.h"
|
2014-10-20 22:21:31 -03:00
|
|
|
#include "doc/doc.h"
|
2014-12-28 11:06:11 -03:00
|
|
|
#include "render/quantization.h"
|
|
|
|
#include "render/render.h"
|
2012-06-17 22:49:58 -03:00
|
|
|
#include "ui/alert.h"
|
2007-09-18 23:57:02 +00:00
|
|
|
|
2013-10-14 19:58:11 -03:00
|
|
|
#include <cstring>
|
2015-02-12 10:55:58 -03:00
|
|
|
#include <cstdarg>
|
2011-03-22 21:11:25 -03:00
|
|
|
|
2013-08-05 21:20:19 -03:00
|
|
|
namespace app {
|
|
|
|
|
|
|
|
using namespace base;
|
|
|
|
|
2015-03-17 17:17:01 -03:00
|
|
|
std::string get_readable_extensions()
|
2007-09-18 23:57:02 +00:00
|
|
|
{
|
2015-03-17 17:17:01 -03:00
|
|
|
std::string buf;
|
2007-09-18 23:57:02 +00:00
|
|
|
|
2015-03-17 17:17:01 -03:00
|
|
|
for (const FileFormat* format : *FileFormatsManager::instance()) {
|
|
|
|
if (format->support(FILE_SUPPORT_LOAD)) {
|
|
|
|
if (!buf.empty())
|
|
|
|
buf.push_back(',');
|
|
|
|
buf += format->extensions();
|
2011-01-16 17:27:18 -03:00
|
|
|
}
|
2007-09-18 23:57:02 +00:00
|
|
|
}
|
2015-03-17 17:17:01 -03:00
|
|
|
|
|
|
|
return buf;
|
2007-09-18 23:57:02 +00:00
|
|
|
}
|
|
|
|
|
2015-03-17 17:17:01 -03:00
|
|
|
std::string get_writable_extensions()
|
2007-09-18 23:57:02 +00:00
|
|
|
{
|
2015-03-17 17:17:01 -03:00
|
|
|
std::string buf;
|
2007-09-18 23:57:02 +00:00
|
|
|
|
2015-03-17 17:17:01 -03:00
|
|
|
for (const FileFormat* format : *FileFormatsManager::instance()) {
|
|
|
|
if (format->support(FILE_SUPPORT_SAVE)) {
|
|
|
|
if (!buf.empty())
|
|
|
|
buf.push_back(',');
|
|
|
|
buf += format->extensions();
|
2011-01-16 17:27:18 -03:00
|
|
|
}
|
2007-09-18 23:57:02 +00:00
|
|
|
}
|
2015-03-17 17:17:01 -03:00
|
|
|
|
|
|
|
return buf;
|
2007-09-18 23:57:02 +00:00
|
|
|
}
|
|
|
|
|
2014-07-19 22:01:39 -03:00
|
|
|
Document* load_document(Context* context, const char* filename)
|
2007-09-18 23:57:02 +00:00
|
|
|
{
|
2008-02-10 19:06:03 +00:00
|
|
|
/* TODO add a option to configure what to do with the sequence */
|
2015-09-29 11:27:00 -03:00
|
|
|
base::UniquePtr<FileOp> fop(FileOp::createLoadDocumentOperation(context, filename, FILE_LOAD_SEQUENCE_NONE));
|
2008-02-04 02:37:26 +00:00
|
|
|
if (!fop)
|
2015-09-29 11:27:00 -03:00
|
|
|
return nullptr;
|
2008-02-04 02:37:26 +00:00
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
// Operate in this same thread
|
|
|
|
fop->operate();
|
|
|
|
fop->done();
|
|
|
|
fop->postLoad();
|
2008-02-04 02:37:26 +00:00
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
if (fop->hasError()) {
|
2015-04-06 11:58:42 -03:00
|
|
|
Console console(context);
|
2015-09-29 11:27:00 -03:00
|
|
|
console.printf(fop->error().c_str());
|
2009-06-11 15:11:11 +00:00
|
|
|
}
|
2008-02-04 02:37:26 +00:00
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
Document* document = fop->releaseDocument();
|
|
|
|
fop.release();
|
2008-02-04 02:37:26 +00:00
|
|
|
|
2014-08-22 09:46:25 -03:00
|
|
|
if (document && context)
|
2014-07-29 00:53:24 -03:00
|
|
|
document->setContext(context);
|
|
|
|
|
2011-03-22 21:11:25 -03:00
|
|
|
return document;
|
2008-02-04 02:37:26 +00:00
|
|
|
}
|
|
|
|
|
2014-07-29 00:53:24 -03:00
|
|
|
int save_document(Context* context, doc::Document* document)
|
2008-02-04 02:37:26 +00:00
|
|
|
{
|
2014-07-29 00:53:24 -03:00
|
|
|
ASSERT(dynamic_cast<app::Document*>(document));
|
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
UniquePtr<FileOp> fop(
|
|
|
|
FileOp::createSaveDocumentOperation(
|
|
|
|
context,
|
|
|
|
static_cast<app::Document*>(document),
|
|
|
|
document->filename().c_str(), ""));
|
2008-02-04 02:37:26 +00:00
|
|
|
if (!fop)
|
|
|
|
return -1;
|
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
// Operate in this same thread
|
|
|
|
fop->operate();
|
|
|
|
fop->done();
|
2008-02-04 02:37:26 +00:00
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
if (fop->hasError()) {
|
2015-04-06 11:58:42 -03:00
|
|
|
Console console(context);
|
2015-09-29 11:27:00 -03:00
|
|
|
console.printf(fop->error().c_str());
|
2009-06-11 15:11:11 +00:00
|
|
|
}
|
2008-02-04 02:37:26 +00:00
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
return (!fop->hasError() ? 0: -1);
|
2008-02-04 02:37:26 +00:00
|
|
|
}
|
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
// static
|
|
|
|
FileOp* FileOp::createLoadDocumentOperation(Context* context, const char* filename, int flags)
|
2008-02-04 02:37:26 +00:00
|
|
|
{
|
2015-09-29 11:27:00 -03:00
|
|
|
base::UniquePtr<FileOp> fop(
|
|
|
|
new FileOp(FileOpLoad, context));
|
2008-02-04 02:37:26 +00:00
|
|
|
if (!fop)
|
2015-09-29 11:27:00 -03:00
|
|
|
return nullptr;
|
2008-02-04 02:37:26 +00:00
|
|
|
|
2013-10-14 19:58:11 -03:00
|
|
|
// Get the extension of the filename (in lower case)
|
2014-04-20 19:53:27 -03:00
|
|
|
std::string extension = base::string_to_lower(base::get_file_extension(filename));
|
2007-09-18 23:57:02 +00:00
|
|
|
|
2015-08-28 20:48:49 -03:00
|
|
|
LOG("Loading file \"%s\" (%s)\n", filename, extension.c_str());
|
2007-09-18 23:57:02 +00:00
|
|
|
|
2013-10-14 19:58:11 -03:00
|
|
|
// Does file exist?
|
2014-04-17 17:12:55 -03:00
|
|
|
if (!base::is_file(filename)) {
|
2015-09-29 11:27:00 -03:00
|
|
|
fop->setError("File not found: \"%s\"\n", filename);
|
2008-02-04 02:37:26 +00:00
|
|
|
goto done;
|
2007-09-18 23:57:02 +00:00
|
|
|
}
|
|
|
|
|
2014-08-21 23:39:20 -03:00
|
|
|
// Get the format through the extension of the filename
|
2015-09-29 11:27:00 -03:00
|
|
|
fop->m_format = FileFormatsManager::instance()
|
2014-08-21 23:39:20 -03:00
|
|
|
->getFileFormatByExtension(extension.c_str());
|
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
if (!fop->m_format ||
|
|
|
|
!fop->m_format->support(FILE_SUPPORT_LOAD)) {
|
2015-12-22 17:55:35 -03:00
|
|
|
fop->setError("%s can't load \"%s\" files\n", PACKAGE, extension.c_str());
|
2008-02-04 02:37:26 +00:00
|
|
|
goto done;
|
|
|
|
}
|
2007-09-18 23:57:02 +00:00
|
|
|
|
|
|
|
/* use the "sequence" interface */
|
2015-09-29 11:27:00 -03:00
|
|
|
if (fop->m_format->support(FILE_SUPPORT_SEQUENCES)) {
|
2008-02-10 19:06:03 +00:00
|
|
|
/* prepare to load a sequence */
|
2015-09-29 11:27:00 -03:00
|
|
|
fop->prepareForSequence();
|
2007-09-18 23:57:02 +00:00
|
|
|
|
|
|
|
/* per now, we want load just one file */
|
2015-09-29 11:27:00 -03:00
|
|
|
fop->m_seq.filename_list.push_back(filename);
|
2007-09-18 23:57:02 +00:00
|
|
|
|
2008-02-10 19:06:03 +00:00
|
|
|
/* don't load the sequence (just the one file/one frame) */
|
|
|
|
if (!(flags & FILE_LOAD_SEQUENCE_NONE)) {
|
2014-09-21 13:42:46 -03:00
|
|
|
std::string left, right;
|
2008-02-10 19:06:03 +00:00
|
|
|
int c, width, start_from;
|
2014-09-21 13:42:46 -03:00
|
|
|
char buf[512];
|
2008-02-10 19:06:03 +00:00
|
|
|
|
|
|
|
/* first of all, we must generate the list of files to load in the
|
2012-01-05 19:45:03 -03:00
|
|
|
sequence... */
|
2008-02-10 19:06:03 +00:00
|
|
|
|
2014-09-21 13:42:46 -03:00
|
|
|
// Check is this could be a sequence
|
|
|
|
start_from = split_filename(filename, left, right, width);
|
2008-02-10 19:06:03 +00:00
|
|
|
if (start_from >= 0) {
|
2014-09-21 13:42:46 -03:00
|
|
|
// Try to get more file names
|
2012-01-05 19:45:03 -03:00
|
|
|
for (c=start_from+1; ; c++) {
|
2014-09-21 13:42:46 -03:00
|
|
|
// Get the next file name
|
|
|
|
sprintf(buf, "%s%0*d%s", left.c_str(), width, c, right.c_str());
|
2012-01-05 19:45:03 -03:00
|
|
|
|
2014-09-21 13:42:46 -03:00
|
|
|
// If the file doesn't exist, we doesn't need more files to load
|
|
|
|
if (!base::is_file(buf))
|
2012-01-05 19:45:03 -03:00
|
|
|
break;
|
|
|
|
|
|
|
|
/* add this file name to the list */
|
2015-09-29 11:27:00 -03:00
|
|
|
fop->m_seq.filename_list.push_back(buf);
|
2012-01-05 19:45:03 -03:00
|
|
|
}
|
2007-09-18 23:57:02 +00:00
|
|
|
}
|
|
|
|
|
2008-02-10 19:06:03 +00:00
|
|
|
/* TODO add a better dialog to edit file-names */
|
2015-05-18 17:04:31 -03:00
|
|
|
if ((flags & FILE_LOAD_SEQUENCE_ASK) && context && context->isUIAvailable()) {
|
2012-01-05 19:45:03 -03:00
|
|
|
/* really want load all files? */
|
2015-09-29 11:27:00 -03:00
|
|
|
if ((fop->m_seq.filename_list.size() > 1) &&
|
2012-06-17 22:02:54 -03:00
|
|
|
(ui::Alert::show("Notice"
|
2014-09-21 13:42:46 -03:00
|
|
|
"<<Possible animation with:"
|
|
|
|
"<<%s, %s..."
|
|
|
|
"<<Do you want to load the sequence of bitmaps?"
|
|
|
|
"||&Agree||&Skip",
|
2015-09-29 11:27:00 -03:00
|
|
|
base::get_file_name(fop->m_seq.filename_list[0]).c_str(),
|
|
|
|
base::get_file_name(fop->m_seq.filename_list[1]).c_str()) != 1)) {
|
2014-09-21 13:42:46 -03:00
|
|
|
|
|
|
|
// If the user replies "Skip", we need just one file name
|
|
|
|
// (the first one).
|
2015-09-29 11:27:00 -03:00
|
|
|
if (fop->m_seq.filename_list.size() > 1) {
|
|
|
|
fop->m_seq.filename_list.erase(fop->m_seq.filename_list.begin()+1,
|
|
|
|
fop->m_seq.filename_list.end());
|
2012-01-05 19:45:03 -03:00
|
|
|
}
|
|
|
|
}
|
2007-09-18 23:57:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-02-04 02:37:26 +00:00
|
|
|
else
|
2015-09-29 11:27:00 -03:00
|
|
|
fop->m_filename = filename;
|
2007-09-18 23:57:02 +00:00
|
|
|
|
2008-02-10 19:06:03 +00:00
|
|
|
/* load just one frame */
|
|
|
|
if (flags & FILE_LOAD_ONE_FRAME)
|
2015-09-29 11:27:00 -03:00
|
|
|
fop->m_oneframe = true;
|
2008-02-10 19:06:03 +00:00
|
|
|
|
2008-02-04 02:37:26 +00:00
|
|
|
done:;
|
2015-09-29 11:27:00 -03:00
|
|
|
return fop.release();
|
2007-09-18 23:57:02 +00:00
|
|
|
}
|
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
// static
|
|
|
|
FileOp* FileOp::createSaveDocumentOperation(const Context* context,
|
|
|
|
const Document* document,
|
|
|
|
const char* filename,
|
|
|
|
const char* fn_format_arg)
|
2007-09-18 23:57:02 +00:00
|
|
|
{
|
2015-09-29 11:27:00 -03:00
|
|
|
base::UniquePtr<FileOp> fop(
|
|
|
|
new FileOp(FileOpSave, const_cast<Context*>(context)));
|
2008-02-04 02:37:26 +00:00
|
|
|
|
2013-10-14 19:58:11 -03:00
|
|
|
// Document to save
|
2015-09-29 11:27:00 -03:00
|
|
|
fop->m_document = const_cast<Document*>(document);
|
2008-02-04 02:37:26 +00:00
|
|
|
|
2013-10-14 19:58:11 -03:00
|
|
|
// Get the extension of the filename (in lower case)
|
2015-04-06 12:01:08 -03:00
|
|
|
std::string extension = base::string_to_lower(base::get_file_extension(filename));
|
2007-09-18 23:57:02 +00:00
|
|
|
|
2015-08-28 20:48:49 -03:00
|
|
|
LOG("Saving document \"%s\" (%s)\n", filename, extension.c_str());
|
2007-09-18 23:57:02 +00:00
|
|
|
|
2014-08-21 23:39:20 -03:00
|
|
|
// Get the format through the extension of the filename
|
2015-09-29 11:27:00 -03:00
|
|
|
fop->m_format = FileFormatsManager::instance()
|
2014-08-21 23:39:20 -03:00
|
|
|
->getFileFormatByExtension(extension.c_str());
|
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
if (!fop->m_format ||
|
|
|
|
!fop->m_format->support(FILE_SUPPORT_SAVE)) {
|
2015-12-22 17:55:35 -03:00
|
|
|
fop->setError("%s can't save \"%s\" files\n", PACKAGE, extension.c_str());
|
2015-09-29 11:27:00 -03:00
|
|
|
return fop.release();
|
2007-09-18 23:57:02 +00:00
|
|
|
}
|
|
|
|
|
2013-10-14 19:58:11 -03:00
|
|
|
// Warnings
|
2014-04-20 19:53:27 -03:00
|
|
|
std::string warnings;
|
2015-09-29 11:27:00 -03:00
|
|
|
bool fatal = false;
|
2007-09-18 23:57:02 +00:00
|
|
|
|
2016-07-05 11:44:58 -03:00
|
|
|
// Check image type support
|
|
|
|
// TODO add support to automatically convert the image to a supported format
|
2015-09-29 11:27:00 -03:00
|
|
|
switch (fop->m_document->sprite()->pixelFormat()) {
|
2007-09-18 23:57:02 +00:00
|
|
|
|
|
|
|
case IMAGE_RGB:
|
2015-09-29 11:27:00 -03:00
|
|
|
if (!(fop->m_format->support(FILE_SUPPORT_RGB))) {
|
2013-10-14 19:58:11 -03:00
|
|
|
warnings += "<<- RGB format";
|
2012-01-05 19:45:03 -03:00
|
|
|
fatal = true;
|
2007-09-18 23:57:02 +00:00
|
|
|
}
|
2013-10-14 19:58:11 -03:00
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
if (!(fop->m_format->support(FILE_SUPPORT_RGBA)) &&
|
|
|
|
fop->m_document->sprite()->needAlpha()) {
|
2013-10-14 19:58:11 -03:00
|
|
|
|
|
|
|
warnings += "<<- Alpha channel";
|
2007-09-18 23:57:02 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IMAGE_GRAYSCALE:
|
2015-09-29 11:27:00 -03:00
|
|
|
if (!(fop->m_format->support(FILE_SUPPORT_GRAY))) {
|
2013-10-14 19:58:11 -03:00
|
|
|
warnings += "<<- Grayscale format";
|
2012-01-05 19:45:03 -03:00
|
|
|
fatal = true;
|
2007-09-18 23:57:02 +00:00
|
|
|
}
|
2015-09-29 11:27:00 -03:00
|
|
|
if (!(fop->m_format->support(FILE_SUPPORT_GRAYA)) &&
|
|
|
|
fop->m_document->sprite()->needAlpha()) {
|
2013-10-14 19:58:11 -03:00
|
|
|
|
|
|
|
warnings += "<<- Alpha channel";
|
2007-09-18 23:57:02 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IMAGE_INDEXED:
|
2015-09-29 11:27:00 -03:00
|
|
|
if (!(fop->m_format->support(FILE_SUPPORT_INDEXED))) {
|
2013-10-14 19:58:11 -03:00
|
|
|
warnings += "<<- Indexed format";
|
2012-01-05 19:45:03 -03:00
|
|
|
fatal = true;
|
2007-09-18 23:57:02 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-03-09 13:57:16 -03:00
|
|
|
// Frames support
|
2015-09-29 11:27:00 -03:00
|
|
|
if (fop->m_document->sprite()->totalFrames() > 1) {
|
|
|
|
if (!fop->m_format->support(FILE_SUPPORT_FRAMES) &&
|
|
|
|
!fop->m_format->support(FILE_SUPPORT_SEQUENCES)) {
|
2013-10-14 19:58:11 -03:00
|
|
|
warnings += "<<- Frames";
|
2011-01-16 17:27:18 -03:00
|
|
|
}
|
2007-09-18 23:57:02 +00:00
|
|
|
}
|
|
|
|
|
2015-03-09 13:57:16 -03:00
|
|
|
// Layers support
|
2015-09-29 11:27:00 -03:00
|
|
|
if (fop->m_document->sprite()->folder()->getLayersCount() > 1) {
|
|
|
|
if (!(fop->m_format->support(FILE_SUPPORT_LAYERS))) {
|
2013-10-14 19:58:11 -03:00
|
|
|
warnings += "<<- Layers";
|
2007-09-18 23:57:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-09 13:57:16 -03:00
|
|
|
// Palettes support
|
2015-09-29 11:27:00 -03:00
|
|
|
if (fop->m_document->sprite()->getPalettes().size() > 1) {
|
|
|
|
if (!fop->m_format->support(FILE_SUPPORT_PALETTES) &&
|
|
|
|
!fop->m_format->support(FILE_SUPPORT_SEQUENCES)) {
|
2013-10-14 19:58:11 -03:00
|
|
|
warnings += "<<- Palette changes between frames";
|
2007-09-18 23:57:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-09 13:57:16 -03:00
|
|
|
// Check frames support
|
2015-09-29 11:27:00 -03:00
|
|
|
if (!fop->m_document->sprite()->frameTags().empty()) {
|
|
|
|
if (!fop->m_format->support(FILE_SUPPORT_FRAME_TAGS)) {
|
2015-03-09 13:57:16 -03:00
|
|
|
warnings += "<<- Frame tags";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-30 13:34:55 -03:00
|
|
|
// Big palettes
|
2015-09-29 11:27:00 -03:00
|
|
|
if (!fop->m_format->support(FILE_SUPPORT_BIG_PALETTES)) {
|
|
|
|
for (const Palette* pal : fop->m_document->sprite()->getPalettes()) {
|
2015-06-30 13:34:55 -03:00
|
|
|
if (pal->size() > 256) {
|
|
|
|
warnings += "<<- Palettes with more than 256 colors";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-30 17:41:25 -03:00
|
|
|
// Palette with alpha
|
2015-09-29 11:27:00 -03:00
|
|
|
if (!fop->m_format->support(FILE_SUPPORT_PALETTE_WITH_ALPHA)) {
|
2015-06-30 17:41:25 -03:00
|
|
|
bool done = false;
|
2015-09-29 11:27:00 -03:00
|
|
|
for (const Palette* pal : fop->m_document->sprite()->getPalettes()) {
|
2015-06-30 17:41:25 -03:00
|
|
|
for (int c=0; c<pal->size(); ++c) {
|
|
|
|
if (rgba_geta(pal->getEntry(c)) < 255) {
|
|
|
|
warnings += "<<- Palette with alpha channel";
|
|
|
|
done = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (done)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-14 19:58:11 -03:00
|
|
|
// Show the confirmation alert
|
|
|
|
if (!warnings.empty()) {
|
|
|
|
// Interative
|
2015-05-18 17:04:31 -03:00
|
|
|
if (context && context->isUIAvailable()) {
|
2015-03-11 16:15:09 -03:00
|
|
|
warnings += "<<You can use \".ase\" format to keep all this information.";
|
|
|
|
|
|
|
|
std::string title, buttons;
|
|
|
|
if (fatal) {
|
|
|
|
title = "Error";
|
|
|
|
buttons = "&Close";
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
title = "Warning";
|
|
|
|
buttons = "&Yes||&No";
|
|
|
|
}
|
|
|
|
|
|
|
|
int ret = ui::Alert::show("%s<<File format \".%s\" doesn't support:%s"
|
|
|
|
"<<Do you want continue with \".%s\" anyway?"
|
|
|
|
"||%s",
|
|
|
|
title.c_str(),
|
2015-09-29 11:27:00 -03:00
|
|
|
fop->m_format->name(),
|
2015-03-11 16:15:09 -03:00
|
|
|
warnings.c_str(),
|
2015-09-29 11:27:00 -03:00
|
|
|
fop->m_format->name(),
|
2015-03-11 16:15:09 -03:00
|
|
|
buttons.c_str());
|
|
|
|
|
|
|
|
// Operation can't be done (by fatal error) or the user cancel
|
|
|
|
// the operation
|
2015-09-29 11:27:00 -03:00
|
|
|
if ((fatal) || (ret != 1))
|
|
|
|
return nullptr;
|
2008-02-04 02:37:26 +00:00
|
|
|
}
|
2013-10-14 19:58:11 -03:00
|
|
|
// No interactive & fatal error?
|
2008-02-04 02:37:26 +00:00
|
|
|
else if (fatal) {
|
2015-09-29 11:27:00 -03:00
|
|
|
fop->setError(warnings.c_str());
|
|
|
|
return fop.release();
|
2007-09-18 23:57:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-16 17:27:18 -03:00
|
|
|
// Use the "sequence" interface.
|
2015-09-29 11:27:00 -03:00
|
|
|
if (fop->m_format->support(FILE_SUPPORT_SEQUENCES)) {
|
|
|
|
fop->prepareForSequence();
|
2008-02-04 02:37:26 +00:00
|
|
|
|
2015-04-06 12:01:08 -03:00
|
|
|
std::string fn = filename;
|
2015-01-25 22:36:32 -03:00
|
|
|
std::string fn_format = fn_format_arg;
|
|
|
|
bool default_format = false;
|
|
|
|
|
|
|
|
if (fn_format.empty()) {
|
2015-09-29 11:27:00 -03:00
|
|
|
if (fop->m_document->sprite()->totalFrames() == 1)
|
2015-01-25 22:36:32 -03:00
|
|
|
fn_format = "{fullname}";
|
|
|
|
else {
|
|
|
|
fn_format = "{path}/{title}{frame}.{extension}";
|
|
|
|
default_format = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Save one frame
|
2015-09-29 11:27:00 -03:00
|
|
|
if (fop->m_document->sprite()->totalFrames() == 1) {
|
2015-04-30 17:02:57 -03:00
|
|
|
FilenameInfo fnInfo;
|
|
|
|
fnInfo.filename(fn);
|
|
|
|
|
|
|
|
fn = filename_formatter(fn_format, fnInfo);
|
2015-09-29 11:27:00 -03:00
|
|
|
fop->m_seq.filename_list.push_back(fn);
|
2008-02-04 02:37:26 +00:00
|
|
|
}
|
2015-01-25 22:36:32 -03:00
|
|
|
// Save multiple frames
|
2008-02-04 02:37:26 +00:00
|
|
|
else {
|
2015-01-25 22:36:32 -03:00
|
|
|
int width = 0;
|
|
|
|
int start_from = 0;
|
|
|
|
|
|
|
|
if (default_format) {
|
2015-01-25 23:10:51 -03:00
|
|
|
std::string left, right;
|
|
|
|
start_from = split_filename(fn.c_str(), left, right, width);
|
2015-01-25 22:36:32 -03:00
|
|
|
if (start_from < 0) {
|
|
|
|
start_from = 1;
|
|
|
|
width = 1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
fn = left;
|
|
|
|
fn += right;
|
|
|
|
}
|
2007-09-18 23:57:02 +00:00
|
|
|
}
|
2008-02-04 02:37:26 +00:00
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
Sprite* spr = fop->m_document->sprite();
|
2015-01-25 22:36:32 -03:00
|
|
|
std::vector<char> buf(32);
|
|
|
|
std::sprintf(&buf[0], "{frame%0*d}", width, 0);
|
|
|
|
if (default_format)
|
|
|
|
fn_format = set_frame_format(fn_format, &buf[0]);
|
2015-04-30 17:02:57 -03:00
|
|
|
else if (spr->totalFrames() > 1)
|
2015-01-25 22:36:32 -03:00
|
|
|
fn_format = add_frame_format(fn_format, &buf[0]);
|
|
|
|
|
2015-04-30 17:02:57 -03:00
|
|
|
for (frame_t frame(0); frame<spr->totalFrames(); ++frame) {
|
|
|
|
FrameTag* innerTag = spr->frameTags().innerTag(frame);
|
|
|
|
FrameTag* outerTag = spr->frameTags().outerTag(frame);
|
|
|
|
FilenameInfo fnInfo;
|
|
|
|
fnInfo
|
|
|
|
.filename(fn)
|
|
|
|
.innerTagName(innerTag ? innerTag->name(): "")
|
|
|
|
.outerTagName(outerTag ? outerTag->name(): "")
|
2015-12-14 16:49:02 -03:00
|
|
|
.frame(start_from+frame)
|
|
|
|
.tagFrame(innerTag ? frame-innerTag->fromFrame():
|
|
|
|
start_from+frame);
|
2015-04-30 17:02:57 -03:00
|
|
|
|
2015-01-25 22:36:32 -03:00
|
|
|
std::string frame_fn =
|
2015-04-30 17:02:57 -03:00
|
|
|
filename_formatter(fn_format, fnInfo);
|
2015-01-25 22:36:32 -03:00
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
fop->m_seq.filename_list.push_back(frame_fn);
|
2008-02-04 02:37:26 +00:00
|
|
|
}
|
2015-12-22 18:00:01 -03:00
|
|
|
|
2016-03-17 10:31:33 -03:00
|
|
|
if (context && context->isUIAvailable() &&
|
|
|
|
fop->m_seq.filename_list.size() > 1 &&
|
2015-12-22 18:00:01 -03:00
|
|
|
ui::Alert::show("Notice"
|
|
|
|
"<<Do you want to export the animation in %d files?"
|
|
|
|
"<<%s, %s..."
|
|
|
|
"||&Agree||&Cancel",
|
|
|
|
int(fop->m_seq.filename_list.size()),
|
|
|
|
base::get_file_name(fop->m_seq.filename_list[0]).c_str(),
|
|
|
|
base::get_file_name(fop->m_seq.filename_list[1]).c_str()) != 1) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2008-02-04 02:37:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2015-09-29 11:27:00 -03:00
|
|
|
fop->m_filename = filename;
|
2008-02-04 02:37:26 +00:00
|
|
|
|
2011-01-18 19:30:42 -03:00
|
|
|
// Configure output format?
|
2015-09-29 11:27:00 -03:00
|
|
|
if (fop->m_format->support(FILE_SUPPORT_GET_FORMAT_OPTIONS)) {
|
|
|
|
base::SharedPtr<FormatOptions> format_options =
|
|
|
|
fop->m_format->getFormatOptions(fop);
|
2008-03-29 03:43:19 +00:00
|
|
|
|
2011-01-16 17:27:18 -03:00
|
|
|
// Does the user cancelled the operation?
|
2015-09-29 11:27:00 -03:00
|
|
|
if (!format_options)
|
|
|
|
return nullptr;
|
2008-03-29 03:43:19 +00:00
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
fop->m_seq.format_options = format_options;
|
|
|
|
fop->m_document->setFormatOptions(format_options);
|
2008-03-29 03:43:19 +00:00
|
|
|
}
|
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
return fop.release();
|
2008-02-04 02:37:26 +00:00
|
|
|
}
|
|
|
|
|
2011-03-22 21:11:25 -03:00
|
|
|
// Executes the file operation: loads or saves the sprite.
|
|
|
|
//
|
|
|
|
// It can be called from a different thread of the one used
|
2015-09-29 11:27:00 -03:00
|
|
|
// by FileOp::createLoadDocumentOperation() or createSaveDocumentOperation().
|
2011-03-22 21:11:25 -03:00
|
|
|
//
|
2015-09-29 11:27:00 -03:00
|
|
|
// After this function you must to mark the FileOp as "done" calling
|
|
|
|
// FileOp::done() function.
|
|
|
|
void FileOp::operate(IFileOpProgress* progress)
|
2008-02-04 02:37:26 +00:00
|
|
|
{
|
2015-09-29 11:27:00 -03:00
|
|
|
ASSERT(!isDone());
|
2008-02-04 02:37:26 +00:00
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
m_progressInterface = progress;
|
2012-07-06 01:06:00 -03:00
|
|
|
|
2011-03-22 21:11:25 -03:00
|
|
|
// Load //////////////////////////////////////////////////////////////////////
|
2015-09-29 11:27:00 -03:00
|
|
|
if (m_type == FileOpLoad &&
|
|
|
|
m_format != NULL &&
|
|
|
|
m_format->support(FILE_SUPPORT_LOAD)) {
|
2011-03-22 21:11:25 -03:00
|
|
|
// Load a sequence
|
2015-09-29 11:27:00 -03:00
|
|
|
if (isSequence()) {
|
2011-03-22 21:11:25 -03:00
|
|
|
// Default palette
|
2015-09-29 11:27:00 -03:00
|
|
|
m_seq.palette->makeBlack();
|
2008-02-04 02:37:26 +00:00
|
|
|
|
2015-01-04 10:58:14 -03:00
|
|
|
// Load the sequence
|
2015-09-29 11:27:00 -03:00
|
|
|
frame_t frames(m_seq.filename_list.size());
|
2014-12-28 20:39:11 -03:00
|
|
|
frame_t frame(0);
|
2015-09-28 18:49:34 -03:00
|
|
|
Image* old_image = nullptr;
|
|
|
|
|
|
|
|
// TODO set_palette for each frame???
|
|
|
|
auto add_image = [&]() {
|
2015-09-29 11:27:00 -03:00
|
|
|
m_seq.last_cel->data()->setImage(m_seq.image);
|
|
|
|
m_seq.layer->addCel(m_seq.last_cel);
|
2015-09-28 18:49:34 -03:00
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
if (m_document->sprite()->palette(frame)
|
|
|
|
->countDiff(m_seq.palette, NULL, NULL) > 0) {
|
|
|
|
m_seq.palette->setFrame(frame);
|
|
|
|
m_document->sprite()->setPalette(m_seq.palette, true);
|
2015-09-28 18:49:34 -03:00
|
|
|
}
|
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
old_image = m_seq.image.get();
|
|
|
|
m_seq.image.reset(NULL);
|
|
|
|
m_seq.last_cel = NULL;
|
2015-09-28 18:49:34 -03:00
|
|
|
};
|
2012-01-05 19:45:03 -03:00
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
m_seq.has_alpha = false;
|
|
|
|
m_seq.progress_offset = 0.0f;
|
|
|
|
m_seq.progress_fraction = 1.0f / (double)frames;
|
2008-02-04 02:37:26 +00:00
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
auto it = m_seq.filename_list.begin(),
|
|
|
|
end = m_seq.filename_list.end();
|
2010-11-06 11:59:03 -03:00
|
|
|
for (; it != end; ++it) {
|
2015-09-29 11:27:00 -03:00
|
|
|
m_filename = it->c_str();
|
2012-01-05 19:45:03 -03:00
|
|
|
|
|
|
|
// Call the "load" procedure to read the first bitmap.
|
2015-09-29 11:27:00 -03:00
|
|
|
bool loadres = m_format->load(this);
|
2012-01-05 19:45:03 -03:00
|
|
|
if (!loadres) {
|
2015-09-29 11:27:00 -03:00
|
|
|
setError("Error loading frame %d from file \"%s\"\n",
|
|
|
|
frame+1, m_filename.c_str());
|
2012-01-05 19:45:03 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
// For the first frame...
|
|
|
|
if (!old_image) {
|
|
|
|
// Error reading the first frame
|
2015-09-29 11:27:00 -03:00
|
|
|
if (!loadres || !m_document || !m_seq.last_cel) {
|
|
|
|
m_seq.image.reset();
|
|
|
|
delete m_seq.last_cel;
|
|
|
|
delete m_document;
|
|
|
|
m_document = nullptr;
|
2012-01-05 19:45:03 -03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
// Read ok
|
|
|
|
else {
|
2013-03-30 19:53:52 -03:00
|
|
|
// Add the keyframe
|
2015-09-28 18:49:34 -03:00
|
|
|
add_image();
|
2012-01-05 19:45:03 -03:00
|
|
|
}
|
|
|
|
}
|
2013-03-30 19:53:52 -03:00
|
|
|
// For other frames
|
2012-01-05 19:45:03 -03:00
|
|
|
else {
|
2013-03-30 19:53:52 -03:00
|
|
|
// All done (or maybe not enough memory)
|
2015-09-29 11:27:00 -03:00
|
|
|
if (!loadres || !m_seq.last_cel) {
|
|
|
|
m_seq.image.reset();
|
|
|
|
delete m_seq.last_cel;
|
2012-01-05 19:45:03 -03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2013-03-30 19:53:52 -03:00
|
|
|
// Compare the old frame with the new one
|
|
|
|
#if USE_LINK // TODO this should be configurable through a check-box
|
2015-09-29 11:27:00 -03:00
|
|
|
if (count_diff_between_images(old_image, m_seq.image)) {
|
2015-09-28 18:49:34 -03:00
|
|
|
add_image();
|
2012-01-05 19:45:03 -03:00
|
|
|
}
|
2013-03-30 19:53:52 -03:00
|
|
|
// We don't need this image
|
2012-01-05 19:45:03 -03:00
|
|
|
else {
|
2015-09-29 11:27:00 -03:00
|
|
|
delete m_seq.image;
|
2012-01-05 19:45:03 -03:00
|
|
|
|
2013-03-30 19:53:52 -03:00
|
|
|
// But add a link frame
|
2015-09-29 11:27:00 -03:00
|
|
|
m_seq.last_cel->image = image_index;
|
|
|
|
layer_add_frame(m_seq.layer, m_seq.last_cel);
|
2012-01-05 19:45:03 -03:00
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
m_seq.last_image = NULL;
|
|
|
|
m_seq.last_cel = NULL;
|
2012-01-05 19:45:03 -03:00
|
|
|
}
|
2008-02-04 02:37:26 +00:00
|
|
|
#else
|
2015-09-28 18:49:34 -03:00
|
|
|
add_image();
|
2008-02-04 02:37:26 +00:00
|
|
|
#endif
|
2012-01-05 19:45:03 -03:00
|
|
|
}
|
2007-09-18 23:57:02 +00:00
|
|
|
|
2012-07-08 21:09:09 -03:00
|
|
|
++frame;
|
2015-09-29 11:27:00 -03:00
|
|
|
m_seq.progress_offset += m_seq.progress_fraction;
|
2008-02-04 02:37:26 +00:00
|
|
|
}
|
2015-09-29 11:27:00 -03:00
|
|
|
m_filename = *m_seq.filename_list.begin();
|
2007-09-18 23:57:02 +00:00
|
|
|
|
2010-03-30 21:43:18 -03:00
|
|
|
// Final setup
|
2015-09-29 11:27:00 -03:00
|
|
|
if (m_document != NULL) {
|
2012-01-05 19:45:03 -03:00
|
|
|
// Configure the layer as the 'Background'
|
2015-09-29 11:27:00 -03:00
|
|
|
if (!m_seq.has_alpha)
|
|
|
|
m_seq.layer->configureAsBackground();
|
2008-03-29 03:43:19 +00:00
|
|
|
|
2012-01-05 19:45:03 -03:00
|
|
|
// Set the frames range
|
2015-09-29 11:27:00 -03:00
|
|
|
m_document->sprite()->setTotalFrames(frame);
|
2008-03-27 14:29:33 +00:00
|
|
|
|
2012-01-05 19:45:03 -03:00
|
|
|
// Sets special options from the specific format (e.g. BMP
|
|
|
|
// file can contain the number of bits per pixel).
|
2015-09-29 11:27:00 -03:00
|
|
|
m_document->setFormatOptions(m_seq.format_options);
|
2008-03-27 14:29:33 +00:00
|
|
|
}
|
2008-02-04 02:37:26 +00:00
|
|
|
}
|
2011-03-22 21:11:25 -03:00
|
|
|
// Direct load from one file.
|
2008-02-04 02:37:26 +00:00
|
|
|
else {
|
2011-03-22 21:11:25 -03:00
|
|
|
// Call the "load" procedure.
|
2015-09-29 11:27:00 -03:00
|
|
|
if (!m_format->load(this))
|
|
|
|
setError("Error loading sprite from file \"%s\"\n",
|
|
|
|
m_filename.c_str());
|
2008-02-04 02:37:26 +00:00
|
|
|
}
|
|
|
|
}
|
2011-03-22 21:11:25 -03:00
|
|
|
// Save //////////////////////////////////////////////////////////////////////
|
2015-09-29 11:27:00 -03:00
|
|
|
else if (m_type == FileOpSave &&
|
|
|
|
m_format != NULL &&
|
|
|
|
m_format->support(FILE_SUPPORT_SAVE)) {
|
2014-04-10 00:33:28 -03:00
|
|
|
#ifdef ENABLE_SAVE
|
2011-03-22 21:11:25 -03:00
|
|
|
// Save a sequence
|
2015-09-29 11:27:00 -03:00
|
|
|
if (isSequence()) {
|
|
|
|
ASSERT(m_format->support(FILE_SUPPORT_SEQUENCES));
|
2008-02-04 02:37:26 +00:00
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
Sprite* sprite = m_document->sprite();
|
2011-03-22 21:11:25 -03:00
|
|
|
|
|
|
|
// Create a temporary bitmap
|
2015-09-29 11:27:00 -03:00
|
|
|
m_seq.image.reset(Image::create(sprite->pixelFormat(),
|
2015-01-04 10:58:14 -03:00
|
|
|
sprite->width(),
|
|
|
|
sprite->height()));
|
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
m_seq.progress_offset = 0.0f;
|
|
|
|
m_seq.progress_fraction = 1.0f / (double)sprite->totalFrames();
|
2015-01-04 10:58:14 -03:00
|
|
|
|
|
|
|
// For each frame in the sprite.
|
|
|
|
render::Render render;
|
|
|
|
for (frame_t frame(0); frame < sprite->totalFrames(); ++frame) {
|
2015-09-29 11:27:00 -03:00
|
|
|
// Draw the "frame" in "m_seq.image"
|
|
|
|
render.renderSprite(m_seq.image.get(), sprite, frame);
|
2015-01-04 10:58:14 -03:00
|
|
|
|
|
|
|
// Setup the palette.
|
2015-09-29 11:27:00 -03:00
|
|
|
sprite->palette(frame)->copyColorsTo(m_seq.palette);
|
2007-09-18 23:57:02 +00:00
|
|
|
|
2015-01-04 10:58:14 -03:00
|
|
|
// Setup the filename to be used.
|
2015-09-29 11:27:00 -03:00
|
|
|
m_filename = m_seq.filename_list[frame];
|
2015-01-04 10:58:14 -03:00
|
|
|
|
|
|
|
// Call the "save" procedure... did it fail?
|
2015-09-29 11:27:00 -03:00
|
|
|
if (!m_format->save(this)) {
|
|
|
|
setError("Error saving frame %d in the file \"%s\"\n",
|
|
|
|
frame+1, m_filename.c_str());
|
2015-01-04 10:58:14 -03:00
|
|
|
break;
|
2012-01-05 19:45:03 -03:00
|
|
|
}
|
2007-09-18 23:57:02 +00:00
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
m_seq.progress_offset += m_seq.progress_fraction;
|
2008-02-04 02:37:26 +00:00
|
|
|
}
|
2015-12-22 18:07:06 -03:00
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
m_filename = *m_seq.filename_list.begin();
|
2015-12-22 18:07:06 -03:00
|
|
|
m_document->setFilename(m_filename);
|
2015-01-04 10:58:14 -03:00
|
|
|
|
|
|
|
// Destroy the image
|
2015-09-29 11:27:00 -03:00
|
|
|
m_seq.image.reset(NULL);
|
2007-09-18 23:57:02 +00:00
|
|
|
}
|
2011-03-22 21:11:25 -03:00
|
|
|
// Direct save to a file.
|
2007-09-18 23:57:02 +00:00
|
|
|
else {
|
2011-03-22 21:11:25 -03:00
|
|
|
// Call the "save" procedure.
|
2015-09-29 11:27:00 -03:00
|
|
|
if (!m_format->save(this))
|
|
|
|
setError("Error saving the sprite in the file \"%s\"\n",
|
|
|
|
m_filename.c_str());
|
2007-09-18 23:57:02 +00:00
|
|
|
}
|
2014-04-10 00:33:28 -03:00
|
|
|
#else
|
2015-09-29 11:27:00 -03:00
|
|
|
setError(
|
2014-04-10 00:33:28 -03:00
|
|
|
"Save operation is not supported in trial version.\n"
|
|
|
|
"Go to " WEBSITE_DOWNLOAD " and get the full-version.");
|
|
|
|
#endif
|
2008-02-04 02:37:26 +00:00
|
|
|
}
|
|
|
|
|
2011-03-22 21:11:25 -03:00
|
|
|
// Progress = 100%
|
2015-09-29 11:27:00 -03:00
|
|
|
setProgress(1.0f);
|
2008-02-10 19:06:03 +00:00
|
|
|
}
|
|
|
|
|
2011-03-22 21:11:25 -03:00
|
|
|
// After mark the 'fop' as 'done' you must to free it calling fop_free().
|
2015-09-29 11:27:00 -03:00
|
|
|
void FileOp::done()
|
2008-02-10 19:06:03 +00:00
|
|
|
{
|
2011-03-22 21:11:25 -03:00
|
|
|
// Finally done.
|
2015-09-29 11:27:00 -03:00
|
|
|
scoped_lock lock(m_mutex);
|
|
|
|
m_done = true;
|
2008-02-04 02:37:26 +00:00
|
|
|
}
|
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
void FileOp::stop()
|
2008-02-10 19:06:03 +00:00
|
|
|
{
|
2015-09-29 11:27:00 -03:00
|
|
|
scoped_lock lock(m_mutex);
|
|
|
|
if (!m_done)
|
|
|
|
m_stop = true;
|
2008-02-10 19:06:03 +00:00
|
|
|
}
|
|
|
|
|
2012-07-06 01:06:00 -03:00
|
|
|
FileOp::~FileOp()
|
2008-02-04 02:37:26 +00:00
|
|
|
{
|
2015-09-29 11:27:00 -03:00
|
|
|
if (m_format)
|
|
|
|
m_format->destroyData(this);
|
2011-06-25 17:12:08 -03:00
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
delete m_seq.palette;
|
2012-07-06 01:06:00 -03:00
|
|
|
}
|
2009-05-31 20:15:38 +00:00
|
|
|
|
2014-07-29 00:53:24 -03:00
|
|
|
void FileOp::createDocument(Sprite* spr)
|
|
|
|
{
|
|
|
|
// spr can be NULL if the sprite is set in onPostLoad() then
|
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
ASSERT(m_document == NULL);
|
|
|
|
m_document = new Document(spr);
|
2008-02-04 02:37:26 +00:00
|
|
|
}
|
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
void FileOp::postLoad()
|
2011-06-25 17:12:08 -03:00
|
|
|
{
|
2015-09-29 11:27:00 -03:00
|
|
|
if (m_document == NULL)
|
2011-06-25 17:12:08 -03:00
|
|
|
return;
|
|
|
|
|
|
|
|
// Set the filename.
|
2016-04-11 19:17:39 -03:00
|
|
|
std::string fn;
|
2015-09-29 11:27:00 -03:00
|
|
|
if (isSequence())
|
2016-04-11 19:17:39 -03:00
|
|
|
fn = m_seq.filename_list.begin()->c_str();
|
2011-06-25 17:12:08 -03:00
|
|
|
else
|
2016-04-11 19:17:39 -03:00
|
|
|
fn = m_filename.c_str();
|
|
|
|
m_document->setFilename(fn);
|
2011-06-25 17:12:08 -03:00
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
bool result = m_format->postLoad(this);
|
2011-06-25 17:12:08 -03:00
|
|
|
if (!result) {
|
|
|
|
// Destroy the document
|
2015-09-29 11:27:00 -03:00
|
|
|
delete m_document;
|
|
|
|
m_document = nullptr;
|
2011-06-25 17:12:08 -03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
Sprite* sprite = m_document->sprite();
|
2015-05-21 10:17:59 -03:00
|
|
|
if (sprite) {
|
2011-06-25 17:12:08 -03:00
|
|
|
// Creates a suitable palette for RGB images
|
2015-05-21 10:17:59 -03:00
|
|
|
if (sprite->pixelFormat() == IMAGE_RGB &&
|
|
|
|
sprite->getPalettes().size() <= 1 &&
|
|
|
|
sprite->palette(frame_t(0))->isBlack()) {
|
|
|
|
base::SharedPtr<Palette> palette(
|
2015-08-20 12:37:58 -03:00
|
|
|
render::create_palette_from_sprite(
|
2015-07-22 18:26:25 -03:00
|
|
|
sprite, frame_t(0), sprite->lastFrame(), true,
|
|
|
|
nullptr, nullptr));
|
2015-05-21 10:17:59 -03:00
|
|
|
|
|
|
|
sprite->resetPalettes();
|
|
|
|
sprite->setPalette(palette.get(), false);
|
2011-06-25 17:12:08 -03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
m_document->markAsSaved();
|
|
|
|
}
|
|
|
|
|
|
|
|
base::SharedPtr<FormatOptions> FileOp::sequenceGetFormatOptions() const
|
|
|
|
{
|
|
|
|
return m_seq.format_options;
|
2011-06-25 17:12:08 -03:00
|
|
|
}
|
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
void FileOp::sequenceSetFormatOptions(const base::SharedPtr<FormatOptions>& format_options)
|
2008-03-27 14:29:33 +00:00
|
|
|
{
|
2015-09-29 11:27:00 -03:00
|
|
|
ASSERT(!m_seq.format_options);
|
|
|
|
m_seq.format_options = format_options;
|
2008-03-27 14:29:33 +00:00
|
|
|
}
|
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
void FileOp::sequenceSetNColors(int ncolors)
|
2015-06-30 18:16:10 -03:00
|
|
|
{
|
2015-09-29 11:27:00 -03:00
|
|
|
m_seq.palette->resize(ncolors);
|
2015-06-30 18:16:10 -03:00
|
|
|
}
|
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
int FileOp::sequenceGetNColors() const
|
2015-06-30 18:16:10 -03:00
|
|
|
{
|
2015-09-29 11:27:00 -03:00
|
|
|
return m_seq.palette->size();
|
2015-06-30 18:16:10 -03:00
|
|
|
}
|
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
void FileOp::sequenceSetColor(int index, int r, int g, int b)
|
2008-02-04 02:37:26 +00:00
|
|
|
{
|
2015-09-29 11:27:00 -03:00
|
|
|
m_seq.palette->setEntry(index, rgba(r, g, b, 255));
|
2008-02-04 02:37:26 +00:00
|
|
|
}
|
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
void FileOp::sequenceGetColor(int index, int* r, int* g, int* b) const
|
2008-02-04 02:37:26 +00:00
|
|
|
{
|
2015-06-30 13:34:55 -03:00
|
|
|
uint32_t c;
|
|
|
|
|
|
|
|
ASSERT(index >= 0);
|
2015-09-29 11:27:00 -03:00
|
|
|
if (index >= 0 && index < m_seq.palette->size())
|
|
|
|
c = m_seq.palette->getEntry(index);
|
2015-06-30 13:34:55 -03:00
|
|
|
else
|
|
|
|
c = rgba(0, 0, 0, 255); // Black color
|
2008-02-04 02:37:26 +00:00
|
|
|
|
2013-11-09 19:59:05 -03:00
|
|
|
*r = rgba_getr(c);
|
|
|
|
*g = rgba_getg(c);
|
|
|
|
*b = rgba_getb(c);
|
2008-02-04 02:37:26 +00:00
|
|
|
}
|
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
void FileOp::sequenceSetAlpha(int index, int a)
|
2015-06-30 18:08:14 -03:00
|
|
|
{
|
2015-09-29 11:27:00 -03:00
|
|
|
int c = m_seq.palette->getEntry(index);
|
2015-06-30 18:08:14 -03:00
|
|
|
int r = rgba_getr(c);
|
|
|
|
int g = rgba_getg(c);
|
|
|
|
int b = rgba_getb(c);
|
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
m_seq.palette->setEntry(index, rgba(r, g, b, a));
|
2015-06-30 18:08:14 -03:00
|
|
|
}
|
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
void FileOp::sequenceGetAlpha(int index, int* a) const
|
2015-06-30 18:08:14 -03:00
|
|
|
{
|
|
|
|
ASSERT(index >= 0);
|
2015-09-29 11:27:00 -03:00
|
|
|
if (index >= 0 && index < m_seq.palette->size())
|
|
|
|
*a = rgba_geta(m_seq.palette->getEntry(index));
|
2015-06-30 18:08:14 -03:00
|
|
|
else
|
|
|
|
*a = 0;
|
|
|
|
}
|
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
Image* FileOp::sequenceImage(PixelFormat pixelFormat, int w, int h)
|
2008-02-04 02:37:26 +00:00
|
|
|
{
|
2009-11-17 13:12:26 +00:00
|
|
|
Sprite* sprite;
|
2008-02-04 02:37:26 +00:00
|
|
|
|
2010-03-28 12:15:32 -03:00
|
|
|
// Create the image
|
2015-09-29 11:27:00 -03:00
|
|
|
if (!m_document) {
|
2012-02-12 23:21:06 -03:00
|
|
|
sprite = new Sprite(pixelFormat, w, h, 256);
|
2009-11-17 13:12:26 +00:00
|
|
|
try {
|
|
|
|
LayerImage* layer = new LayerImage(sprite);
|
|
|
|
|
2010-03-28 12:15:32 -03:00
|
|
|
// Add the layer
|
2014-07-30 01:28:15 -03:00
|
|
|
sprite->folder()->addLayer(layer);
|
2008-02-04 02:37:26 +00:00
|
|
|
|
2010-03-28 12:15:32 -03:00
|
|
|
// Done
|
2015-09-29 11:27:00 -03:00
|
|
|
createDocument(sprite);
|
|
|
|
m_seq.layer = layer;
|
2009-11-17 13:12:26 +00:00
|
|
|
}
|
|
|
|
catch (...) {
|
2009-06-01 02:59:15 +00:00
|
|
|
delete sprite;
|
2009-11-17 13:12:26 +00:00
|
|
|
throw;
|
2008-02-04 02:37:26 +00:00
|
|
|
}
|
2007-09-18 23:57:02 +00:00
|
|
|
}
|
|
|
|
else {
|
2015-09-29 11:27:00 -03:00
|
|
|
sprite = m_document->sprite();
|
2008-02-04 02:37:26 +00:00
|
|
|
|
2014-07-30 01:28:15 -03:00
|
|
|
if (sprite->pixelFormat() != pixelFormat)
|
2015-09-29 11:27:00 -03:00
|
|
|
return nullptr;
|
2007-09-18 23:57:02 +00:00
|
|
|
}
|
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
if (m_seq.last_cel) {
|
|
|
|
setError("Error: called two times \"fop_sequence_image()\".\n");
|
|
|
|
return nullptr;
|
2008-02-04 02:37:26 +00:00
|
|
|
}
|
|
|
|
|
2011-03-22 21:11:25 -03:00
|
|
|
// Create a bitmap
|
2015-09-29 11:27:00 -03:00
|
|
|
m_seq.image.reset(Image::create(pixelFormat, w, h));
|
|
|
|
m_seq.last_cel = new Cel(m_seq.frame++, ImageRef(nullptr));
|
2008-02-04 02:37:26 +00:00
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
return m_seq.image.get();
|
2008-02-04 02:37:26 +00:00
|
|
|
}
|
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
void FileOp::setError(const char *format, ...)
|
2008-02-04 02:37:26 +00:00
|
|
|
{
|
|
|
|
char buf_error[4096];
|
|
|
|
va_list ap;
|
|
|
|
va_start(ap, format);
|
2014-09-21 13:42:46 -03:00
|
|
|
vsnprintf(buf_error, sizeof(buf_error), format, ap);
|
2008-02-04 02:37:26 +00:00
|
|
|
va_end(ap);
|
|
|
|
|
2010-11-06 11:59:03 -03:00
|
|
|
// Concatenate the new error
|
2008-02-04 02:37:26 +00:00
|
|
|
{
|
2015-09-29 11:27:00 -03:00
|
|
|
scoped_lock lock(m_mutex);
|
|
|
|
m_error += buf_error;
|
2008-02-04 02:37:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
void FileOp::setProgress(double progress)
|
2008-02-04 02:37:26 +00:00
|
|
|
{
|
2015-09-29 11:27:00 -03:00
|
|
|
scoped_lock lock(m_mutex);
|
2010-03-10 00:34:50 -02:00
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
if (isSequence()) {
|
|
|
|
m_progress =
|
|
|
|
m_seq.progress_offset +
|
|
|
|
m_seq.progress_fraction*progress;
|
2010-03-10 00:34:50 -02:00
|
|
|
}
|
|
|
|
else {
|
2015-09-29 11:27:00 -03:00
|
|
|
m_progress = progress;
|
2008-02-04 02:37:26 +00:00
|
|
|
}
|
2012-07-06 01:06:00 -03:00
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
if (m_progressInterface)
|
|
|
|
m_progressInterface->ackFileOpProgress(progress);
|
2008-02-04 02:37:26 +00:00
|
|
|
}
|
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
double FileOp::progress() const
|
2008-02-04 02:37:26 +00:00
|
|
|
{
|
2012-07-06 01:06:00 -03:00
|
|
|
double progress;
|
2008-02-04 02:37:26 +00:00
|
|
|
{
|
2015-09-29 11:27:00 -03:00
|
|
|
scoped_lock lock(m_mutex);
|
|
|
|
progress = m_progress;
|
2008-02-04 02:37:26 +00:00
|
|
|
}
|
|
|
|
return progress;
|
|
|
|
}
|
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
// Returns true when the file operation has finished, this means, when
|
|
|
|
// the FileOp::operate() routine ends.
|
|
|
|
bool FileOp::isDone() const
|
2008-02-04 02:37:26 +00:00
|
|
|
{
|
|
|
|
bool done;
|
|
|
|
{
|
2015-09-29 11:27:00 -03:00
|
|
|
scoped_lock lock(m_mutex);
|
|
|
|
done = m_done;
|
2008-02-04 02:37:26 +00:00
|
|
|
}
|
|
|
|
return done;
|
|
|
|
}
|
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
bool FileOp::isStop() const
|
2008-02-04 02:37:26 +00:00
|
|
|
{
|
|
|
|
bool stop;
|
|
|
|
{
|
2015-09-29 11:27:00 -03:00
|
|
|
scoped_lock lock(m_mutex);
|
|
|
|
stop = m_stop;
|
2008-02-04 02:37:26 +00:00
|
|
|
}
|
|
|
|
return stop;
|
|
|
|
}
|
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
FileOp::FileOp(FileOpType type, Context* context)
|
|
|
|
: m_type(type)
|
|
|
|
, m_format(nullptr)
|
|
|
|
, m_context(context)
|
|
|
|
, m_document(nullptr)
|
|
|
|
, m_progress(0.0)
|
|
|
|
, m_progressInterface(nullptr)
|
|
|
|
, m_done(false)
|
|
|
|
, m_stop(false)
|
|
|
|
, m_oneframe(false)
|
2008-02-04 02:37:26 +00:00
|
|
|
{
|
2015-09-29 11:27:00 -03:00
|
|
|
m_seq.palette = nullptr;
|
|
|
|
m_seq.image.reset(nullptr);
|
|
|
|
m_seq.progress_offset = 0.0f;
|
|
|
|
m_seq.progress_fraction = 0.0f;
|
|
|
|
m_seq.frame = frame_t(0);
|
|
|
|
m_seq.layer = nullptr;
|
|
|
|
m_seq.last_cel = nullptr;
|
2008-02-04 02:37:26 +00:00
|
|
|
}
|
|
|
|
|
2015-09-29 11:27:00 -03:00
|
|
|
void FileOp::prepareForSequence()
|
2008-02-04 02:37:26 +00:00
|
|
|
{
|
2015-09-29 11:27:00 -03:00
|
|
|
m_seq.palette = new Palette(frame_t(0), 256);
|
|
|
|
m_seq.format_options.reset();
|
2007-09-18 23:57:02 +00:00
|
|
|
}
|
|
|
|
|
2013-08-05 21:20:19 -03:00
|
|
|
} // namespace app
|