1 #pragma once
2 
3 #ifndef LEVELUPDATER_H
4 #define LEVELUPDATER_H
5 
6 // TnzCore includes
7 #include "tlevel_io.h"
8 
9 // TnzLib includes
10 #include "toonz/txshsimplelevel.h"
11 
12 #undef DVAPI
13 #undef DVVAR
14 #ifdef TOONZLIB_EXPORTS
15 #define DVAPI DV_EXPORT_API
16 #define DVVAR DV_EXPORT_VAR
17 #else
18 #define DVAPI DV_IMPORT_API
19 #define DVVAR DV_IMPORT_VAR
20 #endif
21 
22 //=====================================================
23 
24 //  Forward declarations
25 
26 class TContentHistory;
27 class TPropertyGroup;
28 
29 //=====================================================
30 
31 //*****************************************************************************************
32 //    LevelUpdater  declaration
33 //*****************************************************************************************
34 
35 //! LevelUpdater is the preferential interface for dealing with \a conservative
36 //! levels I/O in Toonz.
37 /*!
38     The Toonz Image library already provides the basic TLevelWriter interface
39 that can be
40     used to save image levels on hard disk. This is usually sufficient to
41 satisfy most needs,
42     with a simple enough usage:
43 
44     \code
45     TLevelWriterP lw(
46       levelPath,                                          // Attach to the
47 required level path (creates level if none).
48       Tiio::makeWriterProperties(levelPath.getType()));   // NOTE: Level
49 Properties are not read from an existing level.
50 
51     TPropertyGroup* props(lw->getProperties());
52     assert(props);                                        // Currently
53 guaranteed ONLY if specified at lw's construction.
54 
55     props->getProperty("Bits Per Pixel")->setValue(L"64(RGBM)");
56 
57     lw->getFrameWriter(fid1)->save(img1);                 // Save image img1 at
58 frame fid1
59     lw->getFrameWriter(fid2)->save(img2);                 // ...
60     \endcode
61 
62     Some output types, however, may not support image insertions in the middle
63 of an already existing
64     level, but just <I> at the end <\I> (as is the case for movie formats like
65 \a avi).
66     In these cases, a newly created temporary file must be used to have both old
67 and new images \a appended at
68     the right time. Once the appending procedure ends, the temporary gets
69 renamed to the original file.
70     Additional files related to the level must be renamed too, such as the
71 level's palette and content history.
72 \n
73     Plus, as noted in the example, the format properties of any existing level
74 at specified path must be manually
75     retrieved.
76 \n\n
77     The LevelUpdater is a wrapper class to both TLevelReader and TLevelWriter
78 employable to deal with these subtelties
79     with a simple, equivalent syntax to the one above:
80 
81     \code
82     LevelUpdater lu(levelPath);                             // Attach to the
83 required level path (creates level if none).
84                                                             // Reads any
85 existing level format properties.
86 
87     TPropertyGroup* props(lu.getLevelWriter()->getProperties());      //
88 Properties (eventually default ones) are ensured
89     assert(props);                                                    // to
90 exist.
91 
92     props->getProperty("Bits Per Pixel")->setValue(L"64(RGBM)");
93 
94     lu.update(fid1, img1);                                  // Save image img1
95 at frame fid1
96     lu.update(fid2, img2);                                  // ...
97     \endcode
98 
99 \warning The LevelUpdater requires that <B> saved images must be ordered by
100 insertion frame <\B>. If necessary,
101          users must have them sorted before supplying them tp the updater.
102 */
103 
104 class DVAPI LevelUpdater {
105   TLevelWriterP m_lw;  //!< The updater's level writer object
106   TFilePath
107       m_lwPath;  //!< Path of the file written by m_lw, could be a temporary
108   TPropertyGroup *m_pg;  //!< Copy of the file format propeties used by m_lw
109 
110   TLevelReaderP m_lr;       //!< The updater's level reader object
111   TLevelP m_inputLevel;     //!< The initial source level frames structure
112   TImageInfo *m_imageInfo;  //!< The source level's image info
113 
114   std::vector<TFrameId>
115       m_fids;     //!< Remaining frames stored in the source level
116   int m_currIdx;  //!< Current m_fids index
117 
118   TXshSimpleLevelP m_sl;  //!< XSheet image level the updater may be attached to
119 
120   bool m_usingTemporaryFile;  //!< Whether a temporary file is being used to
121                               //! hold additional frames
122   bool m_opened;  //!< Wheter the updater is already attached to a level
123 
124 public:
125   LevelUpdater();
126   LevelUpdater(TXshSimpleLevel *sl);
127   LevelUpdater(const TFilePath &path, TPropertyGroup *lwProperties = 0);
128   ~LevelUpdater();
129 
getLevelWriter()130   TLevelWriterP getLevelWriter() { return m_lw; }
getLevelReader()131   TLevelReaderP getLevelReader() { return m_lr; }
132 
133   //! Returns a description of any already existing level on the attached path
134   //! (in terms of frames content and palette).
getInputLevel()135   TLevelP getInputLevel() { return m_inputLevel; }
136 
137   //! Returns the image properties of the updated level, if one already exists.
getImageInfo()138   const TImageInfo *getImageInfo() { return m_imageInfo; }
139 
140   //! Attaches the updater to the specified path, using and <I> taking ownership
141   //! <\I> of the supplied write properties.
142   //! This function may throw in case the specified path has an unrecognized
143   //! extension, or the file could
144   //! not be opened for write.
145   void open(const TFilePath &src, TPropertyGroup *lwProperties);
146 
147   //! Attaches the updater to the specified simple level instance. Format
148   //! properties are the default in case the level
149   //! is saved anew. If the level requires the alpha channel, evenutal bpp and
150   //! alpha properties are upgraded accordingly.
151   //! This function may throw just like its path-based counterpart.
152   void open(TXshSimpleLevel *sl);
153 
opened()154   bool opened() const { return m_opened; }
155 
156   //! Stores the supplied image in the level, at the specified frame. Remember
157   //! that frames \b must be added with
158   //! increasing fid ordering.
159   void update(const TFrameId &fid, const TImageP &img);
160 
161   //! Closes and flushes the level. In case temporary files were used for the
162   //! level, they replace the originals now.
163   //! In case the replace procedure failed, the temporaries are (silently, in
164   //! current implementation) retained on disk.
165   void close();
166 
167   //! Flushes the level currently opened for write, \a suspending the update
168   //! procedure. Since a level cannot be both
169   //! opened for read and write at the same time, users could require to flush
170   //! all updates and suspend (without closing)
171   //! an update procedure to read some of the data that has just been written.
172   //! The update procedure will be resumed automatically at the next update() or
173   //! close() invocation.
174 
175   //! \warning Not all file formats currently support this. A brief list of
176   //! currently supporting formats include TLV,
177   //! MOV and multi-file levels, whereas formats \b not supporting it include
178   //! PLI and AVI (due to TLevelWriter not
179   //! supporting \a appends to an already existing level).
180   void flush();
181 
182 private:
183   void reset();
184   void resume();
185 
186   void buildSourceInfo(const TFilePath &fp);
187   void buildProperties(const TFilePath &fp);
188   TFilePath getNewTemporaryFilePath(const TFilePath &path);
189   void addFramesTo(int endIdx);
190 };
191 
192 #endif  // LEVELUPDATER_H
193