| |
| |
| #include "toonz/txshsimplelevel.h" |
| #include "imagebuilders.h" |
| |
| |
| #include "toonz/txshleveltypes.h" |
| #include "toonz/imagemanager.h" |
| #include "toonz/studiopalette.h" |
| #include "toonz/hook.h" |
| #include "toonz/toonzscene.h" |
| #include "toonz/levelproperties.h" |
| #include "toonz/levelupdater.h" |
| #include "toonz/fullcolorpalette.h" |
| #include "toonz/preferences.h" |
| #include "toonz/stage.h" |
| #include "toonz/textureutils.h" |
| #include "toonz/levelset.h" |
| |
| |
| #include "tenv.h" |
| |
| |
| #include "trasterimage.h" |
| #include "tvectorimage.h" |
| #include "tmeshimage.h" |
| #include "timagecache.h" |
| #include "tofflinegl.h" |
| #include "tvectorgl.h" |
| #include "tvectorrenderdata.h" |
| #include "tropcm.h" |
| #include "tpixelutils.h" |
| #include "timageinfo.h" |
| #include "tlogger.h" |
| #include "tstream.h" |
| #include "tsystem.h" |
| #include "tcontenthistory.h" |
| |
| |
| #include <QDir> |
| #include <QRegExp> |
| #include <QMessageBox> |
| |
| #include "../common/psdlib/psd.h" |
| |
| namespace bc = boost::container; |
| |
| |
| |
| |
| |
| DEFINE_CLASS_CODE(TXshSimpleLevel, 20) |
| PERSIST_IDENTIFIER(TXshSimpleLevel, "level") |
| |
| |
| |
| |
| |
| namespace |
| { |
| |
| int idBaseCode = 1; |
| |
| |
| |
| struct CompatibilityStruct { |
| int writeMask, neededMask, forbiddenMask; |
| }; |
| |
| CompatibilityStruct compatibility = |
| { |
| 0x00F1, |
| |
| 0x0000, |
| |
| |
| |
| 0x000E |
| |
| }; |
| |
| |
| |
| inline std::string rasterized(std::string id) { return id + "_rasterized"; } |
| inline std::string filled(std::string id) { return id + "_filled"; } |
| |
| |
| |
| QString getCreatorString() |
| { |
| QString creator = |
| QString::fromStdString(TEnv::getApplicationName()) + " " + |
| QString::fromStdString(TEnv::getApplicationVersion()) + |
| " CM(" + QString::number(compatibility.writeMask, 16) + ")"; |
| return creator; |
| } |
| |
| |
| |
| bool checkCreatorString(const QString &creator) |
| { |
| int mask = 0; |
| if (creator != "") { |
| QRegExp rx("CM\\([0-9A-Fa-f]*\\)"); |
| int pos = rx.indexIn(creator); |
| int len = rx.matchedLength(); |
| if (pos >= 0 && len >= 4) { |
| QString v; |
| if (len > 4) |
| v = creator.mid(pos + 3, len - 4); |
| bool ok = true; |
| mask = v.toInt(&ok, 16); |
| } |
| } |
| return (mask & compatibility.neededMask) == compatibility.neededMask && |
| (mask & compatibility.forbiddenMask) == 0; |
| } |
| |
| |
| |
| bool isAreadOnlyLevel(const TFilePath &path) |
| { |
| if (path.isEmpty() || !path.isAbsolute()) |
| return false; |
| if (path.getDots() == "." || (path.getDots() == ".." && (path.getType() == "tlv" || path.getType() == "tpl"))) { |
| if (!TSystem::doesExistFileOrLevel(path)) |
| return false; |
| TFileStatus fs(path); |
| return !fs.isWritable(); |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| else |
| return false; |
| } |
| |
| |
| |
| void getIndexesRangefromFids( |
| TXshSimpleLevel *level, const std::set<TFrameId> &fids, int &fromIndex, int &toIndex) |
| { |
| if (fids.empty()) { |
| fromIndex = toIndex = -1; |
| return; |
| } |
| |
| toIndex = 0; |
| fromIndex = level->getFrameCount() - 1; |
| |
| std::set<TFrameId>::const_iterator it; |
| for (it = fids.begin(); it != fids.end(); ++it) { |
| int index = level->guessIndex(*it); |
| if (index > toIndex) |
| toIndex = index; |
| if (index < fromIndex) |
| fromIndex = index; |
| } |
| } |
| |
| } |
| |
| |
| |
| |
| |
| bool TXshSimpleLevel::m_rasterizePli = false; |
| bool TXshSimpleLevel::m_fillFullColorRaster = false; |
| |
| |
| |
| TXshSimpleLevel::TXshSimpleLevel(const wstring &name) |
| : TXshLevel(m_classCode, name), m_properties(new LevelProperties), m_palette(0), m_idBase(toString(idBaseCode++)), m_editableRangeUserInfo(L""), m_isSubsequence(false), m_16BitChannelLevel(false), m_isReadOnly(false), m_temporaryHookMerged(false) |
| { |
| } |
| |
| |
| |
| TXshSimpleLevel::~TXshSimpleLevel() |
| { |
| clearFrames(); |
| |
| if (m_palette) |
| m_palette->release(); |
| } |
| |
| |
| |
| void TXshSimpleLevel::setEditableRange(unsigned int from, unsigned int to, const wstring &userName) |
| { |
| assert(from <= to && to < (unsigned int)getFrameCount()); |
| unsigned int i; |
| for (i = from; i <= to; i++) |
| m_editableRange.insert(index2fid(i)); |
| |
| QString hostName = TSystem::getHostName(); |
| m_editableRangeUserInfo = userName + L"_" + hostName.toStdWString(); |
| |
| wstring fileName = getEditableFileName(); |
| TFilePath dstPath = getScene()->decodeFilePath(m_path); |
| dstPath = dstPath.withName(fileName).withType(dstPath.getType()); |
| |
| |
| if (getType() != OVL_XSHLEVEL && TSystem::doesExistFileOrLevel(dstPath)) { |
| TLevelReaderP lr(dstPath); |
| TLevelP level = lr->loadInfo(); |
| setPalette(level->getPalette()); |
| for (TLevel::Iterator it = level->begin(); it != level->end(); it++) { |
| TImageP img = lr->getFrameReader(it->first)->load(); |
| setFrame(it->first, img); |
| } |
| } |
| |
| |
| const TFilePath &hookFile = getHookPath(dstPath); |
| mergeTemporaryHookFile(from, to, hookFile); |
| } |
| |
| |
| |
| void TXshSimpleLevel::mergeTemporaryHookFile(unsigned int from, unsigned int to, const TFilePath &hookFile) |
| { |
| if (!TFileStatus(hookFile).doesExist()) |
| return; |
| |
| HookSet *tempHookSet = new HookSet; |
| TIStream is(hookFile); |
| string tagName; |
| try { |
| if (is.matchTag(tagName) && tagName == "hooks") |
| tempHookSet->loadData(is); |
| } catch (...) { |
| } |
| |
| HookSet *hookSet = getHookSet(); |
| int tempHookCount = tempHookSet->getHookCount(); |
| |
| if (tempHookCount == 0) { |
| for (unsigned int f = from; f <= to; f++) { |
| TFrameId fid = index2fid(f); |
| hookSet->eraseFrame(fid); |
| } |
| } else { |
| for (int i = 0; i < tempHookCount; i++) { |
| Hook *hook = tempHookSet->getHook(i); |
| Hook *newHook = hookSet->touchHook(hook->getId()); |
| newHook->setTrackerObjectId(hook->getTrackerObjectId()); |
| newHook->setTrackerRegionHeight(hook->getTrackerRegionHeight()); |
| newHook->setTrackerRegionWidth(hook->getTrackerRegionWidth()); |
| for (unsigned int f = from; f <= to; f++) { |
| TFrameId fid = index2fid(f); |
| newHook->setAPos(fid, hook->getAPos(fid)); |
| newHook->setBPos(fid, hook->getBPos(fid)); |
| } |
| } |
| } |
| |
| m_temporaryHookMerged = true; |
| } |
| |
| |
| |
| void TXshSimpleLevel::clearEditableRange() |
| { |
| m_editableRange.clear(); |
| m_editableRangeUserInfo = L""; |
| } |
| |
| |
| |
| wstring TXshSimpleLevel::getEditableFileName() |
| { |
| #ifdef MACOSX |
| wstring fileName = L"." + m_path.getWideName(); |
| #else |
| wstring fileName = m_path.getWideName(); |
| #endif |
| fileName += L"_" + m_editableRangeUserInfo; |
| int from, to; |
| getIndexesRangefromFids(this, m_editableRange, from, to); |
| if (from == -1 && to == -1) |
| return L""; |
| fileName += L"_" + toWideString(from + 1) + L"-" + toWideString(to + 1); |
| return fileName; |
| } |
| |
| |
| |
| std::set<TFrameId> TXshSimpleLevel::getEditableRange() |
| { |
| return m_editableRange; |
| } |
| |
| |
| |
| void TXshSimpleLevel::setRenumberTable() |
| { |
| m_renumberTable.clear(); |
| |
| FramesSet::iterator ft, fEnd = m_frames.end(); |
| for (ft = m_frames.begin(); ft != fEnd; ++ft) |
| m_renumberTable[*ft] = *ft; |
| } |
| |
| |
| |
| void TXshSimpleLevel::setDirtyFlag(bool on) |
| { |
| m_properties->setDirtyFlag(on); |
| } |
| |
| |
| |
| bool TXshSimpleLevel::getDirtyFlag() const |
| { |
| return m_properties->getDirtyFlag(); |
| } |
| |
| |
| |
| void TXshSimpleLevel::touchFrame(const TFrameId &fid) |
| { |
| m_properties->setDirtyFlag(true); |
| TContentHistory *ch = getContentHistory(); |
| if (!ch) { |
| ch = new TContentHistory(true); |
| setContentHistory(ch); |
| } |
| ch->frameModifiedNow(fid); |
| |
| if (getType() == PLI_XSHLEVEL) { |
| string id = rasterized(getImageId(fid)); |
| ImageManager::instance()->invalidate(id); |
| } |
| if (getType() & FULLCOLOR_TYPE) { |
| string id = filled(getImageId(fid)); |
| ImageManager::instance()->invalidate(id); |
| } |
| } |
| |
| |
| |
| void TXshSimpleLevel::onPaletteChanged() |
| { |
| FramesSet::iterator ft, fEnd = m_frames.end(); |
| for (ft = m_frames.begin(); ft != fEnd; ++ft) { |
| const TFrameId &fid = *ft; |
| |
| if (getType() == PLI_XSHLEVEL) { |
| string id = rasterized(getImageId(fid)); |
| ImageManager::instance()->invalidate(id); |
| } |
| if (getType() & FULLCOLOR_TYPE) { |
| string id = filled(getImageId(fid)); |
| ImageManager::instance()->invalidate(id); |
| } |
| |
| texture_utils::invalidateTexture(this, fid); |
| } |
| } |
| |
| |
| |
| void TXshSimpleLevel::setScannedPath(const TFilePath &fp) |
| { |
| m_scannedPath = fp; |
| } |
| |
| |
| |
| void TXshSimpleLevel::setPath(const TFilePath &fp, bool keepFrames) |
| { |
| m_path = fp; |
| if (!keepFrames) { |
| clearFrames(); |
| assert(getScene()); |
| try { |
| load(); |
| } catch (...) { |
| } |
| } |
| |
| if (getType() != PLI_XSHLEVEL) { |
| if (!m_frames.empty()) { |
| string imageId = getImageId(getFirstFid()); |
| const TImageInfo *imageInfo = ImageManager::instance()->getInfo(imageId, ImageManager::none, 0); |
| if (imageInfo) { |
| TDimension imageRes(0, 0); |
| TPointD imageDpi; |
| imageRes.lx = imageInfo->m_lx; |
| imageRes.ly = imageInfo->m_ly; |
| imageDpi.x = imageInfo->m_dpix; |
| imageDpi.y = imageInfo->m_dpiy; |
| m_properties->setImageDpi(imageDpi); |
| m_properties->setImageRes(imageRes); |
| m_properties->setBpp(imageInfo->m_bitsPerSample * imageInfo->m_samplePerPixel); |
| } |
| } |
| } |
| } |
| |
| |
| |
| void TXshSimpleLevel::clonePropertiesFrom(const TXshSimpleLevel *oldSl) |
| { |
| m_properties->setImageDpi(oldSl->m_properties->getImageDpi()); |
| m_properties->setDpi(oldSl->m_properties->getDpi()); |
| m_properties->setDpiPolicy(oldSl->m_properties->getDpiPolicy()); |
| m_properties->setImageRes(oldSl->m_properties->getImageRes()); |
| m_properties->setBpp(oldSl->m_properties->getBpp()); |
| m_properties->setSubsampling(oldSl->m_properties->getSubsampling()); |
| } |
| |
| |
| |
| TPalette *TXshSimpleLevel::getPalette() const |
| { |
| return m_palette; |
| } |
| |
| |
| |
| void TXshSimpleLevel::setPalette(TPalette *palette) |
| { |
| if (m_palette != palette) { |
| if (m_palette) |
| m_palette->release(); |
| |
| m_palette = palette; |
| if (m_palette) { |
| m_palette->addRef(); |
| if (!(getType() & FULLCOLOR_TYPE)) |
| m_palette->setPaletteName(getName()); |
| } |
| } |
| } |
| |
| |
| |
| void TXshSimpleLevel::getFids(std::vector<TFrameId> &fids) const |
| { |
| fids.assign(m_frames.begin(), m_frames.end()); |
| } |
| |
| |
| |
| std::vector<TFrameId> TXshSimpleLevel::getFids() const |
| { |
| return std::vector<TFrameId>(m_frames.begin(), m_frames.end()); |
| } |
| |
| |
| |
| bool TXshSimpleLevel::isFid(const TFrameId &fid) const |
| { |
| return m_frames.count(fid); |
| } |
| |
| |
| |
| const TFrameId &TXshSimpleLevel::getFrameId(int index) const |
| { |
| return *(m_frames.begin() += index); |
| } |
| |
| |
| |
| TFrameId TXshSimpleLevel::getFirstFid() const |
| { |
| return !isEmpty() ? *m_frames.begin() : TFrameId(TFrameId::NO_FRAME); |
| } |
| |
| |
| |
| TFrameId TXshSimpleLevel::getLastFid() const |
| { |
| return !isEmpty() ? *m_frames.rbegin() : TFrameId(TFrameId::NO_FRAME); |
| } |
| |
| |
| |
| int TXshSimpleLevel::guessStep() const |
| { |
| int frameCount = m_frames.size(); |
| if (frameCount < 2) |
| return 1; |
| |
| FramesSet::const_iterator ft = m_frames.begin(); |
| |
| TFrameId firstFid = *ft++, |
| secondFid = *ft++; |
| |
| if (firstFid.getLetter() != 0 || secondFid.getLetter() != 0) |
| return 1; |
| |
| int step = secondFid.getNumber() - firstFid.getNumber(); |
| if (step == 1) |
| return 1; |
| |
| |
| |
| TFrameId lastFid = *m_frames.rbegin(); |
| if (lastFid.getLetter() != 0) |
| return 1; |
| |
| if (lastFid.getNumber() != firstFid.getNumber() + step * (frameCount - 1)) |
| return 1; |
| |
| for (int i = 2; ft != m_frames.end(); ++ft, ++i) { |
| const TFrameId &fid = *ft; |
| |
| if (fid.getLetter() != 0) |
| return 1; |
| |
| if (fid.getNumber() != firstFid.getNumber() + step * i) |
| return 1; |
| } |
| |
| return step; |
| } |
| |
| |
| |
| int TXshSimpleLevel::fid2index(const TFrameId &fid) const |
| { |
| FramesSet::const_iterator ft = m_frames.find(fid); |
| return (ft != m_frames.end()) ? std::distance(m_frames.begin(), ft) : |
| -1; |
| } |
| |
| |
| |
| int TXshSimpleLevel::guessIndex(const TFrameId &fid) const |
| { |
| if (m_frames.empty()) |
| return 0; |
| |
| FramesSet::const_iterator ft = m_frames.lower_bound(fid); |
| if (ft == m_frames.end()) { |
| const TFrameId &maxFid = *m_frames.rbegin(); |
| assert(fid > maxFid); |
| |
| |
| |
| int step = guessStep(); |
| int i = (fid.getNumber() - maxFid.getNumber()) / step; |
| return m_frames.size() - 1 + i; |
| } else |
| return std::distance(m_frames.begin(), ft); |
| } |
| |
| |
| |
| TFrameId TXshSimpleLevel::index2fid(int index) const |
| { |
| if (index < 0) |
| return TFrameId(-2); |
| |
| int frameCount = m_frames.size(); |
| if (frameCount == 0) |
| return TFrameId(1); |
| |
| if (index < frameCount) { |
| FramesSet::const_iterator ft = m_frames.begin(); |
| std::advance(ft, index); |
| return *ft; |
| } else { |
| int step = guessStep(); |
| TFrameId maxFid = *m_frames.rbegin(); |
| int d = step * (index - frameCount + 1); |
| return TFrameId(maxFid.getNumber() + d); |
| } |
| } |
| |
| |
| |
| TImageP TXshSimpleLevel::getFrame(const TFrameId &fid, UCHAR imFlags, int subsampling) const |
| { |
| assert(m_type != UNKNOWN_XSHLEVEL); |
| |
| |
| if (m_frames.count(fid) == 0) |
| return TImageP(); |
| |
| const string &imgId = getImageId(fid); |
| |
| ImageLoader::BuildExtData extData(this, fid, subsampling); |
| TImageP img = ImageManager::instance()->getImage( |
| imgId, imFlags, &extData); |
| |
| if (imFlags & ImageManager::toBeModified) { |
| |
| texture_utils::invalidateTexture(this, fid); |
| } |
| |
| return img; |
| } |
| |
| |
| |
| TImageInfo *TXshSimpleLevel::getFrameInfo(const TFrameId &fid, bool toBeModified) |
| { |
| assert(m_type != UNKNOWN_XSHLEVEL); |
| |
| |
| if (m_frames.count(fid) == 0) |
| return 0; |
| |
| const string &imgId = getImageId(fid); |
| |
| TImageInfo *info = ImageManager::instance()->getInfo( |
| imgId, toBeModified ? ImageManager::toBeModified : ImageManager::none, 0); |
| |
| return info; |
| } |
| |
| |
| |
| TImageP TXshSimpleLevel::getFrameIcon(const TFrameId &fid) const |
| { |
| assert(m_type != UNKNOWN_XSHLEVEL); |
| |
| if (m_frames.count(fid) == 0) |
| return TImageP(); |
| |
| |
| |
| |
| ImageLoader::BuildExtData extData(this, fid); |
| extData.m_subs = 1, extData.m_icon = true; |
| |
| const std::string &imgId = getImageId(fid); |
| TImageP img = ImageManager::instance()->getImage(imgId, ImageManager::dontPutInCache, &extData); |
| |
| TToonzImageP timg = (TToonzImageP)img; |
| if (timg && m_palette) |
| timg->setPalette(m_palette); |
| |
| return img; |
| } |
| |
| |
| |
| void TXshSimpleLevel::loadAllIconsAndPutInCache(bool cacheImagesAsWell) |
| { |
| if (m_type != TZP_XSHLEVEL) |
| return; |
| |
| std::vector<TFrameId> fids; |
| getFids(fids); |
| |
| std::vector<std::string> iconIds; |
| |
| for (int i = 0; i < (int)fids.size(); i++) { |
| iconIds.push_back(getIconId(fids[i])); |
| } |
| |
| ImageManager::instance()->loadAllTlvIconsAndPutInCache(this, fids, iconIds, cacheImagesAsWell); |
| } |
| |
| |
| |
| TRasterImageP TXshSimpleLevel::getFrameToCleanup(const TFrameId &fid) const |
| { |
| assert(m_type != UNKNOWN_XSHLEVEL); |
| |
| FramesSet::const_iterator ft = m_frames.find(fid); |
| if (ft == m_frames.end()) |
| return TImageP(); |
| |
| bool flag = (m_scannedPath != TFilePath()); |
| string imageId = getImageId(fid, flag ? Scanned : 0); |
| |
| ImageLoader::BuildExtData extData(this, fid, 1); |
| TRasterImageP img = ImageManager::instance()->getImage(imageId, ImageManager::dontPutInCache, &extData); |
| if (!img) |
| return img; |
| |
| double x_dpi, y_dpi; |
| img->getDpi(x_dpi, y_dpi); |
| if (!x_dpi && !y_dpi) { |
| TPointD dpi = m_properties->getDpi(); |
| img->setDpi(dpi.x, dpi.y); |
| } |
| |
| return img; |
| } |
| |
| |
| |
| TImageP TXshSimpleLevel::getFullsampledFrame(const TFrameId &fid, UCHAR imFlags) const |
| { |
| assert(m_type != UNKNOWN_XSHLEVEL); |
| |
| FramesSet::const_iterator it = m_frames.find(fid); |
| if (it == m_frames.end()) |
| return TRasterImageP(); |
| |
| string imageId = getImageId(fid); |
| |
| ImageLoader::BuildExtData extData(this, fid, 1); |
| TImageP img = ImageManager::instance()->getImage(imageId, imFlags, &extData); |
| |
| if (imFlags & ImageManager::toBeModified) { |
| |
| texture_utils::invalidateTexture(this, fid); |
| } |
| |
| return img; |
| } |
| |
| |
| |
| string TXshSimpleLevel::getIconId(const TFrameId &fid, int frameStatus) const |
| { |
| return "icon:" + getImageId(fid, frameStatus); |
| } |
| |
| |
| |
| string TXshSimpleLevel::getIconId(const TFrameId &fid, const TDimension &size) const |
| { |
| return getImageId(fid) + ":" + toString(size.lx) + "x" + toString(size.ly); |
| } |
| |
| |
| |
| namespace |
| { |
| |
| TAffine getAffine(const TDimension &srcSize, const TDimension &dstSize) |
| { |
| double scx = 1 * dstSize.lx / (double)srcSize.lx; |
| double scy = 1 * dstSize.ly / (double)srcSize.ly; |
| double sc = tmin(scx, scy); |
| double dx = (dstSize.lx - srcSize.lx * sc) * 0.5; |
| double dy = (dstSize.ly - srcSize.ly * sc) * 0.5; |
| return TScale(sc) * TTranslation(0.5 * TPointD(srcSize.lx, srcSize.ly) + TPointD(dx, dy)); |
| } |
| |
| |
| |
| |
| TImageP buildIcon(const TImageP &img, const TDimension &size) |
| { |
| TRaster32P raster(size); |
| if (TVectorImageP vi = img) { |
| TOfflineGL *glContext = new TOfflineGL(size); |
| TDimension cameraSize(768, 576); |
| TPalette *vPalette = img->getPalette(); |
| assert(vPalette); |
| const TVectorRenderData rd( |
| getAffine(cameraSize, size), |
| TRect(), |
| vPalette, |
| 0, false); |
| glContext->clear(TPixel32::White); |
| glContext->draw(vi, rd); |
| raster->copy(glContext->getRaster()); |
| delete glContext; |
| } else if (TToonzImageP ti = img) { |
| raster->fill(TPixel32(255, 255, 255, 255)); |
| TRasterCM32P rasCM32 = ti->getRaster(); |
| TRect bbox; |
| bbox = ti->getSavebox(); |
| if (!bbox.isEmpty()) { |
| rasCM32 = rasCM32->extractT(bbox); |
| double sx = raster->getLx() / (double)rasCM32->getLx(); |
| double sy = raster->getLy() / (double)rasCM32->getLy(); |
| double sc = tmin(sx, sy); |
| TAffine aff = TScale(sc).place( |
| rasCM32->getCenterD(), |
| raster->getCenterD()); |
| TRop::resample( |
| raster, |
| rasCM32, |
| ti->getPalette(), |
| aff); |
| raster->lock(); |
| for (int y = 0; y < raster->getLy(); y++) { |
| TPixel32 *pix = raster->pixels(y); |
| TPixel32 *endPix = pix + raster->getLx(); |
| while (pix < endPix) { |
| *pix = overPix(TPixel32::White, *pix); |
| pix++; |
| } |
| } |
| raster->unlock(); |
| } |
| } else { |
| TRasterImageP ri = img; |
| if (ri) { |
| ri->makeIcon(raster); |
| TRop::addBackground(raster, TPixel32::White); |
| } else |
| raster->fill(TPixel32(127, 50, 20)); |
| } |
| |
| return TRasterImageP(raster); |
| } |
| |
| } |
| |
| |
| |
| void TXshSimpleLevel::setFrame(const TFrameId &fid, const TImageP &img) |
| { |
| assert(m_type != UNKNOWN_XSHLEVEL); |
| |
| if (img) |
| img->setPalette(getPalette()); |
| |
| m_frames.insert(fid); |
| |
| TFilePath path = m_path; |
| |
| int frameStatus = getFrameStatus(fid); |
| static const int SCANNED_OR_CLEANUPPED = (Scanned | Cleanupped); |
| |
| if ((frameStatus & SCANNED_OR_CLEANUPPED) == Scanned) |
| path = m_scannedPath; |
| |
| |
| |
| const string &imageId = getImageId(fid); |
| |
| if (!ImageManager::instance()->isBound(imageId)) { |
| const TFilePath &decodedPath = getScene()->decodeFilePath(path); |
| ImageManager::instance()->bind(imageId, new ImageLoader(decodedPath, fid)); |
| } |
| |
| ImageManager::instance()->setImage(imageId, img); |
| |
| if (frameStatus == Normal) { |
| |
| |
| |
| |
| if (m_type == PLI_XSHLEVEL) { |
| const string &imageId2 = rasterized(imageId); |
| if (!ImageManager::instance()->isBound(imageId2)) |
| ImageManager::instance()->bind(imageId2, new ImageRasterizer); |
| else |
| ImageManager::instance()->invalidate(imageId2); |
| } |
| |
| if (m_type == OVL_XSHLEVEL || m_type == TZI_XSHLEVEL) { |
| const string &imageId2 = filled(imageId); |
| if (!ImageManager::instance()->isBound(imageId2)) |
| ImageManager::instance()->bind(imageId2, new ImageFiller); |
| else |
| ImageManager::instance()->invalidate(imageId2); |
| } |
| } |
| } |
| |
| |
| |
| void TXshSimpleLevel::eraseFrame(const TFrameId &fid) |
| { |
| FramesSet::iterator ft = m_frames.find(fid); |
| if (ft == m_frames.end()) |
| return; |
| |
| |
| std::map<TFrameId, TFrameId>::iterator rt, rEnd(m_renumberTable.end()); |
| for (rt = m_renumberTable.begin(); rt != rEnd; ++rt) { |
| if (rt->second == fid) { |
| m_renumberTable.erase(rt->first); |
| break; |
| } |
| } |
| |
| m_frames.erase(ft); |
| getHookSet()->eraseFrame(fid); |
| |
| ImageManager *im = ImageManager::instance(); |
| { |
| im->unbind(getImageId(fid, Normal)); |
| im->unbind(getImageId(fid, Scanned)); |
| im->unbind(getImageId(fid, CleanupPreview)); |
| |
| if (m_type == PLI_XSHLEVEL) |
| im->unbind(rasterized(getImageId(fid))); |
| |
| if (m_type == OVL_XSHLEVEL || m_type == TZI_XSHLEVEL) |
| im->unbind(filled(getImageId(fid))); |
| |
| texture_utils::invalidateTexture(this, fid); |
| } |
| } |
| |
| |
| |
| void TXshSimpleLevel::clearFrames() |
| { |
| ImageManager *im = ImageManager::instance(); |
| |
| |
| FramesSet::iterator ft, fEnd = m_frames.end(); |
| for (ft = m_frames.begin(); ft != fEnd; ++ft) { |
| im->unbind(getImageId(*ft, Scanned)); |
| im->unbind(getImageId(*ft, Cleanupped)); |
| im->unbind(getImageId(*ft, CleanupPreview)); |
| |
| if (m_type == PLI_XSHLEVEL) |
| im->unbind(rasterized(getImageId(*ft))); |
| |
| if (m_type == OVL_XSHLEVEL || m_type == TZI_XSHLEVEL) |
| im->unbind(filled(getImageId(*ft))); |
| |
| texture_utils::invalidateTexture(this, *ft); |
| } |
| |
| |
| m_frames.clear(); |
| m_editableRange.clear(); |
| m_editableRangeUserInfo.clear(); |
| m_renumberTable.clear(); |
| m_framesStatus.clear(); |
| } |
| |
| |
| |
| void TXshSimpleLevel::loadData(TIStream &is) |
| { |
| string tagName; |
| bool flag = false; |
| |
| int type = UNKNOWN_XSHLEVEL; |
| |
| for (;;) { |
| if (is.matchTag(tagName)) { |
| if (tagName == "path") { |
| is >> m_path; |
| is.matchEndTag(); |
| } else if (tagName == "scannedPath") { |
| is >> m_scannedPath; |
| is.matchEndTag(); |
| } else if (tagName == "info") { |
| string v; |
| double xdpi = 0, ydpi = 0; |
| int subsampling = 1; |
| int doPremultiply = 0; |
| int whiteTransp = 0; |
| int antialiasSoftness = 0; |
| LevelProperties::DpiPolicy dpiPolicy = LevelProperties::DP_ImageDpi; |
| if (is.getTagParam("dpix", v)) |
| xdpi = toDouble(v); |
| if (is.getTagParam("dpiy", v)) |
| ydpi = toDouble(v); |
| if (xdpi != 0 && ydpi != 0) |
| dpiPolicy = LevelProperties::DP_CustomDpi; |
| string dpiType = is.getTagAttribute("dpiType"); |
| if (dpiType == "image") |
| dpiPolicy = LevelProperties::DP_ImageDpi; |
| if (is.getTagParam("type", v) && v == "s") |
| type = TZI_XSHLEVEL; |
| if (is.getTagParam("subsampling", v)) |
| subsampling = toInt(v); |
| if (is.getTagParam("premultiply", v)) |
| doPremultiply = toInt(v); |
| if (is.getTagParam("antialias", v)) |
| antialiasSoftness = toInt(v); |
| if (is.getTagParam("whiteTransp", v)) |
| whiteTransp = toInt(v); |
| |
| m_properties->setDpiPolicy(dpiPolicy); |
| m_properties->setDpi(TPointD(xdpi, ydpi)); |
| m_properties->setSubsampling(subsampling); |
| m_properties->setDoPremultiply(doPremultiply); |
| m_properties->setDoAntialias(antialiasSoftness); |
| m_properties->setWhiteTransp(whiteTransp); |
| } else |
| throw TException("unexpected tag " + tagName); |
| } else { |
| if (flag) |
| break; |
| flag = true; |
| wstring token; |
| is >> token; |
| if (token == L"__empty") { |
| |
| is >> token; |
| } |
| |
| if (token == L"_raster") |
| { |
| double xdpi = 1, ydpi = 1; |
| is >> xdpi >> ydpi >> m_name; |
| setName(m_name); |
| type = OVL_XSHLEVEL; |
| m_properties->setDpi(TPointD(xdpi, ydpi)); |
| setType(type); |
| setPath(TFilePath("+drawings/") + (getName() + L"." + toWideString("bmp")), true); |
| } else if (token == L"__raster") |
| { |
| double xdpi = 1, ydpi = 1; |
| string extension; |
| is >> xdpi >> ydpi >> m_name >> extension; |
| setName(m_name); |
| type = OVL_XSHLEVEL; |
| m_properties->setDpi(TPointD(xdpi, ydpi)); |
| setType(type); |
| setPath(TFilePath("+drawings/") + (getName() + L"." + toWideString(extension)), true); |
| } else { |
| m_name = token; |
| setName(m_name); |
| } |
| } |
| } |
| if (type == UNKNOWN_XSHLEVEL) { |
| string ext = m_path.getType(); |
| if (ext == "pli" || ext == "svg") |
| type = PLI_XSHLEVEL; |
| else if (ext == "tlv" || ext == "tzu" || ext == "tzp" || ext == "tzl") |
| type = TZP_XSHLEVEL; |
| else if (ext == "tzi") |
| type = TZI_XSHLEVEL; |
| else if (ext == "mesh") |
| type = MESH_XSHLEVEL; |
| else |
| type = OVL_XSHLEVEL; |
| } |
| setType(type); |
| } |
| |
| |
| |
| namespace |
| { |
| class LoadingLevelRange |
| { |
| public: |
| TFrameId m_fromFid, m_toFid; |
| LoadingLevelRange() : m_fromFid(1), m_toFid(0) {} |
| |
| bool match(const TFrameId &fid) const |
| { |
| |
| return m_fromFid <= fid && fid <= m_toFid || m_fromFid > m_toFid; |
| } |
| bool isEnabled() const |
| { |
| return m_fromFid <= m_toFid; |
| } |
| void reset() |
| { |
| m_fromFid = TFrameId(1); |
| m_toFid = TFrameId(0); |
| } |
| |
| } loadingLevelRange; |
| |
| |
| } |
| |
| |
| void setLoadingLevelRange(const TFrameId &fromFid, const TFrameId &toFid) |
| { |
| loadingLevelRange.m_fromFid = fromFid; |
| loadingLevelRange.m_toFid = toFid; |
| } |
| |
| void getLoadingLevelRange(TFrameId &fromFid, TFrameId &toFid) |
| { |
| fromFid = loadingLevelRange.m_fromFid; |
| toFid = loadingLevelRange.m_toFid; |
| } |
| |
| TFilePath getLevelPathAndSetNameWithPsdLevelName(TXshSimpleLevel *xshLevel) |
| { |
| TFilePath retfp = xshLevel->getPath(); |
| |
| QString name = QString::fromStdWString(retfp.getWideName()); |
| QStringList list = name.split("#"); |
| |
| if (list.size() >= 2 && list.at(1) != "frames") { |
| bool hasLayerId; |
| int layid = list.at(1).toInt(&hasLayerId); |
| |
| if (hasLayerId) { |
| |
| TPSDParser psdparser(xshLevel->getScene()->decodeFilePath(retfp)); |
| std::string levelName = psdparser.getLevelNameWithCounter(layid); |
| |
| list[1] = QString::fromStdString(levelName); |
| |
| std::wstring wLevelName = list.join("#").toStdWString(); |
| retfp = retfp.withName(wLevelName); |
| |
| TLevelSet *levelSet = xshLevel->getScene()->getLevelSet(); |
| if (levelSet && levelSet->hasLevel(wLevelName)) |
| levelSet->renameLevel(xshLevel, wLevelName); |
| |
| xshLevel->setName(wLevelName); |
| } |
| } |
| |
| return retfp; |
| } |
| |
| |
| |
| |
| void TXshSimpleLevel::load() |
| { |
| getProperties()->setCreator(""); |
| QString creator; |
| |
| assert(getScene()); |
| if (!getScene()) |
| return; |
| |
| getProperties()->setDirtyFlag(false); |
| |
| m_isSubsequence = loadingLevelRange.isEnabled(); |
| |
| TFilePath checkpath = getScene()->decodeFilePath(m_path); |
| string type = checkpath.getType(); |
| |
| if (m_scannedPath != TFilePath()) { |
| getProperties()->setDirtyFlag(false); |
| |
| static const int ScannedCleanuppedMask = Scanned | Cleanupped; |
| TFilePath path = getScene()->decodeFilePath(m_scannedPath); |
| if (TSystem::doesExistFileOrLevel(path)) { |
| TLevelReaderP lr(path); |
| assert(lr); |
| TLevelP level = lr->loadInfo(); |
| if (!checkCreatorString(creator = lr->getCreator())) |
| getProperties()->setIsForbidden(true); |
| else |
| for (TLevel::Iterator it = level->begin(); it != level->end(); it++) { |
| TFrameId fid = it->first; |
| if (!loadingLevelRange.match(fid)) |
| continue; |
| setFrameStatus(fid, (getFrameStatus(fid) & ~ScannedCleanuppedMask) | Scanned); |
| setFrame(fid, TImageP()); |
| } |
| } |
| |
| path = getScene()->decodeFilePath(m_path); |
| if (TSystem::doesExistFileOrLevel(path)) { |
| TLevelReaderP lr(path); |
| assert(lr); |
| TLevelP level = lr->loadInfo(); |
| if (getType() & FULLCOLOR_TYPE) |
| setPalette(FullColorPalette::instance()->getPalette(getScene())); |
| else |
| setPalette(level->getPalette()); |
| if (!checkCreatorString(creator = lr->getCreator())) |
| getProperties()->setIsForbidden(true); |
| else |
| for (TLevel::Iterator it = level->begin(); it != level->end(); it++) { |
| TFrameId fid = it->first; |
| if (!loadingLevelRange.match(fid)) |
| continue; |
| setFrameStatus(fid, getFrameStatus(fid) | Cleanupped); |
| setFrame(fid, TImageP()); |
| } |
| setContentHistory(lr->getContentHistory() ? lr->getContentHistory()->clone() : 0); |
| } |
| |
| } else { |
| |
| |
| if (m_path.getType() == "psd" && this->getScene()->getVersionNumber().first < 71) |
| m_path = getLevelPathAndSetNameWithPsdLevelName(this); |
| |
| TFilePath path = getScene()->decodeFilePath(m_path); |
| |
| getProperties()->setDirtyFlag(false); |
| |
| TLevelReaderP lr(path); |
| assert(lr); |
| |
| TLevelP level = lr->loadInfo(); |
| if (level->getFrameCount() > 0) { |
| const TImageInfo *info = lr->getImageInfo(level->begin()->first); |
| |
| if (info && info->m_samplePerPixel >= 5) { |
| QString msg = QString("Failed to open %1.\nSamples per pixel is more than 4. It may containt more than one alpha channel.").arg(QString::fromStdWString(m_path.getWideString())); |
| QMessageBox::warning(0, "Image format not supported", msg); |
| return; |
| } |
| |
| if (info) |
| set16BitChannelLevel(info->m_bitsPerSample == 16); |
| } |
| if ((getType() & FULLCOLOR_TYPE) && !is16BitChannelLevel()) |
| setPalette(FullColorPalette::instance()->getPalette(getScene())); |
| else |
| setPalette(level->getPalette()); |
| |
| if (!checkCreatorString(creator = lr->getCreator())) |
| getProperties()->setIsForbidden(true); |
| else |
| for (TLevel::Iterator it = level->begin(); it != level->end(); it++) { |
| m_renumberTable[it->first] = it->first; |
| if (!loadingLevelRange.match(it->first)) |
| continue; |
| setFrame(it->first, TImageP()); |
| } |
| |
| setContentHistory(lr->getContentHistory() ? lr->getContentHistory()->clone() : 0); |
| } |
| getProperties()->setCreator(creator.toStdString()); |
| |
| loadingLevelRange.reset(); |
| if (getType() != PLI_XSHLEVEL) { |
| if (m_properties->getImageDpi() == TPointD() && !m_frames.empty()) { |
| TDimension imageRes(0, 0); |
| TPointD imageDpi; |
| |
| const TFrameId &firstFid = getFirstFid(); |
| string imageId = getImageId(firstFid); |
| |
| const TImageInfo *imageInfo = ImageManager::instance()->getInfo(imageId, ImageManager::none, 0); |
| if (imageInfo) { |
| imageRes.lx = imageInfo->m_lx; |
| imageRes.ly = imageInfo->m_ly; |
| imageDpi.x = imageInfo->m_dpix; |
| imageDpi.y = imageInfo->m_dpiy; |
| m_properties->setImageDpi(imageDpi); |
| m_properties->setImageRes(imageRes); |
| m_properties->setBpp(imageInfo->m_bitsPerSample * imageInfo->m_samplePerPixel); |
| } |
| } |
| setRenumberTable(); |
| } |
| |
| if (getPalette() && StudioPalette::isEnabled()) |
| StudioPalette::instance()->updateLinkedColors(getPalette()); |
| |
| TFilePath refImgName; |
| if (m_palette) { |
| refImgName = m_palette->getRefImgPath(); |
| TFilePath refImgPath = refImgName; |
| if (refImgName != TFilePath() && |
| TFileStatus(refImgPath).doesExist()) { |
| TLevelReaderP lr(refImgPath); |
| if (lr) { |
| TLevelP level = lr->loadInfo(); |
| if (level->getFrameCount() > 0) { |
| TImageP img = lr->getFrameReader(level->begin()->first)->load(); |
| if (img && getPalette()) { |
| img->setPalette(0); |
| getPalette()->setRefImg(img); |
| std::vector<TFrameId> fids; |
| for (TLevel::Iterator it = level->begin(); it != level->end(); ++it) |
| fids.push_back(it->first); |
| getPalette()->setRefLevelFids(fids); |
| } |
| } |
| } |
| } |
| } |
| |
| |
| HookSet *hookSet = getHookSet(); |
| hookSet->clearHooks(); |
| |
| const TFilePath &hookFile = TXshSimpleLevel::getExistingHookFile( |
| getScene()->decodeFilePath(m_path)); |
| |
| if (!hookFile.isEmpty()) { |
| TIStream is(hookFile); |
| string tagName; |
| try { |
| if (is.matchTag(tagName) && tagName == "hooks") |
| hookSet->loadData(is); |
| } catch (...) { |
| } |
| } |
| updateReadOnly(); |
| } |
| |
| |
| |
| void TXshSimpleLevel::load(const std::vector<TFrameId> &fIds) |
| { |
| |
| getProperties()->setCreator(""); |
| QString creator; |
| assert(getScene()); |
| getProperties()->setDirtyFlag(false); |
| |
| m_isSubsequence = loadingLevelRange.isEnabled(); |
| |
| |
| TFilePath path = getScene()->decodeFilePath(m_path); |
| |
| TLevelReaderP lr(path); |
| assert(lr); |
| |
| if (!checkCreatorString(creator = lr->getCreator())) |
| getProperties()->setIsForbidden(true); |
| else { |
| if (fIds.size() != 0) { |
| for (int i = 0; i < (int)fIds.size(); i++) { |
| m_renumberTable[fIds[i]] = fIds[i]; |
| if (!loadingLevelRange.match(fIds[i])) |
| continue; |
| setFrame(fIds[i], TImageP()); |
| } |
| } else { |
| TLevelP level = lr->loadInfo(); |
| for (TLevel::Iterator it = level->begin(); it != level->end(); it++) { |
| m_renumberTable[it->first] = it->first; |
| if (!loadingLevelRange.match(it->first)) |
| continue; |
| setFrame(it->first, TImageP()); |
| } |
| } |
| } |
| |
| setContentHistory(lr->getContentHistory() ? lr->getContentHistory()->clone() : 0); |
| |
| getProperties()->setCreator(creator.toStdString()); |
| |
| loadingLevelRange.reset(); |
| |
| if (getType() != PLI_XSHLEVEL) { |
| if (m_properties->getImageDpi() == TPointD() && !m_frames.empty()) { |
| TDimension imageRes(0, 0); |
| TPointD imageDpi; |
| string imageId = getImageId(getFirstFid()); |
| const TImageInfo *imageInfo = ImageManager::instance()->getInfo(imageId, ImageManager::none, 0); |
| if (imageInfo) { |
| imageRes.lx = imageInfo->m_lx; |
| imageRes.ly = imageInfo->m_ly; |
| imageDpi.x = imageInfo->m_dpix; |
| imageDpi.y = imageInfo->m_dpiy; |
| m_properties->setImageDpi(imageDpi); |
| m_properties->setImageRes(imageRes); |
| } |
| } |
| setRenumberTable(); |
| } |
| } |
| |
| |
| |
| void TXshSimpleLevel::updateReadOnly() |
| { |
| TFilePath path = getScene()->decodeFilePath(m_path); |
| m_isReadOnly = isAreadOnlyLevel(path); |
| } |
| |
| |
| |
| void TXshSimpleLevel::saveData(TOStream &os) |
| { |
| os << m_name; |
| |
| map<string, string> attr; |
| if (getProperties()->getDpiPolicy() == LevelProperties::DP_CustomDpi) { |
| TPointD dpi = getProperties()->getDpi(); |
| if (dpi.x != 0 && dpi.y != 0) { |
| attr["dpix"] = toString(dpi.x); |
| attr["dpiy"] = toString(dpi.y); |
| } |
| } else { |
| attr["dpiType"] = "image"; |
| } |
| |
| if (getProperties()->getSubsampling() != 1) { |
| attr["subsampling"] = toString(getProperties()->getSubsampling()); |
| } |
| if (getProperties()->antialiasSoftness() > 0) { |
| attr["antialias"] = toString(getProperties()->antialiasSoftness()); |
| } |
| if (getProperties()->doPremultiply()) { |
| attr["premultiply"] = toString(getProperties()->doPremultiply()); |
| } else if (getProperties()->whiteTransp()) { |
| attr["whiteTransp"] = toString(getProperties()->whiteTransp()); |
| } |
| |
| if (m_type == TZI_XSHLEVEL) |
| attr["type"] = "s"; |
| |
| os.openCloseChild("info", attr); |
| |
| os.child("path") << m_path; |
| if (m_scannedPath != TFilePath()) |
| os.child("scannedPath") << m_scannedPath; |
| } |
| |
| |
| |
| void TXshSimpleLevel::save() |
| { |
| assert(getScene()); |
| TFilePath path = getScene()->decodeFilePath(m_path); |
| TSystem::outputDebug("save() : " + toString(m_path) + " = " + toString(path) + "\n"); |
| |
| if (getProperties()->getDirtyFlag() == false && |
| getPalette()->getDirtyFlag() == false && |
| TSystem::doesExistFileOrLevel(path)) |
| return; |
| |
| if (!TFileStatus(path.getParentDir()).doesExist()) { |
| try { |
| TSystem::mkDir(path.getParentDir()); |
| } catch (...) { |
| } |
| } |
| save(path); |
| } |
| |
| |
| |
| void saveBackup(TFilePath path) |
| { |
| try { |
| TFilePath backup = path.withName(path.getName() + "_backup"); |
| if (TSystem::doesExistFileOrLevel(backup)) |
| TSystem::removeFileOrLevel_throw(backup); |
| TSystem::copyFileOrLevel_throw(backup, path); |
| } catch (...) { |
| } |
| } |
| |
| |
| |
| void TXshSimpleLevel::save(const TFilePath &fp, const TFilePath &oldFp, bool overwritePalette) |
| { |
| TFilePath dOldPath = (!oldFp.isEmpty()) ? oldFp : getScene()->decodeFilePath(m_path); |
| |
| TFilePath dDstPath = getScene()->decodeFilePath(fp); |
| TSystem::touchParentDir(dDstPath); |
| |
| |
| if (Preferences::instance()->isLevelsBackupEnabled() && |
| dOldPath == dDstPath && |
| TSystem::doesExistFileOrLevel(dDstPath)) |
| saveBackup(dDstPath); |
| |
| if (isAreadOnlyLevel(dDstPath)) { |
| if (m_editableRange.empty() && !m_temporaryHookMerged) |
| throw TSystemException(dDstPath, "The level cannot be saved: it is a read only level."); |
| else if (getType() != OVL_XSHLEVEL) { |
| |
| wstring fileName = getEditableFileName(); |
| assert(!fileName.empty()); |
| |
| TFilePath app = dDstPath.withName(fileName).withType(dDstPath.getType()); |
| |
| |
| if (TSystem::doesExistFileOrLevel(app)) |
| TSystem::removeFileOrLevel(app); |
| |
| TFilePathSet oldFilePaths; |
| getFiles(app, oldFilePaths); |
| |
| TFilePathSet::iterator it; |
| for (it = oldFilePaths.begin(); it != oldFilePaths.end(); ++it) { |
| if (TSystem::doesExistFileOrLevel(*it)) |
| TSystem::removeFileOrLevel(*it); |
| } |
| |
| |
| TXshSimpleLevel *sl = new TXshSimpleLevel; |
| sl->setScene(getScene()); |
| sl->setPalette(getPalette()); |
| sl->setPath(getScene()->codeFilePath(app)); |
| sl->setType(getType()); |
| |
| set<TFrameId>::iterator eft, efEnd; |
| for (eft = m_editableRange.begin(); eft != efEnd; ++eft) { |
| const TFrameId &fid = *eft; |
| sl->setFrame(fid, getFrame(fid, false)); |
| } |
| |
| |
| HookSet *hookSet = sl->getHookSet(); |
| *hookSet = *getHookSet(); |
| |
| FramesSet::iterator ft, fEnd = m_frames.end(); |
| for (ft = m_frames.begin(); ft != fEnd; ++ft) { |
| const TFrameId &fid = *ft; |
| |
| if (m_editableRange.find(fid) == m_editableRange.end()) |
| hookSet->eraseFrame(fid); |
| } |
| |
| |
| sl->save(app); |
| |
| #ifdef WIN32 |
| |
| |
| oldFilePaths.clear(); |
| |
| if (TSystem::doesExistFileOrLevel(app)) |
| TSystem::hideFileOrLevel(app); |
| |
| getFiles(app, oldFilePaths); |
| |
| for (it = oldFilePaths.begin(); it != oldFilePaths.end(); ++it) { |
| if (TSystem::doesExistFileOrLevel(*it)) |
| TSystem::hideFileOrLevel(*it); |
| } |
| #endif |
| return; |
| } |
| } |
| |
| if (dOldPath != dDstPath && m_path != TFilePath()) { |
| const TFilePath &dSrcPath = dOldPath; |
| |
| try { |
| if (TSystem::doesExistFileOrLevel(dSrcPath)) { |
| if (TSystem::doesExistFileOrLevel(dDstPath)) |
| TSystem::removeFileOrLevel(dDstPath); |
| |
| copyFiles(dDstPath, dSrcPath); |
| } |
| } catch (...) { |
| } |
| } |
| |
| if (overwritePalette && getType() == TZP_XSHLEVEL && getPalette() && getPalette()->getGlobalName() != L"") { |
| overwritePalette = false; |
| TFilePath palettePath = dDstPath.withNoFrame().withType("tpl"); |
| StudioPalette::instance()->save(palettePath, getPalette()); |
| } |
| |
| saveSimpleLevel(dDstPath, overwritePalette); |
| } |
| |
| |
| |
| void TXshSimpleLevel::saveSimpleLevel(const TFilePath &decodedFp, bool overwritePalette) |
| { |
| |
| |
| |
| |
| TFilePath oldPath = m_path; |
| TFilePath dOldPath = getScene()->decodeFilePath(oldPath); |
| |
| |
| struct CopyOnExit { |
| TFilePath &m_dstPath, &m_srcPath; |
| ~CopyOnExit() { m_dstPath = m_srcPath; } |
| } copyOnExit = {m_path = decodedFp, oldPath}; |
| |
| bool savingOriginal = (decodedFp == dOldPath), |
| paletteNotSaved = false; |
| |
| int imFlags = savingOriginal ? ImageManager::dontPutInCache | ImageManager::toBeSaved : ImageManager::dontPutInCache; |
| |
| std::vector<TFrameId> fids; |
| getFids(fids); |
| std::vector<TFrameId>::iterator it; |
| |
| bool isLevelModified = getProperties()->getDirtyFlag(); |
| bool isPaletteModified = false; |
| if (getPalette()) |
| isPaletteModified = getPalette()->getDirtyFlag(); |
| |
| if (isLevelModified || isPaletteModified) { |
| |
| |
| TDimension oldRes(0, 0); |
| |
| if (TSystem::doesExistFileOrLevel(decodedFp)) { |
| TLevelReaderP lr(decodedFp); |
| const TImageInfo *imageInfo = m_frames.empty() ? lr->getImageInfo() : lr->getImageInfo(*(m_frames.begin())); |
| |
| if (imageInfo) { |
| oldRes.lx = imageInfo->m_lx; |
| oldRes.ly = imageInfo->m_ly; |
| lr = TLevelReaderP(); |
| if (getProperties()->getImageRes() != oldRes) { |
| |
| |
| |
| TSystem::removeFileOrLevel(decodedFp); |
| } |
| } |
| } |
| |
| if (decodedFp.getType() == "tlv" && TSystem::doesExistFileOrLevel(decodedFp)) { |
| if (isLevelModified) { |
| |
| |
| |
| |
| int oldSubs = getProperties()->getSubsampling(); |
| |
| TLevelWriterP lw; |
| try { |
| lw = TLevelWriterP(decodedFp); |
| } catch (...) { |
| |
| m_properties->setSubsampling(oldSubs); |
| m_path = oldPath; |
| throw TSystemException(decodedFp, "can't fopen.\nSomeone may be saving the same file. Please wait a while and retry."); |
| } |
| |
| lw->setOverwritePaletteFlag(overwritePalette); |
| |
| lw->setCreator(getCreatorString()); |
| lw->setPalette(getPalette()); |
| |
| |
| |
| std::map<TFrameId, TFrameId> renumberTable; |
| |
| std::map<TFrameId, TFrameId>::reverse_iterator mapIt = m_renumberTable.rbegin(); |
| for (mapIt; mapIt != m_renumberTable.rend(); ++mapIt) { |
| TFrameId id = mapIt->first; |
| if (getFrameStatus(id) != Scanned && getFrameStatus(id) != CleanupPreview) |
| renumberTable[id] = mapIt->second; |
| } |
| |
| m_renumberTable.clear(); |
| m_renumberTable = renumberTable; |
| |
| lw->setIconSize(Preferences::instance()->getIconSize()); |
| if (!isSubsequence()) |
| lw->renumberFids(m_renumberTable); |
| |
| if (getContentHistory()) |
| lw->setContentHistory(getContentHistory()->clone()); |
| |
| ImageLoader::BuildExtData extData(this, TFrameId()); |
| |
| for (it = fids.begin(); it != fids.end(); ++it) { |
| string imageId = getImageId(*it, Normal); |
| if (!ImageManager::instance()->isModified(imageId)) |
| continue; |
| |
| extData.m_fid = *it; |
| TImageP img = ImageManager::instance()->getImage(imageId, imFlags, &extData); |
| |
| assert(img); |
| if (!img) |
| continue; |
| |
| int subs = 1; |
| if (TToonzImageP ti = img) |
| subs = ti->getSubsampling(); |
| else if (TRasterImageP ri = img) |
| subs = ri->getSubsampling(); |
| |
| assert(subs == 1); |
| if (subs != 1) |
| continue; |
| |
| if (TToonzImageP ti = img) { |
| |
| TRect saveBox; |
| TRop::computeBBox(ti->getRaster(), saveBox); |
| ti->setSavebox(saveBox); |
| } |
| |
| lw->getFrameWriter(*it)->save(img); |
| } |
| |
| lw = TLevelWriterP(); |
| } else if (isPaletteModified && overwritePalette) { |
| TFilePath palettePath = decodedFp.withNoFrame().withType("tpl"); |
| if (Preferences::instance()->isLevelsBackupEnabled() && TSystem::doesExistFileOrLevel(palettePath)) |
| saveBackup(palettePath); |
| TOStream os(palettePath); |
| if (os.checkStatus()) |
| os << getPalette(); |
| else |
| paletteNotSaved = true; |
| } |
| } else { |
| |
| LevelUpdater updater(this); |
| updater.getLevelWriter()->setCreator(getCreatorString()); |
| |
| if (isLevelModified) { |
| |
| |
| |
| updater.getLevelWriter()->renumberFids(m_renumberTable); |
| |
| if (!m_editableRange.empty()) |
| fids = vector<TFrameId>(m_editableRange.begin(), m_editableRange.end()); |
| |
| ImageLoader::BuildExtData extData(this, TFrameId()); |
| |
| for (it = fids.begin(); it != fids.end(); ++it) { |
| string imageId = getImageId(*it, Normal); |
| if (!ImageManager::instance()->isModified(imageId)) |
| continue; |
| |
| extData.m_fid = *it; |
| TImageP img = ImageManager::instance()->getImage(imageId, imFlags, &extData); |
| |
| assert(img); |
| if (!img) |
| continue; |
| |
| int subs = 1; |
| if (TToonzImageP ti = img) |
| subs = ti->getSubsampling(); |
| else if (TRasterImageP ri = img) |
| subs = ri->getSubsampling(); |
| |
| assert(subs == 1); |
| if (subs != 1) |
| continue; |
| |
| updater.update(*it, img); |
| } |
| } |
| updater.close(); |
| if ((getType() & FULLCOLOR_TYPE) && isPaletteModified) |
| FullColorPalette::instance()->savePalette(getScene()); |
| } |
| } |
| |
| |
| |
| TFilePath hookFile; |
| HookSet *hookSet = 0; |
| |
| |
| if (getType() == OVL_XSHLEVEL && !m_editableRange.empty()) { |
| hookSet = new HookSet(*getHookSet()); |
| |
| FramesSet::const_iterator it; |
| for (it = m_frames.begin(); it != m_frames.end(); ++it) { |
| TFrameId fid = *it; |
| if (m_editableRange.find(fid) == m_editableRange.end()) |
| hookSet->eraseFrame(fid); |
| } |
| |
| |
| wstring fileName = getEditableFileName(); |
| assert(!fileName.empty()); |
| TFilePath app = decodedFp.withName(fileName).withType(decodedFp.getType()); |
| hookFile = getHookPath(app); |
| } else { |
| hookFile = getHookPath(decodedFp); |
| hookSet = getHookSet(); |
| } |
| |
| #ifdef WIN32 |
| |
| if (getType() == OVL_XSHLEVEL && !m_editableRange.empty()) |
| SetFileAttributesW(hookFile.getWideString().c_str(), FILE_ATTRIBUTE_NORMAL); |
| #endif |
| |
| if (hookSet && hookSet->getHookCount() > 0) { |
| TOStream os(hookFile); |
| os.openChild("hooks"); |
| hookSet->saveData(os); |
| os.closeChild(); |
| } else if (TFileStatus(hookFile).doesExist()) { |
| try { |
| TSystem::deleteFile(hookFile); |
| } catch (...) { |
| } |
| } |
| |
| #ifdef WIN32 |
| if (getType() == OVL_XSHLEVEL && !m_editableRange.empty()) |
| TSystem::hideFileOrLevel(hookFile); |
| #endif |
| |
| if (savingOriginal) { |
| setRenumberTable(); |
| |
| if (m_properties) |
| m_properties->setDirtyFlag(false); |
| |
| if (getPalette() && overwritePalette) |
| getPalette()->setDirtyFlag(false); |
| } |
| |
| if (paletteNotSaved) |
| throw TSystemException(m_path, "The palette of the level could not be saved."); |
| } |
| |
| |
| |
| std::string TXshSimpleLevel::getImageId(const TFrameId &fid, int frameStatus) const |
| { |
| if (frameStatus < 0) |
| frameStatus = getFrameStatus(fid); |
| string prefix = "L"; |
| if (frameStatus & CleanupPreview) |
| prefix = "P"; |
| else if ((frameStatus & (Scanned | Cleanupped)) == Scanned) |
| prefix = "S"; |
| string imageId = m_idBase + "_" + prefix + fid.expand(); |
| return imageId; |
| } |
| |
| |
| |
| int TXshSimpleLevel::getFrameStatus(const TFrameId &fid) const |
| { |
| std::map<TFrameId, int>::const_iterator it = m_framesStatus.find(fid); |
| return (it != m_framesStatus.end()) ? it->second : Normal; |
| } |
| |
| |
| |
| void TXshSimpleLevel::setFrameStatus(const TFrameId &fid, int status) |
| { |
| assert((status & ~(Scanned | Cleanupped | CleanupPreview)) == 0); |
| m_framesStatus[fid] = status; |
| } |
| |
| |
| |
| void TXshSimpleLevel::makeTlv(const TFilePath &tlvPath) |
| { |
| int ltype = getType(); |
| |
| if (!(ltype & FULLCOLOR_TYPE)) { |
| assert(ltype & FULLCOLOR_TYPE); |
| return; |
| } |
| |
| setType(TZP_XSHLEVEL); |
| |
| m_scannedPath = m_path; |
| |
| assert(tlvPath.getType() == "tlv"); |
| m_path = tlvPath; |
| |
| FramesSet::const_iterator it; |
| for (it = m_frames.begin(); it != m_frames.end(); ++it) { |
| TFrameId fid = *it; |
| setFrameStatus(fid, Scanned); |
| ImageManager::instance()->rebind(getImageId(fid, Scanned), getImageId(fid, 0)); |
| ImageManager::instance()->rebind(getIconId(fid, Scanned), getIconId(fid, 0)); |
| } |
| } |
| |
| |
| |
| void TXshSimpleLevel::invalidateFrames() |
| { |
| FramesSet::iterator ft, fEnd = m_frames.end(); |
| for (ft = m_frames.begin(); ft != fEnd; ++ft) |
| ImageManager::instance()->invalidate(getImageId(*ft)); |
| } |
| |
| |
| |
| void TXshSimpleLevel::invalidateFrame(const TFrameId &fid) |
| { |
| string id = getImageId(fid); |
| ImageManager::instance()->invalidate(id); |
| } |
| |
| |
| |
| |
| TImageP TXshSimpleLevel::createEmptyFrame() |
| { |
| TImageP result; |
| |
| switch (m_type) { |
| case PLI_XSHLEVEL: |
| result = new TVectorImage; |
| |
| CASE MESH_XSHLEVEL : assert(false); |
| |
| DEFAULT : { |
| |
| |
| |
| |
| TPointD dpi = getProperties()->getImageDpi(); |
| |
| |
| |
| |
| |
| |
| |
| TDimension res = getProperties()->getImageRes(); |
| |
| if (m_type == TZP_XSHLEVEL) { |
| TRasterCM32P raster(res); |
| raster->fill(TPixelCM32()); |
| TToonzImageP ti(raster, TRect()); |
| ti->setDpi(dpi.x, dpi.y); |
| ti->setSavebox(TRect(0, 0, res.lx - 1, res.ly - 1)); |
| |
| result = ti; |
| } else { |
| TRaster32P raster(res); |
| raster->fill(TPixel32(0, 0, 0, 0)); |
| TRasterImageP ri(raster); |
| ri->setDpi(dpi.x, dpi.y); |
| |
| result = ri; |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| |
| |
| |
| TDimension TXshSimpleLevel::getResolution() |
| { |
| if (isEmpty() || getType() == PLI_XSHLEVEL) |
| return TDimension(); |
| return m_properties->getImageRes(); |
| } |
| |
| |
| |
| |
| TPointD TXshSimpleLevel::getImageDpi(const TFrameId &fid, int frameStatus) |
| { |
| if (isEmpty() || getType() == PLI_XSHLEVEL) |
| return TPointD(); |
| |
| const TFrameId &theFid = (fid == TFrameId::NO_FRAME || !isFid(fid)) ? getFirstFid() : fid; |
| const string &imageId = getImageId(theFid, frameStatus); |
| |
| const TImageInfo *imageInfo = ImageManager::instance()->getInfo(imageId, ImageManager::none, 0); |
| |
| if (!imageInfo) |
| return TPointD(); |
| |
| return TPointD(imageInfo->m_dpix, imageInfo->m_dpiy); |
| } |
| |
| |
| |
| int TXshSimpleLevel::getImageSubsampling(const TFrameId &fid) const |
| { |
| if (isEmpty() || getType() == PLI_XSHLEVEL) |
| return 1; |
| TImageP img = TImageCache::instance()->get(getImageId(fid), false); |
| if (!img) |
| return 1; |
| if (TRasterImageP ri = img) |
| return ri->getSubsampling(); |
| if (TToonzImageP ti = img) |
| return ti->getSubsampling(); |
| return 1; |
| } |
| |
| |
| |
| |
| TPointD TXshSimpleLevel::getDpi(const TFrameId &fid, int frameStatus) |
| { |
| TPointD dpi; |
| if (m_properties->getDpiPolicy() == LevelProperties::DP_ImageDpi) |
| dpi = getImageDpi(fid, frameStatus); |
| else |
| dpi = m_properties->getDpi(); |
| return dpi; |
| } |
| |
| |
| |
| void TXshSimpleLevel::renumber(const std::vector<TFrameId> &fids) |
| { |
| assert(fids.size() == m_frames.size()); |
| int n = fids.size(); |
| |
| int i = 0; |
| std::vector<TFrameId> oldFids; |
| getFids(oldFids); |
| std::map<TFrameId, TFrameId> table; |
| std::map<TFrameId, TFrameId> newRenumberTable; |
| for (std::vector<TFrameId>::iterator it = oldFids.begin(); it != oldFids.end(); ++it) { |
| TFrameId oldFrameId = *it; |
| TFrameId newFrameId = fids[i++]; |
| table[oldFrameId] = newFrameId; |
| std::map<TFrameId, TFrameId>::iterator mapIt = m_renumberTable.begin(); |
| for (mapIt; mapIt != m_renumberTable.end(); ++mapIt) |
| if (mapIt->second == oldFrameId) { |
| newRenumberTable[mapIt->first] = newFrameId; |
| break; |
| } |
| } |
| std::map<TFrameId, TFrameId>::iterator newMapIt = newRenumberTable.begin(); |
| for (newMapIt; newMapIt != newRenumberTable.end(); ++newMapIt) |
| m_renumberTable[newMapIt->first] = newMapIt->second; |
| |
| m_frames.clear(); |
| for (i = 0; i < n; ++i) { |
| TFrameId fid(fids[i]); |
| assert(m_frames.count(fid) == 0); |
| m_frames.insert(fid); |
| } |
| |
| ImageManager *im = ImageManager::instance(); |
| |
| std::map<TFrameId, TFrameId>::iterator jt; |
| |
| { |
| for (i = 0, jt = table.begin(); jt != table.end(); ++jt, ++i) |
| im->rebind(getImageId(jt->first), "^" + toString(i)); |
| |
| for (i = 0, jt = table.begin(); jt != table.end(); ++jt, ++i) |
| im->rebind("^" + toString(i), getImageId(jt->second)); |
| } |
| |
| if (getType() == PLI_XSHLEVEL) { |
| for (i = 0, jt = table.begin(); jt != table.end(); ++jt, ++i) { |
| const std::string &id = rasterized(getImageId(jt->first)); |
| if (im->isBound(id)) |
| im->rebind(id, rasterized("^" + toString(i))); |
| } |
| for (i = 0, jt = table.begin(); jt != table.end(); ++jt, ++i) { |
| const std::string &id = rasterized("^" + toString(i)); |
| if (im->isBound(id)) |
| im->rebind(id, rasterized(getImageId(jt->second))); |
| } |
| } |
| |
| if (getType() & FULLCOLOR_TYPE) { |
| for (i = 0, jt = table.begin(); jt != table.end(); ++jt, ++i) { |
| const std::string &id = filled(getImageId(jt->first)); |
| if (im->isBound(id)) |
| im->rebind(id, filled("^" + toString(i))); |
| } |
| for (i = 0, jt = table.begin(); jt != table.end(); ++jt, ++i) { |
| const std::string &id = filled("^" + toString(i)); |
| if (im->isBound(id)) |
| im->rebind(id, filled(getImageId(jt->second))); |
| } |
| } |
| |
| m_properties->setDirtyFlag(true); |
| |
| if (getHookSet()) |
| getHookSet()->renumber(table); |
| } |
| |
| |
| |
| void TXshSimpleLevel::copyFiles(const TFilePath &dst, const TFilePath &src) |
| { |
| if (dst == src) |
| return; |
| TSystem::touchParentDir(dst); |
| TSystem::copyFileOrLevel_throw(dst, src); |
| if (dst.getType() == "tlv") { |
| |
| TFilePath srcPltPath = src.getParentDir() + TFilePath(src.getWideName() + L".tpl"); |
| if (TFileStatus(srcPltPath).doesExist()) |
| TSystem::copyFile(dst.getParentDir() + TFilePath(dst.getWideName() + L".tpl"), srcPltPath, true); |
| } |
| if (dst.getType() == "tzp" || dst.getType() == "tzu") { |
| |
| TFilePath srcPltPath = src.getParentDir() + TFilePath(src.getWideName() + L".plt"); |
| if (TFileStatus(srcPltPath).doesExist()) |
| TSystem::copyFile(dst.getParentDir() + TFilePath(dst.getWideName() + L".plt"), srcPltPath, true); |
| } |
| |
| const TFilePath &srcHookFile = TXshSimpleLevel::getExistingHookFile(src); |
| if (!srcHookFile.isEmpty()) { |
| const TFilePath &dstHookFile = getHookPath(dst); |
| TSystem::copyFile(dstHookFile, srcHookFile, true); |
| } |
| TFilePath files = src.getParentDir() + (src.getName() + "_files"); |
| if (TFileStatus(files).doesExist() && TFileStatus(files).isDirectory()) |
| TSystem::copyDir(dst.getParentDir() + (src.getName() + "_files"), files); |
| } |
| |
| |
| |
| void TXshSimpleLevel::renameFiles(const TFilePath &dst, const TFilePath &src) |
| { |
| if (dst == src) |
| return; |
| TSystem::touchParentDir(dst); |
| if (TSystem::doesExistFileOrLevel(dst)) |
| TXshSimpleLevel::removeFiles(dst); |
| TSystem::renameFileOrLevel_throw(dst, src); |
| if (dst.getType() == "tlv") |
| TSystem::renameFile(dst.withType("tpl"), src.withType("tpl")); |
| |
| const TFilePath &srcHookFile = TXshSimpleLevel::getExistingHookFile(src); |
| if (!srcHookFile.isEmpty()) { |
| const TFilePath &dstHookFile = getHookPath(dst); |
| TSystem::renameFile(dstHookFile, srcHookFile); |
| } |
| |
| TFilePath files = src.getParentDir() + (src.getName() + "_files"); |
| if (TFileStatus(files).doesExist() && TFileStatus(files).isDirectory()) |
| TSystem::renameFile(dst.getParentDir() + (dst.getName() + "_files"), files); |
| } |
| |
| |
| |
| void TXshSimpleLevel::removeFiles(const TFilePath &fp) |
| { |
| TSystem::moveFileOrLevelToRecycleBin(fp); |
| if (fp.getType() == "tlv") { |
| TFilePath tpl = fp.withType("tpl"); |
| if (TFileStatus(tpl).doesExist()) |
| TSystem::moveFileToRecycleBin(tpl); |
| } |
| |
| |
| const QStringList &hookFiles = TXshSimpleLevel::getHookFiles(fp); |
| |
| int f, fCount = hookFiles.size(); |
| for (f = 0; f != fCount; ++f) |
| TSystem::moveFileToRecycleBin(TFilePath(hookFiles[f].toStdWString())); |
| |
| TFilePath files = fp.getParentDir() + (fp.getName() + "_files"); |
| if (TFileStatus(files).doesExist() && TFileStatus(files).isDirectory()) |
| TSystem::rmDirTree(files); |
| } |
| |
| |
| |
| void TXshSimpleLevel::getFiles(const TFilePath &fp, TFilePathSet &fpset) |
| { |
| if (fp.getType() == "tlv") { |
| TFilePath tpl = fp.withType("tpl"); |
| if (TFileStatus(tpl).doesExist()) |
| fpset.push_back(tpl); |
| } |
| |
| |
| |
| |
| const TFilePath &hookFile = getExistingHookFile(fp); |
| if (!hookFile.isEmpty()) |
| fpset.push_back(hookFile); |
| |
| |
| |
| |
| |
| |
| } |
| |
| |
| |
| void TXshSimpleLevel::setContentHistory(TContentHistory *contentHistory) |
| { |
| if (contentHistory != m_contentHistory.get()) |
| m_contentHistory.reset(contentHistory); |
| } |
| |
| |
| |
| void TXshSimpleLevel::setCompatibilityMasks(int writeMask, int neededMask, int forbiddenMask) |
| { |
| compatibility.writeMask = writeMask; |
| compatibility.neededMask = neededMask; |
| compatibility.forbiddenMask = forbiddenMask; |
| } |
| |
| |
| |
| TFilePath TXshSimpleLevel::getHookPath(const TFilePath &path) |
| { |
| |
| |
| |
| |
| |
| |
| |
| return TFilePath(path.withName(path.getName() + "_hooks").getWideString() + L".xml"); |
| } |
| |
| |
| |
| QStringList TXshSimpleLevel::getHookFiles(const TFilePath &decodedLevelPath) |
| { |
| const TFilePath &dirPath = decodedLevelPath.getParentDir(); |
| QDir levelDir(QString::fromStdWString(dirPath.getWideString())); |
| |
| QStringList hookFileFilter(QString::fromStdWString( |
| decodedLevelPath.getWideName() + L"_hooks*.xml")); |
| |
| return levelDir.entryList( |
| hookFileFilter, QDir::Files | QDir::NoDotAndDotDot, |
| QDir::Time); |
| } |
| |
| |
| |
| TFilePath TXshSimpleLevel::getExistingHookFile(const TFilePath &decodedLevelPath) |
| { |
| static const int pCount = 3; |
| static const QRegExp pattern[pCount] = { |
| |
| QRegExp(".*\\.\\.?.+\\.xml$"), |
| QRegExp(".*\\.xml$"), |
| QRegExp(".*\\.\\.?xml$") |
| }; |
| |
| struct locals { |
| |
| static inline int getPattern(const QString &fp) |
| { |
| for (int p = 0; p != pCount; ++p) |
| if (pattern[p].exactMatch(fp)) |
| return p; |
| return -1; |
| } |
| }; |
| |
| const QStringList &hookFiles = getHookFiles(decodedLevelPath); |
| if (hookFiles.empty()) |
| return TFilePath(); |
| |
| |
| |
| int fPattern, p = pCount, h = -1; |
| |
| int f, fCount = hookFiles.size(); |
| for (f = 0; f != fCount; ++f) { |
| fPattern = locals::getPattern(hookFiles[f]); |
| if (fPattern < p) |
| p = fPattern, h = f; |
| } |
| |
| assert(h >= 0); |
| return (h < 0) ? TFilePath() : decodedLevelPath.getParentDir() + TFilePath(hookFiles[h].toStdWString()); |
| } |
| |
| |
| |
| TRectD TXshSimpleLevel::getBBox(const TFrameId &fid) const |
| { |
| TRectD bbox; |
| double dpiX = Stage::inch, dpiY = dpiX; |
| |
| |
| switch (getType()) { |
| case PLI_XSHLEVEL: |
| case MESH_XSHLEVEL: { |
| |
| TImageP img = getFrame(fid, false); |
| if (!img) |
| return TRectD(); |
| |
| bbox = img->getBBox(); |
| |
| if (TMeshImageP mi = img) |
| mi->getDpi(dpiX, dpiY); |
| } |
| |
| DEFAULT : { |
| |
| const std::string &imageId = getImageId(fid); |
| |
| const TImageInfo *info = ImageManager::instance()->getInfo(imageId, ImageManager::none, 0); |
| if (!info) |
| return TRectD(); |
| |
| bbox = |
| TRectD(TPointD(info->m_x0, info->m_y0), TDimensionD(info->m_lx, info->m_ly)) - |
| 0.5 * TPointD(info->m_lx, info->m_ly); |
| |
| if (info->m_dpix > 0.0 && info->m_dpiy > 0.0) |
| dpiX = info->m_dpix, dpiY = info->m_dpiy; |
| } |
| } |
| |
| |
| return TScale(1.0 / dpiX, 1.0 / dpiY) * bbox; |
| } |
| |