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