| |
| |
|
|
| #include "timagecache.h" |
| #include "trasterimage.h" |
| #include "ttoonzimage.h" |
| #include "tmeshimage.h" |
| #include "timage_io.h" |
| |
| |
| #include <QMutex> |
| #include <QMutexLocker> |
| #include <QReadWriteLock> |
| #include <QReadLocker> |
| #include <QWriteLocker> |
| |
| #include "toonz/imagemanager.h" |
| #include "toonz/txshsimplelevel.h" |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| DEFINE_CLASS_CODE(ImageBuilder, 100) |
| |
| |
| |
| ImageBuilder::ImageBuilder() |
| : TSmartObject(m_classCode), m_imageBuildingLock(QReadWriteLock::Recursive), m_cached(false), m_modified(false), m_imFlags(ImageManager::none) |
| { |
| } |
| |
| |
| |
| ImageBuilder::~ImageBuilder() |
| { |
| } |
| |
| |
| |
| bool ImageBuilder::areInfosCompatible(int imFlags, void *extData) |
| { |
| return m_info.m_valid; |
| } |
| |
| |
| |
| bool ImageBuilder::isImageCompatible(int imFlags, void *extData) |
| { |
| return m_info.m_valid; |
| } |
| |
| |
| |
| bool ImageBuilder::setImageInfo(TImageInfo &info, const TDimension &size) |
| { |
| info = TImageInfo(); |
| info.m_lx = size.lx; |
| info.m_ly = size.ly; |
| info.m_x0 = 0; |
| info.m_y0 = 0; |
| info.m_x1 = size.lx - 1; |
| info.m_y1 = size.ly - 1; |
| info.m_valid = true; |
| |
| return true; |
| } |
| |
| |
| |
| bool ImageBuilder::setImageInfo(TImageInfo &info, TImage *img) |
| { |
| info = TImageInfo(); |
| if (TRasterImageP ri = TRasterImageP(img)) { |
| TRasterP ras = ri->getRaster(); |
| info.m_lx = ras->getLx(); |
| info.m_ly = ras->getLy(); |
| ri->getDpi(info.m_dpix, info.m_dpiy); |
| TRect savebox = ri->getSavebox(); |
| info.m_x0 = savebox.x0; |
| info.m_y0 = savebox.y0; |
| info.m_x1 = savebox.x1; |
| info.m_y1 = savebox.y1; |
| } else if (TToonzImageP ti = TToonzImageP(img)) { |
| TRasterP ras = ti->getRaster(); |
| info.m_lx = ras->getLx(); |
| info.m_ly = ras->getLy(); |
| ti->getDpi(info.m_dpix, info.m_dpiy); |
| TRect savebox = ti->getSavebox(); |
| info.m_x0 = savebox.x0; |
| info.m_y0 = savebox.y0; |
| info.m_x1 = savebox.x1; |
| info.m_y1 = savebox.y1; |
| } else if (TMeshImageP mi = TMeshImageP(img)) { |
| mi->getDpi(info.m_dpix, info.m_dpiy); |
| } |
| |
| info.m_valid = true; |
| return true; |
| } |
| |
| |
| |
| bool ImageBuilder::setImageInfo(TImageInfo &info, TImageReader *ir) |
| { |
| info = TImageInfo(); |
| |
| const TImageInfo *tmp = ir->getImageInfo(); |
| if (tmp) { |
| info = *tmp; |
| if (info.m_x1 < info.m_x0 || info.m_y1 < info.m_y0) { |
| info.m_x0 = info.m_y0 = 0; |
| info.m_x1 = info.m_lx - 1; |
| info.m_y1 = info.m_ly - 1; |
| } |
| |
| info.m_valid = true; |
| return true; |
| } |
| |
| return false; |
| } |
| |
| |
| |
| |
| |
| struct ImageManager::Imp { |
| QReadWriteLock m_tableLock; |
| std::map<string, ImageBuilderP> m_builders; |
| |
| public: |
| Imp() : m_tableLock(QReadWriteLock::Recursive) {} |
| |
| void clear() { m_builders.clear(); } |
| }; |
| |
| |
| |
| |
| |
| ImageManager::ImageManager() |
| : m_imp(new Imp) |
| { |
| } |
| |
| |
| |
| ImageManager::~ImageManager() |
| { |
| delete m_imp; |
| } |
| |
| |
| |
| ImageManager *ImageManager::instance() |
| { |
| |
| static ImageManager theInstance; |
| return &theInstance; |
| } |
| |
| |
| |
| void ImageManager::bind(const string &id, ImageBuilder *builderPtr) |
| { |
| if (!builderPtr) { |
| unbind(id); |
| return; |
| } |
| |
| QWriteLocker locker(&m_imp->m_tableLock); |
| |
| ImageBuilderP &builderP = m_imp->m_builders[id]; |
| if (builderP && builderP->m_cached) |
| TImageCache::instance()->remove(id); |
| |
| builderP = builderPtr; |
| } |
| |
| |
| |
| bool ImageManager::unbind(const string &id) |
| { |
| QWriteLocker locker(&m_imp->m_tableLock); |
| |
| std::map<std::string, ImageBuilderP>::iterator it = m_imp->m_builders.find(id); |
| if (it == m_imp->m_builders.end()) |
| return false; |
| |
| ImageBuilderP &builderP = it->second; |
| if (builderP && builderP->m_cached) |
| TImageCache::instance()->remove(id); |
| |
| m_imp->m_builders.erase(it); |
| return true; |
| } |
| |
| |
| |
| bool ImageManager::isBound(const string &id) const |
| { |
| QReadLocker locker(&m_imp->m_tableLock); |
| return m_imp->m_builders.find(id) != m_imp->m_builders.end(); |
| } |
| |
| |
| |
| bool ImageManager::rebind(const string &srcId, const string &dstId) |
| { |
| QWriteLocker locker(&m_imp->m_tableLock); |
| |
| std::map<string, ImageBuilderP>::iterator st = m_imp->m_builders.find(srcId); |
| if (st == m_imp->m_builders.end()) |
| return false; |
| |
| ImageBuilderP builder = st->second; |
| |
| m_imp->m_builders.erase(st); |
| m_imp->m_builders[dstId] = builder; |
| |
| TImageCache::instance()->remap(dstId, srcId); |
| |
| return true; |
| } |
| |
| |
| |
| void ImageManager::clear() |
| { |
| QWriteLocker locker(&m_imp->m_tableLock); |
| |
| TImageCache::instance()->clearSceneImages(); |
| m_imp->clear(); |
| } |
| |
| |
| |
| TImageInfo *ImageManager::getInfo(const string &id, int imFlags, void *extData) |
| { |
| |
| QReadLocker tableLocker(&m_imp->m_tableLock); |
| |
| std::map<string, ImageBuilderP>::iterator it = m_imp->m_builders.find(id); |
| if (it == m_imp->m_builders.end()) |
| return 0; |
| |
| ImageBuilderP &builder = it->second; |
| |
| assert(!((imFlags & ImageManager::toBeModified) && !builder->m_modified)); |
| |
| |
| if (builder->areInfosCompatible(imFlags, extData)) |
| return &builder->m_info; |
| |
| QWriteLocker imageBuildingLocker(&builder->m_imageBuildingLock); |
| |
| |
| if (builder->areInfosCompatible(imFlags, extData)) |
| return &builder->m_info; |
| |
| TImageInfo info; |
| if (builder->getInfo(info, imFlags, extData)) { |
| builder->m_info = info; |
| return &builder->m_info; |
| } |
| |
| return 0; |
| } |
| |
| |
| |
| TImageP ImageManager::getImage(const string &id, int imFlags, void *extData) |
| { |
| assert(!((imFlags & ImageManager::toBeModified) && (imFlags & ImageManager::dontPutInCache))); |
| assert(!((imFlags & ImageManager::toBeModified) && (imFlags & ImageManager::toBeSaved))); |
| |
| |
| QReadLocker tableLocker(&m_imp->m_tableLock); |
| |
| std::map<string, ImageBuilderP>::iterator it = m_imp->m_builders.find(id); |
| if (it == m_imp->m_builders.end()) |
| return TImageP(); |
| |
| ImageBuilderP &builder = it->second; |
| bool modified = builder->m_modified; |
| |
| |
| bool _putInCache = TImageCache::instance()->isEnabled() && !(bool)(imFlags & dontPutInCache); |
| bool _toBeModified = (imFlags & toBeModified); |
| bool _toBeSaved = (imFlags & toBeSaved); |
| |
| |
| if (_toBeModified) |
| builder->m_modified = true; |
| else if (_toBeSaved) |
| builder->m_modified = false; |
| |
| |
| TImageP img; |
| |
| if (builder->m_cached) { |
| if (modified || builder->isImageCompatible(imFlags, extData)) { |
| img = TImageCache::instance()->get(id, _toBeModified); |
| |
| assert(img); |
| if (img) |
| return img; |
| } |
| } |
| |
| |
| QWriteLocker imageBuildingLocker(&builder->m_imageBuildingLock); |
| |
| |
| if (builder->m_cached) { |
| if (modified || builder->isImageCompatible(imFlags, extData)) { |
| img = TImageCache::instance()->get(id, _toBeModified); |
| |
| assert(img); |
| if (img) |
| return img; |
| } |
| } |
| |
| |
| |
| |
| |
| img = builder->build(imFlags, extData); |
| |
| if (img && _putInCache) { |
| builder->m_cached = true; |
| builder->m_modified = _toBeModified; |
| |
| TImageCache::instance()->add(id, img, true); |
| } |
| |
| return img; |
| } |
| |
| |
| |
| void ImageManager::loadAllTlvIconsAndPutInCache(TXshSimpleLevel *level, vector<TFrameId> fids, vector<string> iconIds, bool cacheImagesAsWell) |
| { |
| if (fids.empty() || iconIds.empty()) |
| return; |
| |
| if ((int)fids.size() != (int)iconIds.size()) |
| return; |
| |
| |
| TImageInfo info; |
| std::map<string, ImageBuilderP>::iterator it = m_imp->m_builders.find(level->getImageId(fids[0])); |
| if (it != m_imp->m_builders.end()) { |
| const ImageBuilderP &builder = it->second; |
| assert(builder); |
| assert(builder->getRefCount() > 0); |
| |
| |
| builder->buildAllIconsAndPutInCache(level, fids, iconIds, cacheImagesAsWell); |
| builder->getInfo(info, ImageManager::none, 0); |
| } |
| if (cacheImagesAsWell) { |
| |
| info.m_x0 = info.m_y0 = 0; |
| info.m_x1 = info.m_lx - 1; |
| info.m_y1 = info.m_ly - 1; |
| |
| |
| for (int f = 0; f < fids.size(); f++) { |
| std::map<string, ImageBuilderP>::iterator it = m_imp->m_builders.find(level->getImageId(fids[f])); |
| if (it != m_imp->m_builders.end()) { |
| const ImageBuilderP &builder = it->second; |
| builder->setImageCachedAndModified(); |
| builder->m_info = info; |
| } |
| } |
| } |
| } |
| |
| |
| |
| bool ImageManager::invalidate(const string &id) |
| { |
| QWriteLocker locker(&m_imp->m_tableLock); |
| |
| std::map<string, ImageBuilderP>::iterator it = m_imp->m_builders.find(id); |
| if (it == m_imp->m_builders.end()) |
| return false; |
| |
| ImageBuilderP &builder = it->second; |
| |
| builder->invalidate(); |
| builder->m_cached = builder->m_modified = false; |
| |
| TImageCache::instance()->remove(id); |
| |
| return true; |
| } |
| |
| |
| |
| bool ImageManager::setImage(const string &id, const TImageP &img) |
| { |
| if (!img) |
| return invalidate(id); |
| |
| QWriteLocker locker(&m_imp->m_tableLock); |
| |
| std::map<string, ImageBuilderP>::iterator it = m_imp->m_builders.find(id); |
| if (it == m_imp->m_builders.end()) |
| return false; |
| |
| ImageBuilderP &builder = it->second; |
| |
| builder->invalidate(); |
| ImageBuilder::setImageInfo(builder->m_info, img.getPointer()); |
| |
| TImageCache::instance()->add(id, img, true); |
| builder->m_cached = builder->m_modified = true; |
| |
| return true; |
| } |
| |
| |
| |
| ImageBuilder *ImageManager::getBuilder(const string &id) |
| { |
| QWriteLocker locker(&m_imp->m_tableLock); |
| |
| std::map<string, ImageBuilderP>::iterator it = m_imp->m_builders.find(id); |
| return (it == m_imp->m_builders.end()) ? (ImageBuilder *)0 : it->second.getPointer(); |
| } |
| |
| |
| |
| bool ImageManager::isCached(const string &id) |
| { |
| QWriteLocker locker(&m_imp->m_tableLock); |
| |
| std::map<string, ImageBuilderP>::iterator it = m_imp->m_builders.find(id); |
| return (it == m_imp->m_builders.end()) ? false : it->second->m_cached; |
| } |
| |
| |
| |
| bool ImageManager::isModified(const string &id) |
| { |
| QWriteLocker locker(&m_imp->m_tableLock); |
| |
| std::map<string, ImageBuilderP>::iterator it = m_imp->m_builders.find(id); |
| return (it == m_imp->m_builders.end()) ? false : it->second->m_modified; |
| } |
| |