1 // Aseprite
2 // Copyright (C) 2001-2018  David Capello
3 //
4 // This program is distributed under the terms of
5 // the End-User License Agreement for Aseprite.
6 
7 #ifndef APP_FILE_FILE_H_INCLUDED
8 #define APP_FILE_FILE_H_INCLUDED
9 #pragma once
10 
11 #include "base/mutex.h"
12 #include "base/paths.h"
13 #include "base/shared_ptr.h"
14 #include "doc/frame.h"
15 #include "doc/image_ref.h"
16 #include "doc/pixel_format.h"
17 #include "doc/selected_frames.h"
18 
19 #include <cstdio>
20 #include <string>
21 
22 // Flags for FileOp::createLoadDocumentOperation()
23 #define FILE_LOAD_SEQUENCE_NONE         0x00000001
24 #define FILE_LOAD_SEQUENCE_ASK          0x00000002
25 #define FILE_LOAD_SEQUENCE_ASK_CHECKBOX 0x00000004
26 #define FILE_LOAD_SEQUENCE_YES          0x00000008
27 #define FILE_LOAD_ONE_FRAME             0x00000010
28 #define FILE_LOAD_DATA_FILE             0x00000020
29 
30 namespace doc {
31   class FrameTag;
32 }
33 
34 namespace doc {
35   class Cel;
36   class Image;
37   class Layer;
38   class LayerImage;
39   class Palette;
40   class Slice;
41   class Sprite;
42 }
43 
44 namespace app {
45 
46   class Context;
47   class Doc;
48   class FileFormat;
49   class FormatOptions;
50 
51   using namespace doc;
52 
53   // File operations.
54   typedef enum {
55     FileOpLoad,
56     FileOpSave
57   } FileOpType;
58 
59   class IFileOpProgress {
60   public:
~IFileOpProgress()61     virtual ~IFileOpProgress() { }
62     virtual void ackFileOpProgress(double progress) = 0;
63   };
64 
65   class FileOpROI {             // Region of interest
66   public:
67     FileOpROI();
68     FileOpROI(const Doc* doc,
69               const std::string& sliceName,
70               const std::string& frameTagName,
71               const doc::SelectedFrames& selFrames,
72               const bool adjustByFrameTag);
73 
document()74     const Doc* document() const { return m_document; }
slice()75     doc::Slice* slice() const { return m_slice; }
frameTag()76     doc::FrameTag* frameTag() const { return m_frameTag; }
fromFrame()77     doc::frame_t fromFrame() const { return m_selFrames.firstFrame(); }
toFrame()78     doc::frame_t toFrame() const { return m_selFrames.lastFrame(); }
selectedFrames()79     const doc::SelectedFrames& selectedFrames() const { return m_selFrames; }
80 
frames()81     doc::frame_t frames() const {
82       return (doc::frame_t)m_selFrames.size();
83     }
84 
85   private:
86     const Doc* m_document;
87     doc::Slice* m_slice;
88     doc::FrameTag* m_frameTag;
89     doc::SelectedFrames m_selFrames;
90   };
91 
92   // Structure to load & save files.
93   //
94   // TODO This class do to many things. There should be a previous
95   // instance (class) to verify what the user want to do with the
96   // sequence of files, and the result of that operation should be the
97   // input of this one.
98   class FileOp {
99   public:
100     static FileOp* createLoadDocumentOperation(Context* context,
101                                                const std::string& filename,
102                                                int flags);
103 
104     static FileOp* createSaveDocumentOperation(const Context* context,
105                                                const FileOpROI& roi,
106                                                const std::string& filename,
107                                                const std::string& filenameFormat);
108 
109     ~FileOp();
110 
isSequence()111     bool isSequence() const { return !m_seq.filename_list.empty(); }
isOneFrame()112     bool isOneFrame() const { return m_oneframe; }
113 
filename()114     const std::string& filename() const { return m_filename; }
filenames()115     const base::paths& filenames() const { return m_seq.filename_list; }
context()116     Context* context() const { return m_context; }
document()117     Doc* document() const { return m_document; }
releaseDocument()118     Doc* releaseDocument() {
119       Doc* doc = m_document;
120       m_document = nullptr;
121       return doc;
122     }
123 
roi()124     const FileOpROI& roi() const { return m_roi; }
125 
126     void createDocument(Sprite* spr);
127     void operate(IFileOpProgress* progress = nullptr);
128 
129     void done();
130     void stop();
131     bool isDone() const;
132     bool isStop() const;
133 
134     // Does extra post-load processing which may require user intervention.
135     void postLoad();
136 
137     // Special options specific to the file format.
138     base::SharedPtr<FormatOptions> formatOptions() const;
139     void setFormatOptions(const base::SharedPtr<FormatOptions>& opts);
140 
141     // Helpers for file decoder/encoder (FileFormat) with
142     // FILE_SUPPORT_SEQUENCES flag.
143     void sequenceSetNColors(int ncolors);
144     int sequenceGetNColors() const;
145     void sequenceSetColor(int index, int r, int g, int b);
146     void sequenceGetColor(int index, int* r, int* g, int* b) const;
147     void sequenceSetAlpha(int index, int a);
148     void sequenceGetAlpha(int index, int* a) const;
149     Image* sequenceImage(PixelFormat pixelFormat, int w, int h);
sequenceImage()150     const Image* sequenceImage() const { return m_seq.image.get(); }
sequenceGetHasAlpha()151     bool sequenceGetHasAlpha() const {
152       return m_seq.has_alpha;
153     }
sequenceSetHasAlpha(bool hasAlpha)154     void sequenceSetHasAlpha(bool hasAlpha) {
155       m_seq.has_alpha = hasAlpha;
156     }
sequenceFlags()157     int sequenceFlags() const {
158       return m_seq.flags;
159     }
160 
error()161     const std::string& error() const { return m_error; }
162     void setError(const char *error, ...);
hasError()163     bool hasError() const { return !m_error.empty(); }
164 
165     double progress() const;
166     void setProgress(double progress);
167 
168     void getFilenameList(base::paths& output) const;
169 
170   private:
171     FileOp();                   // Undefined
172     FileOp(FileOpType type, Context* context);
173 
174     FileOpType m_type;          // Operation type: 0=load, 1=save.
175     FileFormat* m_format;
176     Context* m_context;
177     // TODO this should be a shared pointer (and we should remove
178     //      releaseDocument() member function)
179     Doc* m_document;            // Loaded document, or document to be saved.
180     std::string m_filename;     // File-name to load/save.
181     std::string m_dataFilename; // File-name for a special XML .aseprite-data where extra sprite data can be stored
182     FileOpROI m_roi;
183 
184     // Shared fields between threads.
185     mutable base::mutex m_mutex; // Mutex to access to the next two fields.
186     double m_progress;          // Progress (1.0 is ready).
187     IFileOpProgress* m_progressInterface;
188     std::string m_error;        // Error string.
189     bool m_done;                // True if the operation finished.
190     bool m_stop;                // Force the break of the operation.
191     bool m_oneframe;            // Load just one frame (in formats
192                                 // that support animation like
193                                 // GIF/FLI/ASE).
194 
195     base::SharedPtr<FormatOptions> m_formatOptions;
196 
197     // Data for sequences.
198     struct {
199       base::paths filename_list;  // All file names to load/save.
200       Palette* palette;           // Palette of the sequence.
201       ImageRef image;             // Image to be saved/loaded.
202       // For the progress bar.
203       double progress_offset;      // Progress offset from the current frame.
204       double progress_fraction;    // Progress fraction for one frame.
205       // To load sequences.
206       frame_t frame;
207       bool has_alpha;
208       LayerImage* layer;
209       Cel* last_cel;
210       // Flags after the user choose what to do with the sequence.
211       int flags;
212     } m_seq;
213 
214     void prepareForSequence();
215   };
216 
217   // Available extensions for each load/save operation.
218   base::paths get_readable_extensions();
219   base::paths get_writable_extensions();
220 
221   // High-level routines to load/save documents.
222   Doc* load_document(Context* context, const std::string& filename);
223   int save_document(Context* context, Doc* document);
224 
225   // Returns true if the given filename contains a file extension that
226   // can be used to save only static images (i.e. animations are saved
227   // as sequence of files).
228   bool is_static_image_format(const std::string& filename);
229 
230 } // namespace app
231 
232 #endif
233