| |
| |
|
|
| #include "tsystem.h" |
| #include "trasterimage.h" |
| #include "tiio.h" |
| #include "timageinfo.h" |
| #include "tcontenthistory.h" |
| |
| |
| #include "toonz/txshleveltypes.h" |
| #include "toonz/imagemanager.h" |
| #include "toonz/toonzscene.h" |
| #include "toonz/levelproperties.h" |
| #include "toonz/preferences.h" |
| #include "toonz/sceneproperties.h" |
| |
| #include "toonz/levelupdater.h" |
| |
| |
| |
| |
| |
| namespace |
| { |
| |
| inline bool supportsRandomAccess(const TFilePath &fp) |
| { |
| const std::string &type = fp.getType(); |
| return type == "tlv" || |
| |
| |
| fp.getDots() == ".."; |
| } |
| |
| |
| |
| void enforceBpp(TPropertyGroup *pg, int bpp, bool upgradeOnly) |
| { |
| |
| TEnumProperty *bppProp = (TEnumProperty *)pg->getProperty("Bits Per Pixel"); |
| if (bppProp) { |
| typedef TEnumProperty::Range Range; |
| const Range &range = bppProp->getRange(); |
| |
| |
| int idx = bppProp->getIndex(); |
| |
| |
| int currentBpp = upgradeOnly ? atoi(bppProp->getValueAsString().c_str()) : 0; |
| int targetBpp = (std::numeric_limits<int>::max)(), targetIdx = -1; |
| |
| int i, count = (int)range.size(); |
| for (i = 0; i < count; ++i) { |
| int bppEntry = atoi(toString(range[i]).c_str()); |
| if ((bppEntry % bpp == 0) && currentBpp <= bppEntry && bppEntry < targetBpp) |
| targetBpp = bppEntry, targetIdx = i; |
| } |
| |
| if (targetIdx >= 0) |
| bppProp->setIndex(targetIdx); |
| } |
| |
| |
| if (bpp % 32 == 0) { |
| TBoolProperty *alphaProp = (TBoolProperty *)pg->getProperty("Alpha Channel"); |
| if (alphaProp) |
| alphaProp->setValue(true); |
| } |
| } |
| |
| } |
| |
| |
| |
| |
| |
| LevelUpdater::LevelUpdater() |
| : m_pg(0), m_inputLevel(0), m_currIdx(0), m_imageInfo(0), m_usingTemporaryFile(false), m_opened(false) |
| { |
| } |
| |
| |
| |
| LevelUpdater::LevelUpdater(TXshSimpleLevel *sl) |
| : m_pg(0), m_inputLevel(0), m_imageInfo(0), m_currIdx(0), m_opened(false), m_usingTemporaryFile(false) |
| { |
| open(sl); |
| } |
| |
| |
| |
| LevelUpdater::LevelUpdater(const TFilePath &fp, TPropertyGroup *lwProperties) |
| : m_pg(0), m_inputLevel(0), m_imageInfo(0), m_currIdx(0), m_opened(false), m_usingTemporaryFile(false) |
| { |
| open(fp, lwProperties); |
| } |
| |
| |
| |
| LevelUpdater::~LevelUpdater() |
| { |
| |
| |
| |
| |
| |
| |
| try { |
| close(); |
| } catch (...) { |
| } |
| } |
| |
| |
| |
| void LevelUpdater::reset() |
| { |
| m_lw = TLevelWriterP(); |
| m_lwPath = TFilePath(); |
| |
| m_lr = TLevelReaderP(); |
| m_inputLevel = TLevelP(); |
| m_sl = TXshSimpleLevelP(); |
| |
| delete m_pg; |
| m_pg = 0; |
| |
| if (m_imageInfo) { |
| delete m_imageInfo->m_properties; |
| delete m_imageInfo; |
| m_imageInfo = 0; |
| } |
| |
| m_fids.clear(); |
| m_currIdx = 0; |
| |
| m_usingTemporaryFile = false; |
| m_opened = false; |
| } |
| |
| |
| |
| void LevelUpdater::buildSourceInfo(const TFilePath &fp) |
| { |
| try { |
| m_lr = TLevelReaderP(fp); |
| assert(m_lr); |
| |
| m_lr->enableRandomAccessRead(true); |
| |
| m_inputLevel = m_lr->loadInfo(); |
| |
| const TImageInfo *info = m_lr->getImageInfo(); |
| if (info) { |
| m_imageInfo = new TImageInfo(*info); |
| if (info->m_properties) |
| m_imageInfo->m_properties = info->m_properties->clone(); |
| |
| } |
| } catch (...) { |
| |
| |
| |
| m_lr = TLevelReaderP(); |
| m_inputLevel = TLevelP(0); |
| |
| if (m_imageInfo) { |
| delete m_imageInfo->m_properties; |
| delete m_imageInfo; |
| m_imageInfo = 0; |
| } |
| } |
| } |
| |
| |
| |
| void LevelUpdater::buildProperties(const TFilePath &fp) |
| { |
| |
| m_pg = (m_imageInfo && m_imageInfo->m_properties) ? m_imageInfo->m_properties->clone() : Tiio::makeWriterProperties(fp.getType()); |
| |
| if (!m_pg) { |
| |
| reset(); |
| throw TException("Unrecognized file format"); |
| } |
| |
| assert(m_pg); |
| } |
| |
| |
| |
| void LevelUpdater::open(const TFilePath &fp, TPropertyGroup *pg) |
| { |
| assert(!m_lw); |
| |
| |
| bool existsLevel = TSystem::doesExistFileOrLevel(fp); |
| if (existsLevel) |
| buildSourceInfo(fp); |
| |
| |
| if (pg) |
| m_pg = pg->clone(); |
| else |
| buildProperties(fp); |
| |
| try { |
| |
| m_usingTemporaryFile = existsLevel && !supportsRandomAccess(fp); |
| if (m_usingTemporaryFile) { |
| |
| |
| m_lwPath = getNewTemporaryFilePath(fp); |
| m_lw = TLevelWriterP(m_lwPath, m_pg->clone()); |
| |
| if (m_inputLevel) |
| for (TLevel::Iterator it = m_inputLevel->begin(); it != m_inputLevel->end(); ++it) |
| m_fids.push_back(it->first); |
| } else { |
| m_lr = TLevelReaderP(); |
| m_lw = TLevelWriterP(fp, m_pg->clone()); |
| m_lwPath = fp; |
| } |
| } catch (...) { |
| |
| |
| |
| |
| reset(); |
| throw; |
| } |
| |
| |
| TDimension iconSize = Preferences::instance()->getIconSize(); |
| assert(iconSize.lx > 0 && iconSize.ly > 0); |
| m_lw->setIconSize(iconSize); |
| |
| m_opened = true; |
| } |
| |
| |
| |
| void LevelUpdater::open(TXshSimpleLevel *sl) |
| { |
| assert(!m_lw); |
| |
| assert(sl && sl->getScene()); |
| m_sl = sl; |
| |
| const TFilePath &fp = sl->getScene()->decodeFilePath(sl->getPath()); |
| |
| |
| bool existsLevel = TSystem::doesExistFileOrLevel(fp); |
| if (existsLevel) |
| buildSourceInfo(fp); |
| |
| |
| buildProperties(fp); |
| |
| |
| |
| |
| LevelProperties *levelProperties = sl->getProperties(); |
| assert(levelProperties); |
| |
| if (levelProperties->hasAlpha() || !existsLevel) { |
| int bpp = levelProperties->hasAlpha() ? tmin(32, levelProperties->getBpp()) : levelProperties->getBpp(); |
| enforceBpp(m_pg, bpp, existsLevel); |
| } |
| |
| |
| |
| try { |
| |
| m_usingTemporaryFile = existsLevel && !supportsRandomAccess(fp); |
| if (m_usingTemporaryFile) { |
| |
| |
| m_lwPath = getNewTemporaryFilePath(fp); |
| m_lw = TLevelWriterP(m_lwPath, m_pg->clone()); |
| } else { |
| m_lr = TLevelReaderP(); |
| m_lw = TLevelWriterP(fp, m_pg->clone()); |
| m_lwPath = fp; |
| } |
| } catch (...) { |
| |
| reset(); |
| throw; |
| } |
| |
| |
| sl->getFids(m_fids); |
| |
| |
| TDimension iconSize = Preferences::instance()->getIconSize(); |
| assert(iconSize.lx > 0 && iconSize.ly > 0); |
| m_lw->setIconSize(iconSize); |
| |
| if (sl->getContentHistory()) |
| m_lw->setContentHistory(m_sl->getContentHistory()->clone()); |
| |
| m_opened = true; |
| } |
| |
| |
| |
| TFilePath LevelUpdater::getNewTemporaryFilePath(const TFilePath &fp) |
| { |
| TFilePath fp2; |
| int count = 1; |
| |
| for (;;) { |
| fp2 = fp.withName(fp.getWideName() + L"__" + toWideString(count++)); |
| if (!TSystem::doesExistFileOrLevel(fp2)) |
| break; |
| } |
| |
| return fp2; |
| } |
| |
| |
| |
| void LevelUpdater::addFramesTo(int endIdx) |
| { |
| if (m_sl) { |
| |
| |
| |
| for (; m_currIdx < endIdx; ++m_currIdx) { |
| TImageP img = m_sl->getFullsampledFrame(m_fids[m_currIdx], ImageManager::dontPutInCache); |
| assert(img); |
| |
| if (!img && m_lr) { |
| |
| |
| img = m_lr->getFrameReader(m_fids[m_currIdx])->load(); |
| if (img) |
| img->setPalette(m_sl->getPalette()); |
| } |
| |
| if (img) |
| m_lw->getFrameWriter(m_fids[m_currIdx])->save(img); |
| } |
| } else if (m_lr) { |
| |
| for (; m_currIdx < endIdx; ++m_currIdx) { |
| TImageP img = m_lr->getFrameReader(m_fids[m_currIdx])->load(); |
| |
| if (img) |
| m_lw->getFrameWriter(m_fids[m_currIdx])->save(img); |
| } |
| } |
| } |
| |
| |
| |
| void LevelUpdater::update(const TFrameId &fid, const TImageP &img) |
| { |
| |
| resume(); |
| |
| if (!m_usingTemporaryFile) { |
| |
| m_lw->getFrameWriter(fid)->save(img); |
| return; |
| } |
| |
| |
| |
| addFramesTo(std::lower_bound(m_fids.begin() + m_currIdx, m_fids.end(), fid) - m_fids.begin()); |
| |
| |
| m_lw->getFrameWriter(fid)->save(img); |
| if (m_currIdx < int(m_fids.size()) && m_fids[m_currIdx] == fid) |
| ++m_currIdx; |
| } |
| |
| |
| |
| void LevelUpdater::close() |
| { |
| if (!m_opened) |
| return; |
| |
| |
| resume(); |
| |
| try { |
| if (m_usingTemporaryFile) { |
| |
| addFramesTo((int)m_fids.size()); |
| |
| |
| |
| |
| |
| |
| |
| |
| if (m_lr) { |
| TFilePath finalPath(m_lr->getFilePath()), tempPath(m_lw->getFilePath()); |
| |
| |
| |
| |
| m_lr = TLevelReaderP(), m_lw = TLevelWriterP(); |
| |
| |
| TSystem::removeFileOrLevel_throw(finalPath); |
| TSystem::renameFileOrLevel_throw(finalPath, tempPath); |
| |
| |
| if (finalPath.getType() == "tlv") { |
| |
| TFilePath finalPalette = finalPath.withType("tpl"); |
| TFilePath tempPalette = tempPath.withType("tpl"); |
| |
| if (TFileStatus(finalPalette).doesExist()) { |
| if (TFileStatus(tempPalette).doesExist()) |
| TSystem::deleteFile(finalPalette); |
| TSystem::renameFile(finalPalette, tempPalette); |
| } |
| |
| |
| TFilePath finalHistory = finalPath.withType("hst"); |
| TFilePath tempHistory = tempPath.withType("hst"); |
| |
| if (TFileStatus(tempHistory).doesExist()) { |
| if (TFileStatus(finalHistory).doesExist()) |
| TSystem::deleteFile(finalHistory); |
| TSystem::renameFile(finalHistory, tempHistory); |
| } |
| } |
| } |
| |
| |
| |
| |
| } |
| |
| |
| reset(); |
| } catch (...) { |
| |
| |
| |
| |
| reset(); |
| throw; |
| } |
| } |
| |
| |
| |
| void LevelUpdater::flush() |
| { |
| assert(m_opened); |
| if (!m_lw) |
| return; |
| |
| |
| |
| try { |
| m_lw = TLevelWriterP(); |
| } catch (...) { |
| reset(); |
| throw; |
| } |
| } |
| |
| |
| |
| void LevelUpdater::resume() |
| { |
| assert(m_opened); |
| if (m_lw) |
| return; |
| |
| try { |
| m_lw = TLevelWriterP(m_lwPath, m_pg->clone()); |
| } catch (...) { |
| reset(); |
| throw; |
| } |
| } |
| |