| |
| |
| #include "tiio_tzl.h" |
| #include "tmachine.h" |
| #include "tsystem.h" |
| #include "ttoonzimage.h" |
| #include "tstream.h" |
| #include "tfilepath_io.h" |
| #include "tpixelcm.h" |
| #include "tpalette.h" |
| #include "tcodec.h" |
| #include <stdio.h> |
| #include "trastercm.h" |
| #include "timageinfo.h" |
| #include "timagecache.h" |
| #include "tcontenthistory.h" |
| #include "tropcm.h" |
| #include "tenv.h" |
| #include "tconvert.h" |
| #include "trasterimage.h" |
| |
| #include <QByteArray> |
| |
| #if !defined(TNZ_LITTLE_ENDIAN) |
| TNZ_LITTLE_ENDIAN undefined !! |
| #endif |
| |
| const int CURRENT_VERSION = 14; |
| const int CREATOR_LENGTH = 40; |
| |
| namespace { |
| |
| char *reverse(char *buffer, int size) { |
| char *start = buffer; |
| char *end = start + size; |
| while (start < --end) { |
| char tmp = *start; |
| *start++ = *end; |
| *end = tmp; |
| } |
| return buffer; |
| } |
| } |
| |
| int tfwrite(const char *data, const unsigned int count, FILE *f) { |
| return fwrite(data, sizeof(char), count, f); |
| } |
| |
| int tfwrite(UCHAR *data, const unsigned int count, FILE *f) { |
| return fwrite(data, sizeof(char), count, f); |
| } |
| |
| int tfwrite(TINT32 *data, const unsigned int count, FILE *f) { |
| if (count == 1) { |
| #if !TNZ_LITTLE_ENDIAN |
| TUINT32 dataToWrite = swapTINT32(*data); |
| #else |
| TUINT32 dataToWrite = *data; |
| #endif |
| return fwrite(&dataToWrite, sizeof(TINT32), 1, f); |
| } |
| assert(0); |
| return 0; |
| } |
| |
| int tfwrite(TUINT32 *data, const unsigned int count, FILE *f) { |
| if (count == 1) { |
| #if !TNZ_LITTLE_ENDIAN |
| TUINT32 dataToWrite = swapTINT32(*data); |
| #else |
| TUINT32 dataToWrite = *data; |
| #endif |
| return fwrite(&dataToWrite, sizeof(TINT32), 1, f); |
| } |
| assert(0); |
| return 0; |
| } |
| |
| int tfwrite(double *data, unsigned int count, FILE *f) { |
| if (count == 1) { |
| double v = *data; |
| char *ptr = (char *)&v; |
| #if !TNZ_LITTLE_ENDIAN |
| ptr = reverse((char *)&v, sizeof(double)); |
| #endif |
| return fwrite(ptr, sizeof(double), 1, f); |
| } |
| assert(0); |
| return 0; |
| } |
| |
| |
| |
| |
| |
| |
| |
| namespace { |
| |
| bool erasedFrame; |
| |
| bool writeVersionAndCreator(FILE *chan, const char *version, QString creator) { |
| if (!chan) return false; |
| tfwrite(version, strlen(version), chan); |
| |
| |
| char s[CREATOR_LENGTH]; |
| if (creator.length() == 0) creator = "UNKNOWN"; |
| memset(s, 0, sizeof s); |
| if (creator.length() > CREATOR_LENGTH - 1) |
| #if QT_VERSION >= 0x050000 |
| memcpy(s, creator.toLatin1(), CREATOR_LENGTH - 1); |
| #else |
| memcpy(s, creator.toAscii(), CREATOR_LENGTH - 1); |
| #endif |
| else |
| #if QT_VERSION >= 0x050000 |
| memcpy(s, creator.toLatin1(), creator.length()); |
| #else |
| memcpy(s, creator.toAscii(), creator.length()); |
| #endif |
| tfwrite(s, CREATOR_LENGTH, chan); |
| |
| return true; |
| } |
| |
| bool readVersion(FILE *chan, int &version) { |
| char magic[8]; |
| memset(magic, 0, sizeof(magic)); |
| fread(&magic, sizeof(char), 8, chan); |
| if (std::string(magic).substr(0, 5) == "TLV10") |
| version = 10; |
| else if (std::string(magic, 5) == "TLV11") |
| version = 11; |
| else if (std::string(magic, 5) == "TLV12") |
| version = 12; |
| else if (std::string(magic, 5) == "TLV13") |
| version = 13; |
| else if (std::string(magic, 5) == "TLV14") |
| version = 14; |
| else { |
| fclose(chan); |
| chan = 0; |
| return false; |
| } |
| return true; |
| } |
| |
| bool readHeaderAndOffsets(FILE *chan, TzlOffsetMap &frameOffsTable, |
| TzlOffsetMap &iconOffsTable, TDimension &res, |
| int &version, QString &creator, TINT32 *_frameCount, |
| TINT32 *_offsetTablePos, TINT32 *_iconOffsetTablePos, |
| TLevelP level) { |
| TINT32 hdrSize; |
| TINT32 lx = 0, ly = 0, frameCount = 0; |
| char codec[4]; |
| TINT32 offsetTablePos; |
| TINT32 iconOffsetTablePos; |
| |
| |
| assert(frameOffsTable.empty()); |
| assert(iconOffsTable.empty()); |
| |
| if (!readVersion(chan, version)) return false; |
| |
| |
| if (version == 14) { |
| char buffer[CREATOR_LENGTH + 1]; |
| memset(buffer, 0, sizeof buffer); |
| fread(&buffer, sizeof(char), CREATOR_LENGTH, chan); |
| creator = buffer; |
| } |
| |
| fread(&hdrSize, sizeof(TINT32), 1, chan); |
| fread(&lx, sizeof(TINT32), 1, chan); |
| fread(&ly, sizeof(TINT32), 1, chan); |
| fread(&frameCount, sizeof(TINT32), 1, chan); |
| |
| if (version > 10) { |
| fread(&offsetTablePos, sizeof(TINT32), 1, chan); |
| fread(&iconOffsetTablePos, sizeof(TINT32), 1, chan); |
| #if !TNZ_LITTLE_ENDIAN |
| offsetTablePos = swapTINT32(offsetTablePos); |
| iconOffsetTablePos = swapTINT32(iconOffsetTablePos); |
| #endif |
| } |
| |
| fread(&codec, 4, 1, chan); |
| |
| #if !TNZ_LITTLE_ENDIAN |
| hdrSize = swapTINT32(hdrSize); |
| lx = swapTINT32(lx); |
| ly = swapTINT32(ly); |
| frameCount = swapTINT32(frameCount); |
| #endif |
| assert(0 < frameCount && frameCount < 60000); |
| |
| if (version > 10 && offsetTablePos != 0 && iconOffsetTablePos != 0) { |
| |
| assert(frameCount > 0); |
| |
| fseek(chan, offsetTablePos, SEEK_SET); |
| TFrameId oldFid(TFrameId::EMPTY_FRAME); |
| for (int i = 0; i < (int)frameCount; i++) { |
| TINT32 number, offs, length; |
| char letter; |
| fread(&number, sizeof(TINT32), 1, chan); |
| fread(&letter, sizeof(char), 1, chan); |
| fread(&offs, sizeof(TINT32), 1, chan); |
| if (version >= 12) fread(&length, sizeof(TINT32), 1, chan); |
| |
| #if !TNZ_LITTLE_ENDIAN |
| number = swapTINT32(number); |
| offs = swapTINT32(offs); |
| if (version == 12) length = swapTINT32(length); |
| #endif |
| |
| |
| |
| TFrameId fid(number, letter); |
| |
| |
| if (version >= 12) { |
| frameOffsTable[fid] = TzlChunk(offs, length); |
| } else { |
| frameOffsTable[fid] = TzlChunk(offs, 0); |
| if (i > 0) { |
| frameOffsTable[oldFid].m_length = |
| offs - frameOffsTable[oldFid].m_offs; |
| assert(frameOffsTable[oldFid].m_length > 0); |
| } |
| if (i == frameCount - 1) { |
| frameOffsTable[fid].m_length = offsetTablePos - offs; |
| assert(frameOffsTable[fid].m_length > 0); |
| } |
| } |
| oldFid = fid; |
| if (level) level->setFrame(fid, TImageP()); |
| } |
| if (version >= 13) { |
| |
| fseek(chan, iconOffsetTablePos, SEEK_SET); |
| |
| for (int i = 0; i < (int)frameCount; i++) { |
| TINT32 number, thumbnailOffs, thumbnailLength; |
| char letter; |
| fread(&number, sizeof(TINT32), 1, chan); |
| fread(&letter, sizeof(char), 1, chan); |
| fread(&thumbnailOffs, sizeof(TINT32), 1, chan); |
| fread(&thumbnailLength, sizeof(TINT32), 1, chan); |
| |
| #if !TNZ_LITTLE_ENDIAN |
| number = swapTINT32(number); |
| thumbnailOffs = swapTINT32(thumbnailOffs); |
| thumbnailLength = swapTINT32(thumbnailLength); |
| #endif |
| TFrameId fid(number, letter); |
| iconOffsTable[fid] = TzlChunk(thumbnailOffs, thumbnailLength); |
| } |
| } |
| } else { |
| |
| frameOffsTable[TFrameId(1)] = TzlChunk(ftell(chan), 0); |
| iconOffsTable[TFrameId(1)] = TzlChunk(ftell(chan), 0); |
| int i; |
| for (i = 2; i <= (int)frameCount; i++) { |
| frameOffsTable[TFrameId(i)] = TzlChunk(0, 0); |
| iconOffsTable[TFrameId(i)] = TzlChunk(0, 0); |
| } |
| if (level) |
| for (i = 1; i <= (int)frameCount; i++) |
| level->setFrame(TFrameId(i), TImageP()); |
| } |
| |
| res.lx = lx; |
| res.ly = ly; |
| if (_offsetTablePos) *_offsetTablePos = offsetTablePos; |
| if (_iconOffsetTablePos) *_iconOffsetTablePos = iconOffsetTablePos; |
| |
| if (_frameCount) *_frameCount = frameCount; |
| |
| return true; |
| } |
| } |
| |
| bool adjustIconAspectRatio(TDimension &outDimension, TDimension inDimension, |
| TDimension imageRes) { |
| TINT32 iconLx = inDimension.lx, iconLy = inDimension.ly; |
| assert(iconLx > 0 && iconLy > 0); |
| assert(imageRes.lx > 0 && imageRes.ly > 0); |
| if (iconLx <= 0 || iconLy <= 0 || imageRes.lx <= 0 || imageRes.ly <= 0) |
| return false; |
| int lx = imageRes.lx; |
| int ly = imageRes.ly; |
| |
| if (std::max(double(lx) / inDimension.lx, double(ly) / inDimension.ly) == |
| double(ly) / inDimension.ly) |
| iconLx = tround((double(lx) * inDimension.ly) / ly); |
| else |
| iconLy = tround((double(ly) * inDimension.lx) / lx); |
| outDimension = TDimension(iconLx, iconLy); |
| return true; |
| } |
| |
| void getThumbnail(TRasterP ras, int shrink, TRasterP &thumbnail) { |
| int j = 0; |
| int y = 0; |
| TPixel32 *pix2 = (TPixel32 *)thumbnail->getRawData(); |
| for (j = 0; j < thumbnail->getLy(); j++) { |
| ras->lock(); |
| TPixel32 *pix = (TPixel32 *)ras->getRawData() + y * ras->getLx(); |
| TPixel32 *endPix = pix2 + thumbnail->getLx(); |
| while (pix2 < endPix) { |
| *pix2++ = *pix; |
| pix += shrink; |
| } |
| y += shrink; |
| ras->unlock(); |
| } |
| } |
| |
| |
| |
| class TImageReaderTzl final : public TImageReader { |
| public: |
| TImageReaderTzl(const TFilePath &f, const TFrameId &fid, TLevelReaderTzl *); |
| ~TImageReaderTzl() {} |
| |
| private: |
| |
| TImageReaderTzl(const TImageReaderTzl &); |
| TImageReaderTzl &operator=(const TImageReaderTzl &src); |
| TImageP load10(); |
| TImageP load11(); |
| TImageP load13(); |
| TImageP load14(); |
| const TImageInfo *getImageInfo10() const; |
| const TImageInfo *getImageInfo11() const; |
| |
| public: |
| |
| TFrameId m_fid; |
| TImageP load() override; |
| TImageP loadIcon() override { |
| m_isIcon = true; |
| return load(); |
| } |
| const TImageInfo *getImageInfo() const override; |
| |
| |
| |
| TDimension getSize() const; |
| TRect getBBox() const; |
| |
| private: |
| |
| int m_lx, m_ly; |
| bool m_isIcon; |
| |
| TLevelReaderTzl *m_lrp; |
| }; |
| |
| |
| |
| |
| |
| |
| |
| class TImageWriterTzl final : public TImageWriter { |
| |
| TLevelWriterTzl *m_lwp; |
| TFrameId m_fid; |
| TDimension |
| m_iconSize; |
| |
| |
| |
| public: |
| TImageWriterTzl(TLevelWriterTzl *lw, TFrameId fid) |
| : TImageWriter(TFilePath()) |
| , m_lwp(lw) |
| , m_fid(fid) |
| , m_iconSize(TDimension(80, 60)) {} |
| ~TImageWriterTzl() {} |
| |
| private: |
| |
| TImageWriterTzl(const TImageWriterTzl &); |
| TImageWriterTzl &operator=(const TImageWriterTzl &src); |
| |
| public: |
| void save(const TImageP &img) override { m_lwp->save(img, m_fid); } |
| }; |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| namespace { |
| |
| class Header { |
| public: |
| enum RasType { |
| Raster32RGBM, |
| Raster64RGBM, |
| Raster32CM, |
| RasterGR8, |
| RasterUnknown |
| }; |
| |
| int m_lx; |
| int m_ly; |
| RasType m_rasType; |
| }; |
| |
| } |
| |
| |
| |
| |
| |
| void TLevelWriterTzl::buildFreeChunksTable() { |
| std::set<TzlChunk> occupiedChunks; |
| TzlOffsetMap::const_iterator it1 = m_frameOffsTable.begin(); |
| TINT32 lastOccupiedPos = 0; |
| |
| |
| while (it1 != m_frameOffsTable.end()) { |
| occupiedChunks.insert(TzlChunk(it1->second.m_offs, it1->second.m_length)); |
| if (it1->second.m_offs + it1->second.m_length > lastOccupiedPos) |
| lastOccupiedPos = it1->second.m_offs + it1->second.m_length - 1; |
| it1++; |
| } |
| TzlOffsetMap::const_iterator iconIt1 = m_iconOffsTable.begin(); |
| while (iconIt1 != m_iconOffsTable.end()) { |
| occupiedChunks.insert( |
| TzlChunk(iconIt1->second.m_offs, iconIt1->second.m_length)); |
| if (iconIt1->second.m_offs + iconIt1->second.m_length > lastOccupiedPos) |
| lastOccupiedPos = iconIt1->second.m_offs + iconIt1->second.m_length - 1; |
| iconIt1++; |
| } |
| |
| std::set<TzlChunk>::const_iterator it2 = occupiedChunks.begin(); |
| TINT32 curPos; |
| |
| if (m_version == 13) |
| curPos = 6 * sizeof(TINT32) + 4 * sizeof(char) + 8 * sizeof(char); |
| else if (m_version == 14) |
| curPos = 6 * sizeof(TINT32) + 4 * sizeof(char) + 8 * sizeof(char) + |
| CREATOR_LENGTH * sizeof(char); |
| else |
| curPos = it2->m_offs; |
| |
| while (it2 != occupiedChunks.end()) { |
| assert(it2->m_offs >= curPos); |
| if (it2->m_offs > curPos) |
| m_freeChunks.insert(TzlChunk(curPos, it2->m_offs - curPos)); |
| curPos = it2->m_offs + it2->m_length; |
| it2++; |
| } |
| assert(lastOccupiedPos < m_offsetTablePos); |
| if (lastOccupiedPos + 1 < m_offsetTablePos) |
| m_freeChunks.insert( |
| TzlChunk(lastOccupiedPos + 1, m_offsetTablePos - lastOccupiedPos)); |
| } |
| |
| |
| |
| |
| |
| |
| |
| TLevelWriterTzl::TLevelWriterTzl(const TFilePath &path, TPropertyGroup *info) |
| : TLevelWriter(path, info) |
| , m_headerWritten(false) |
| , m_creatorWritten(false) |
| , m_chan(0) |
| , m_frameCountPos(0) |
| , m_frameCount(0) |
| , m_palette(0) |
| , m_res(0, 0) |
| , m_exists(false) |
| , m_version(CURRENT_VERSION) |
| , m_updatedIconsSize(false) |
| , m_currentIconSize(0, 0) |
| , m_iconSize(TDimension(80, 60)) |
| , m_userIconSize(TDimension(80, 60)) |
| , m_adjustRatio(false) |
| , m_codec(new TRasterCodecLZO("LZO", true)) |
| , m_overwritePaletteFlag(true) { |
| m_path = path; |
| m_palettePath = path.withNoFrame().withType("tpl"); |
| TFileStatus fs(path); |
| m_magic = "TLV14B1a"; |
| erasedFrame = false; |
| |
| |
| |
| |
| |
| |
| if (fs.doesExist()) { |
| |
| m_chan = fopen(path, "rb+"); |
| |
| if (!m_chan) { |
| throw TSystemException(path, "can't fopen."); |
| } |
| |
| if (!readHeaderAndOffsets(m_chan, m_frameOffsTable, m_iconOffsTable, m_res, |
| m_version, m_creator, &m_frameCount, |
| &m_offsetTablePos, &m_iconOffsetTablePos, 0)) { |
| throw TSystemException(path, "can't readHeaderAndOffsets."); |
| } else { |
| if (m_version >= 12) buildFreeChunksTable(); |
| m_headerWritten = true; |
| m_exists = true; |
| if (m_version == 14) |
| m_frameCountPos = 8 + CREATOR_LENGTH + 3 * sizeof(TINT32); |
| else |
| m_frameCountPos = 8 + 3 * sizeof(TINT32); |
| } |
| } |
| if (!m_exists) { |
| TFilePath parentDir = path.getParentDir(); |
| if (!TFileStatus(parentDir).doesExist()) { |
| try { |
| TSystem::mkDir(parentDir); |
| |
| } catch (...) { |
| return; |
| } |
| } |
| m_chan = fopen(path, "wb"); |
| if (!m_chan) return; |
| if (!writeVersionAndCreator(m_chan, m_magic, m_creator)) return; |
| } |
| } |
| |
| |
| |
| TLevelWriterTzl::~TLevelWriterTzl() { |
| if (m_version < CURRENT_VERSION) { |
| if (!convertToLatestVersion()) return; |
| assert(m_version == CURRENT_VERSION); |
| } |
| delete m_codec; |
| |
| TINT32 offsetMapPos = 0; |
| TINT32 iconOffsetMapPos = 0; |
| if (!m_chan) return; |
| |
| assert(m_frameCount == (int)m_frameOffsTable.size()); |
| assert(m_frameCount == (int)m_iconOffsTable.size()); |
| |
| offsetMapPos = (m_exists ? m_offsetTablePos : ftell(m_chan)); |
| fseek(m_chan, offsetMapPos, SEEK_SET); |
| |
| TzlOffsetMap::iterator it = m_frameOffsTable.begin(); |
| for (; it != m_frameOffsTable.end(); ++it) { |
| TFrameId fid = it->first; |
| TINT32 num = fid.getNumber(); |
| char letter = fid.getLetter(); |
| TINT32 offs = it->second.m_offs; |
| TINT32 length = it->second.m_length; |
| tfwrite(&num, 1, m_chan); |
| tfwrite(&letter, 1, m_chan); |
| tfwrite(&offs, 1, m_chan); |
| tfwrite(&length, 1, m_chan); |
| } |
| |
| |
| iconOffsetMapPos = |
| ftell(m_chan); |
| fseek(m_chan, iconOffsetMapPos, SEEK_SET); |
| |
| TzlOffsetMap::iterator iconIt = m_iconOffsTable.begin(); |
| for (; iconIt != m_iconOffsTable.end(); ++iconIt) { |
| TFrameId fid = iconIt->first; |
| TINT32 num = fid.getNumber(); |
| char letter = fid.getLetter(); |
| TINT32 thumbnailOffs = iconIt->second.m_offs; |
| TINT32 thumbnailLength = iconIt->second.m_length; |
| tfwrite(&num, 1, m_chan); |
| tfwrite(&letter, 1, m_chan); |
| tfwrite(&thumbnailOffs, 1, m_chan); |
| tfwrite(&thumbnailLength, 1, m_chan); |
| } |
| |
| fseek(m_chan, m_frameCountPos, SEEK_SET); |
| TINT32 frameCount = m_frameCount; |
| |
| tfwrite(&frameCount, 1, m_chan); |
| tfwrite(&offsetMapPos, 1, m_chan); |
| tfwrite(&iconOffsetMapPos, 1, m_chan); |
| fclose(m_chan); |
| m_chan = 0; |
| |
| if (m_palette && m_overwritePaletteFlag && |
| (m_palette->getDirtyFlag() || |
| !TSystem::doesExistFileOrLevel(m_palettePath))) { |
| TOStream os(m_palettePath); |
| os << m_palette; |
| m_palette->release(); |
| } |
| |
| if (m_contentHistory) { |
| TFilePath historyFp = m_path.withNoFrame().withType("hst"); |
| FILE *historyChan = fopen(historyFp, "w"); |
| if (historyChan) { |
| std::string historyData = m_contentHistory->serialize().toStdString(); |
| fwrite(&historyData[0], 1, historyData.length(), historyChan); |
| fclose(historyChan); |
| } |
| } |
| |
| |
| |
| |
| |
| if (getFreeSpace() > 0.3 || erasedFrame) optimize(); |
| } |
| |
| |
| |
| TImageWriterP TLevelWriterTzl::getFrameWriter(TFrameId fid) { |
| return new TImageWriterTzl(this, fid); |
| } |
| |
| |
| |
| void TLevelWriterTzl::writeHeader(const TDimension &size) { |
| m_headerWritten = true; |
| const char *codec = "LZO "; |
| int codecLen = strlen(codec); |
| TINT32 hdrSize = 3 * sizeof(TINT32) + codecLen; |
| TINT32 lx = size.lx, ly = size.ly, intval = 1; |
| |
| tfwrite(&hdrSize, 1, m_chan); |
| tfwrite(&lx, 1, m_chan); |
| tfwrite(&ly, 1, m_chan); |
| m_frameCountPos = ftell(m_chan); |
| |
| assert(m_frameCountPos == 8 + CREATOR_LENGTH + 3 * sizeof(TINT32)); |
| |
| |
| |
| tfwrite(&intval, 1, m_chan); |
| |
| |
| intval = 0; |
| tfwrite(&intval, 1, m_chan); |
| |
| |
| tfwrite(&intval, 1, m_chan); |
| tfwrite(codec, codecLen, m_chan); |
| } |
| |
| |
| |
| void TLevelWriterTzl::addFreeChunk(TINT32 offs, TINT32 length) { |
| std::set<TzlChunk>::iterator it = m_freeChunks.begin(); |
| while (it != m_freeChunks.end()) { |
| |
| |
| |
| if (it->m_offs + it->m_length == offs) |
| { |
| TzlChunk chunk(it->m_offs, it->m_length + length); |
| m_freeChunks.erase(it); |
| m_freeChunks.insert(chunk); |
| |
| return; |
| } else if (offs + length == it->m_offs) { |
| TzlChunk chunk(offs, it->m_length + length); |
| m_freeChunks.erase(it); |
| m_freeChunks.insert(chunk); |
| |
| |
| return; |
| } |
| it++; |
| } |
| if (it == m_freeChunks.end()) m_freeChunks.insert(TzlChunk(offs, length)); |
| } |
| |
| |
| TINT32 TLevelWriterTzl::findSavingChunk(const TFrameId &fid, TINT32 length, |
| bool isIcon) { |
| TzlOffsetMap::iterator it; |
| |
| |
| if (!isIcon) { |
| if ((it = m_frameOffsTable.find(fid)) != m_frameOffsTable.end()) { |
| addFreeChunk(it->second.m_offs, it->second.m_length); |
| m_frameOffsTable.erase(it); |
| } else |
| m_frameCount++; |
| } else { |
| if ((it = m_iconOffsTable.find(fid)) != m_iconOffsTable.end()) { |
| addFreeChunk(it->second.m_offs, it->second.m_length); |
| m_iconOffsTable.erase(it); |
| } |
| } |
| |
| |
| std::set<TzlChunk>::iterator it1 = m_freeChunks.begin(), |
| found = m_freeChunks.end(); |
| for (; it1 != m_freeChunks.end(); it1++) { |
| |
| |
| if (it1->m_length >= length && |
| (found == m_freeChunks.end() || found->m_length > it1->m_length)) |
| found = it1; |
| } |
| |
| if (found != m_freeChunks.end()) { |
| |
| TINT32 _offset = found->m_offs; |
| if (found->m_length > length) { |
| TzlChunk chunk(found->m_offs + length, found->m_length - length); |
| m_freeChunks.insert(chunk); |
| |
| |
| } else |
| assert(found->m_length == length); |
| m_freeChunks.erase(found); |
| return _offset; |
| } else { |
| m_offsetTablePos += length; |
| return m_offsetTablePos - length; |
| } |
| } |
| |
| bool TLevelWriterTzl::convertToLatestVersion() { |
| TFileStatus fs(m_path); |
| |
| |
| assert(fs.doesExist()); |
| if (!fs.doesExist()) return false; |
| m_exists = false; |
| m_frameCount = 0; |
| m_frameOffsTable = TzlOffsetMap(); |
| m_iconOffsTable = TzlOffsetMap(); |
| m_headerWritten = false; |
| |
| fclose(m_chan); |
| m_chan = 0; |
| |
| std::string tempName = "~" + m_path.getName() + "tmp&.tlv"; |
| TFilePath tempPath = TSystem::getTempDir() + tempName; |
| if (TSystem::doesExistFileOrLevel(m_path)) { |
| assert(m_path != tempPath); |
| if (TSystem::doesExistFileOrLevel(tempPath)) TSystem::deleteFile(tempPath); |
| TSystem::copyFile(tempPath, m_path); |
| } else |
| return false; |
| m_chan = fopen(m_path, "rb+"); |
| if (!m_chan) return false; |
| if (!writeVersionAndCreator(m_chan, m_magic, m_creator)) return false; |
| m_creatorWritten = true; |
| m_version = CURRENT_VERSION; |
| TLevelReaderP lr(tempPath); |
| if (!lr) return false; |
| TLevelP level = lr->loadInfo(); |
| for (TLevel::Iterator it = level->begin(); it != level->end(); ++it) { |
| save(lr->getFrameReader(it->first)->load(), it->first); |
| } |
| lr = TLevelReaderP(); |
| if (TSystem::doesExistFileOrLevel(tempPath)) { |
| TSystem::deleteFile(tempPath); |
| } |
| |
| TINT32 offsetMapPos = 0; |
| TINT32 iconOffsetMapPos = 0; |
| if (!m_chan) return false; |
| |
| assert(m_frameCount == (int)m_frameOffsTable.size()); |
| assert(m_frameCount == (int)m_iconOffsTable.size()); |
| |
| offsetMapPos = (m_exists ? m_offsetTablePos : ftell(m_chan)); |
| fseek(m_chan, offsetMapPos, SEEK_SET); |
| |
| TzlOffsetMap::iterator it2 = m_frameOffsTable.begin(); |
| for (; it2 != m_frameOffsTable.end(); ++it2) { |
| TFrameId fid = it2->first; |
| TINT32 num = fid.getNumber(); |
| char letter = fid.getLetter(); |
| TINT32 offs = it2->second.m_offs; |
| TINT32 length = it2->second.m_length; |
| tfwrite(&num, 1, m_chan); |
| tfwrite(&letter, 1, m_chan); |
| tfwrite(&offs, 1, m_chan); |
| tfwrite(&length, 1, m_chan); |
| } |
| |
| iconOffsetMapPos = ftell(m_chan); |
| fseek(m_chan, iconOffsetMapPos, SEEK_SET); |
| |
| TzlOffsetMap::iterator iconIt = m_iconOffsTable.begin(); |
| for (; iconIt != m_iconOffsTable.end(); ++iconIt) { |
| TFrameId fid = iconIt->first; |
| TINT32 num = fid.getNumber(); |
| char letter = fid.getLetter(); |
| TINT32 thumbnailOffs = iconIt->second.m_offs; |
| TINT32 thumbnailLength = iconIt->second.m_length; |
| tfwrite(&num, 1, m_chan); |
| tfwrite(&letter, 1, m_chan); |
| tfwrite(&thumbnailOffs, 1, m_chan); |
| tfwrite(&thumbnailLength, 1, m_chan); |
| } |
| |
| fseek(m_chan, m_frameCountPos, SEEK_SET); |
| TINT32 frameCount = m_frameCount; |
| tfwrite(&frameCount, 1, m_chan); |
| tfwrite(&offsetMapPos, 1, m_chan); |
| tfwrite(&iconOffsetMapPos, 1, m_chan); |
| m_frameOffsTable = TzlOffsetMap(); |
| m_iconOffsTable = TzlOffsetMap(); |
| m_frameCount = 0; |
| m_res = TDimension(); |
| fclose(m_chan); |
| m_chan = 0; |
| |
| if (m_palette && (m_palette->getDirtyFlag() || |
| !TSystem::doesExistFileOrLevel(m_palettePath))) { |
| TOStream os(m_palettePath); |
| os << m_palette; |
| } |
| |
| |
| |
| m_chan = fopen(m_path, "rb+"); |
| if (!m_chan) return false; |
| if (!readHeaderAndOffsets(m_chan, m_frameOffsTable, m_iconOffsTable, m_res, |
| m_version, m_creator, &m_frameCount, |
| &m_offsetTablePos, &m_iconOffsetTablePos, 0)) |
| return false; |
| m_freeChunks.clear(); |
| buildFreeChunksTable(); |
| m_headerWritten = true; |
| m_exists = true; |
| m_frameCountPos = 8 + CREATOR_LENGTH + 3 * sizeof(TINT32); |
| assert(m_version == CURRENT_VERSION); |
| if (!m_renumberTable.empty()) renumberFids(m_renumberTable); |
| return true; |
| } |
| |
| void TLevelWriterTzl::saveImage(const TImageP &img, const TFrameId &_fid, |
| bool isIcon) { |
| TFrameId fid = _fid; |
| if (!m_chan) return; |
| |
| |
| if (m_version < CURRENT_VERSION) { |
| if (!convertToLatestVersion()) return; |
| assert(m_version == CURRENT_VERSION); |
| } |
| |
| if (!m_updatedIconsSize && m_exists) |
| m_updatedIconsSize = checkIconSize(getIconSize()); |
| |
| TToonzImageP ti = img; |
| if (!ti) return; |
| |
| if (!m_palette) { |
| m_palette = ti->getPalette(); |
| if (m_palette) m_palette->addRef(); |
| } |
| |
| if (!m_creatorWritten) { |
| fseek(m_chan, 0, SEEK_SET); |
| writeVersionAndCreator(m_chan, m_magic, m_creator); |
| m_creatorWritten = true; |
| } |
| if (!m_headerWritten) writeHeader(ti->getSize()); |
| |
| if (m_res != TDimension()) |
| if (!isIcon) |
| assert(m_res == ti->getSize()); |
| else |
| assert(getIconSize() == ti->getSize()); |
| else |
| m_res = ti->getSize(); |
| |
| TRect sb = ti->getSavebox(); |
| |
| TINT32 sbx0 = sb.x0, sby0 = sb.y0, sblx = sb.getLx(), sbly = sb.getLy(); |
| TINT32 buffSize = 0; |
| |
| UCHAR *buff = 0; |
| |
| TRasterP cmras = ti->getRaster(); |
| |
| assert(cmras); |
| |
| if (cmras->getBounds() != sb) { |
| TRect rectToExtract = sb; |
| if (!rectToExtract.isEmpty()) { |
| TRasterP smallRaster = cmras->extract(rectToExtract)->clone(); |
| assert(rectToExtract == sb); |
| cmras = smallRaster; |
| } else { |
| cmras = cmras->create(1, 1); |
| cmras->clear(); |
| } |
| } |
| |
| TRasterGR8P rCompressed = m_codec->compress(cmras, 1, buffSize); |
| if (rCompressed == TRasterGR8P()) { |
| static bool firstTime = true; |
| if (firstTime) { |
| firstTime = false; |
| |
| |
| } |
| return; |
| } |
| |
| rCompressed->lock(); |
| |
| buffSize = rCompressed->getLx(); |
| buff = rCompressed->getRawData(); |
| |
| assert(buffSize); |
| assert(buff); |
| |
| #if !TNZ_LITTLE_ENDIAN |
| |
| Header *header = (Header *)buff; |
| |
| TRasterP ras; |
| m_codec->decompress(buff, buffSize, ras); |
| delete[] buff; |
| assert((TRasterCM32P)ras); |
| assert(ras->getLx() == header->m_lx); |
| assert(ras->getLy() == header->m_ly); |
| |
| for (int y = 0; y < ras->getLy(); ++y) { |
| ras->lock(); |
| TINT32 *pix = ((TINT32 *)ras->getRawData()) + y * ras->getLx(); |
| TINT32 *endPix = pix + ras->getLx(); |
| while (pix < endPix) { |
| *pix = swapTINT32(*pix); |
| pix++; |
| } |
| ras->unlock(); |
| } |
| |
| rCompressed = m_codec->compress(ras, 1, buffSize); |
| |
| header = (Header *)buff; |
| |
| header->m_lx = swapTINT32(header->m_lx); |
| header->m_ly = swapTINT32(header->m_ly); |
| header->m_rasType = (Header::RasType)swapTINT32(header->m_rasType); |
| #endif |
| |
| double xdpi = 1, ydpi = 1; |
| ti->getDpi(xdpi, ydpi); |
| |
| TINT32 theBuffSize = buffSize; |
| |
| TINT32 length = 0; |
| if (!isIcon) |
| length = 5 * sizeof(TINT32) + 2 * sizeof(double) + theBuffSize; |
| else |
| length = 3 * sizeof(TINT32) + theBuffSize; |
| |
| if (fid == TFrameId()) { |
| assert(!m_exists); |
| if (m_frameOffsTable.empty()) |
| fid = (m_frameOffsTable.empty()) |
| ? TFrameId(1, 0) |
| : TFrameId(m_frameOffsTable.rbegin()->first.getNumber() + 1, 0); |
| if (m_iconOffsTable.empty()) |
| fid = (m_iconOffsTable.empty()) |
| ? TFrameId(1, 0) |
| : TFrameId(m_iconOffsTable.rbegin()->first.getNumber() + 1, 0); |
| } |
| |
| if (!m_exists) { |
| long offs = ftell(m_chan); |
| if (!isIcon) { |
| m_frameOffsTable[fid] = TzlChunk(offs, length); |
| m_frameCount++; |
| } else |
| m_iconOffsTable[fid] = TzlChunk(offs, length); |
| |
| } else { |
| long frameOffset = findSavingChunk(fid, length, isIcon); |
| if (!isIcon) |
| m_frameOffsTable[fid] = TzlChunk(frameOffset, length); |
| else |
| m_iconOffsTable[fid] = TzlChunk(frameOffset, length); |
| fseek(m_chan, frameOffset, SEEK_SET); |
| } |
| if (!isIcon) { |
| tfwrite(&sbx0, 1, m_chan); |
| tfwrite(&sby0, 1, m_chan); |
| tfwrite(&sblx, 1, m_chan); |
| tfwrite(&sbly, 1, m_chan); |
| tfwrite(&buffSize, 1, m_chan); |
| tfwrite(&xdpi, 1, m_chan); |
| tfwrite(&ydpi, 1, m_chan); |
| tfwrite(buff, theBuffSize, m_chan); |
| } else { |
| TINT32 iconLx = getIconSize().lx; |
| TINT32 iconLy = getIconSize().ly; |
| tfwrite(&iconLx, 1, m_chan); |
| tfwrite(&iconLy, 1, m_chan); |
| tfwrite(&buffSize, 1, m_chan); |
| tfwrite(buff, theBuffSize, m_chan); |
| } |
| rCompressed->unlock(); |
| |
| |
| |
| |
| } |
| |
| |
| |
| void TLevelWriterTzl::doSave(const TImageP &img, const TFrameId &_fid) { |
| |
| saveImage(img, _fid); |
| if (!img) |
| throw(TException( |
| "Saving tlv: it is not possible to create the image frame.")); |
| |
| TImageP icon = TImageP(); |
| createIcon(img, icon); |
| assert(icon); |
| if (!icon) |
| throw( |
| TException("Saving tlv: it is not possible to create the image icon.")); |
| |
| saveImage(icon, _fid, true); |
| return; |
| } |
| |
| |
| void TLevelWriterTzl::save(const TImageP &img, const TFrameId &fid) { |
| doSave(img, fid); |
| } |
| void TLevelWriterTzl::save(const TImageP &img) { doSave(img, TFrameId()); } |
| |
| void TLevelWriterTzl::saveIcon(const TImageP &img, const TFrameId &fid) { |
| |
| saveImage(img, fid, true); |
| } |
| |
| |
| void TLevelWriterTzl::setPalette(TPalette *palette) { |
| if (!m_palette) { |
| m_palette = palette; |
| m_palette->addRef(); |
| } |
| } |
| |
| void TLevelWriterTzl::renumberFids( |
| const std::map<TFrameId, TFrameId> &renumberTable) { |
| m_renumberTable = renumberTable; |
| if (m_version < 13) return; |
| if (m_frameOffsTable.empty() || !m_exists) return; |
| |
| |
| std::map<TFrameId, TzlChunk> frameOffsTableTemp; |
| frameOffsTableTemp = m_frameOffsTable; |
| TzlOffsetMap::iterator it = frameOffsTableTemp.begin(); |
| while (it != frameOffsTableTemp.end()) { |
| TFrameId fid = it->first; |
| std::map<TFrameId, TFrameId>::const_iterator it2 = renumberTable.find(fid); |
| if (it2 == renumberTable.end()) remove(fid); |
| it++; |
| } |
| |
| std::map<TFrameId, TzlChunk> frameOffsTable, iconOffsTable; |
| |
| std::map<TFrameId, TFrameId>::const_iterator it3 = renumberTable.begin(); |
| while (it3 != renumberTable.end()) { |
| TFrameId fidToRenumber = it3->first; |
| TzlOffsetMap::iterator it = m_frameOffsTable.find(fidToRenumber); |
| TzlOffsetMap::iterator iconIt = m_iconOffsTable.find(fidToRenumber); |
| if (it != m_frameOffsTable.end()) frameOffsTable[it3->second] = it->second; |
| if (m_iconOffsTable.size() > 0 && iconIt != m_iconOffsTable.end()) |
| iconOffsTable[it3->second] = iconIt->second; |
| it3++; |
| } |
| |
| m_frameOffsTable.clear(); |
| m_frameOffsTable = frameOffsTable; |
| m_iconOffsTable.clear(); |
| m_iconOffsTable = iconOffsTable; |
| m_frameCount = m_frameOffsTable.size(); |
| |
| } |
| |
| |
| |
| void TLevelWriterTzl::createIcon(const TImageP &imgIn, TImageP &imgOut) { |
| |
| TToonzImageP ti = imgIn; |
| if (!ti) return; |
| TRect sb = ti->getSavebox(); |
| TINT32 sbx0 = sb.x0, sby0 = sb.y0, sblx = sb.getLx(), sbly = sb.getLy(); |
| TRasterP cmras = ti->getRaster(); |
| |
| assert(m_iconSize.lx > 0 && m_iconSize.ly > 0); |
| if (m_iconSize.lx <= 0 || m_iconSize.ly <= 0) return; |
| TINT32 iconLx = m_iconSize.lx, iconLy = m_iconSize.ly; |
| if (cmras->getLx() <= iconLx && cmras->getLy() <= iconLy) { |
| iconLx = cmras->getLx(); |
| iconLy = cmras->getLy(); |
| m_iconSize = TDimension(iconLx, iconLy); |
| imgOut = imgIn; |
| return; |
| } |
| |
| TRasterCM32P thumbnailRas(iconLx, iconLy); |
| if (iconLx > 0 && iconLy > 0) { |
| |
| TRop::makeIcon(thumbnailRas, TRasterCM32P(cmras)); |
| assert(thumbnailRas); |
| if (!thumbnailRas) return; |
| } |
| |
| if (ti->getSize().lx <= 0 || ti->getSize().ly <= 0) return; |
| TRect tmp_savebox; |
| TRect savebox; |
| TRop::computeBBox(thumbnailRas, tmp_savebox); |
| if (tmp_savebox.isEmpty()) { |
| TINT32 iconsbx0 = tround((double)iconLx * sbx0 / ti->getSize().lx); |
| TINT32 iconsby0 = tround((double)iconLy * sby0 / ti->getSize().ly); |
| TINT32 iconsblx = |
| std::max(tround((double)iconLx * sblx / ti->getSize().lx), 1); |
| TINT32 iconsbly = |
| std::max(tround((double)iconLy * sbly / ti->getSize().ly), 1); |
| savebox = TRect(TPoint(iconsbx0, iconsby0), TDimension(iconsblx, iconsbly)); |
| } else { |
| savebox = tmp_savebox; |
| } |
| |
| if (!TRect(m_iconSize).contains(savebox)) |
| |
| |
| |
| |
| |
| |
| |
| |
| savebox = savebox * TRect(m_iconSize); |
| thumbnailRas->clearOutside(savebox); |
| TToonzImageP ticon(thumbnailRas, savebox); |
| double xdpi = 1, ydpi = 1; |
| ti->getDpi(xdpi, ydpi); |
| ticon->setDpi(xdpi, ydpi); |
| ticon->setPalette(ti->getPalette()); |
| imgOut = TImageP(ticon); |
| } |
| |
| |
| |
| void TLevelWriterTzl::remove(const TFrameId &fid) { |
| TzlOffsetMap::iterator it = m_frameOffsTable.find(fid); |
| |
| if (it == m_frameOffsTable.end()) return; |
| |
| |
| addFreeChunk(it->second.m_offs, it->second.m_length); |
| |
| m_frameOffsTable.erase(it); |
| |
| if (m_iconOffsTable.size() > 0) { |
| TzlOffsetMap::iterator iconIt = m_iconOffsTable.find(fid); |
| |
| assert(iconIt != m_iconOffsTable.end()); |
| if (iconIt == m_iconOffsTable.end()) return; |
| |
| |
| |
| addFreeChunk(iconIt->second.m_offs, iconIt->second.m_length); |
| |
| m_iconOffsTable.erase(iconIt); |
| erasedFrame = true; |
| } |
| } |
| |
| |
| |
| void TLevelWriterTzl::setIconSize(TDimension iconSize) { |
| assert(iconSize.lx > 0 && iconSize.ly > 0); |
| |
| m_iconSize = TDimension(iconSize.lx, iconSize.ly); |
| m_userIconSize = TDimension( |
| iconSize.lx, iconSize.ly); |
| |
| if (m_version >= 13 && m_exists) { |
| |
| |
| |
| |
| if (!m_updatedIconsSize) |
| m_updatedIconsSize = |
| checkIconSize(m_iconSize); |
| |
| if (!m_updatedIconsSize) { |
| |
| |
| m_updatedIconsSize = resizeIcons(m_iconSize); |
| assert(m_updatedIconsSize); |
| } |
| } |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| bool TLevelWriterTzl::checkIconSize(const TDimension &newSize) { |
| assert(m_version >= 13); |
| |
| if (!m_exists || m_iconOffsTable.empty() || !m_chan || m_version < 13) |
| return false; |
| |
| |
| TINT32 iconLx = 0, iconLy = 0; |
| |
| long currentPos = |
| ftell(m_chan); |
| |
| TzlOffsetMap::iterator it = m_iconOffsTable.begin(); |
| long offs = it->second.m_offs; |
| |
| fseek(m_chan, offs, SEEK_SET); |
| |
| fread(&iconLx, sizeof(TINT32), 1, m_chan); |
| fread(&iconLy, sizeof(TINT32), 1, m_chan); |
| |
| fseek(m_chan, currentPos, |
| SEEK_SET); |
| |
| assert(iconLx > 0 && iconLy > 0); |
| if (iconLx <= 0 || iconLy <= 0 || iconLx > m_res.lx || iconLy > m_res.ly) |
| return false; |
| |
| m_currentIconSize = TDimension( |
| iconLx, iconLy); |
| |
| |
| |
| return (m_currentIconSize == newSize); |
| } |
| |
| |
| |
| bool TLevelWriterTzl::resizeIcons(const TDimension &newSize) { |
| if (!m_exists) return false; |
| if (m_iconOffsTable.empty()) return false; |
| if (!m_chan) return false; |
| assert(m_version >= 13); |
| |
| |
| fclose(m_chan); |
| m_chan = 0; |
| TFileStatus fs(m_path); |
| assert(fs.doesExist()); |
| if (!fs.doesExist()) return false; |
| std::string tempName = "~" + m_path.getName() + "tmpIcon&.tlv"; |
| TFilePath tempPath = TSystem::getTempDir() + tempName; |
| if (TSystem::doesExistFileOrLevel(m_path)) { |
| assert(m_path != tempPath); |
| if (TSystem::doesExistFileOrLevel(tempPath)) TSystem::deleteFile(tempPath); |
| TSystem::copyFile(tempPath, m_path); |
| } else |
| return false; |
| m_chan = fopen(m_path, "rb+"); |
| assert(m_chan); |
| |
| assert(TSystem::doesExistFileOrLevel(tempPath)); |
| if (!TSystem::doesExistFileOrLevel(tempPath)) return false; |
| TLevelReaderP lr(tempPath); |
| TLevelP level = lr->loadInfo(); |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| for (TLevel::Iterator it = level->begin(); it != level->end(); ++it) { |
| |
| TImageP img = lr->getFrameReader(it->first)->load(); |
| |
| TImageP icon; |
| createIcon(img, icon); |
| saveIcon(icon, it->first); |
| } |
| |
| |
| lr = TLevelReaderP(); |
| |
| if (TSystem::doesExistFileOrLevel(tempPath)) { |
| TSystem::deleteFile(tempPath); |
| } |
| |
| return true; |
| } |
| |
| float TLevelWriterTzl::getFreeSpace() { |
| if (m_exists && m_version >= 13) { |
| TINT32 freeSpace = 0; |
| std::set<TzlChunk>::iterator it = m_freeChunks.begin(); |
| for (; it != m_freeChunks.end(); ++it) freeSpace += it->m_length; |
| |
| TINT32 totalSpace = 0; |
| if (m_version == 13) |
| totalSpace = m_offsetTablePos - 6 * sizeof(TINT32) - 4 * sizeof(char) - |
| 8 * sizeof(char); |
| else if (m_version == 14) |
| totalSpace = m_offsetTablePos - 6 * sizeof(TINT32) - 4 * sizeof(char) - |
| 8 * sizeof(char) - CREATOR_LENGTH * sizeof(char); |
| assert(totalSpace > 0); |
| return (float)freeSpace / totalSpace; |
| } |
| return 0; |
| } |
| |
| bool TLevelWriterTzl::optimize() { |
| TFileStatus fs(m_path); |
| assert(fs.doesExist()); |
| |
| std::string tempName = "~" + m_path.getName() + "tmp&.tlv"; |
| TFilePath tempPath = |
| TSystem::getTempDir() + tempName; |
| |
| if (TSystem::doesExistFileOrLevel(tempPath)) TSystem::deleteFile(tempPath); |
| |
| TLevelWriterP lw(tempPath); |
| |
| TLevelReaderP lr(m_path); |
| lw->setIconSize(m_userIconSize); |
| TLevelP level = lr->loadInfo(); |
| if (!level || level->getFrameCount() == 0) return false; |
| TLevel::Iterator levelIt = level->begin(); |
| for (levelIt; levelIt != level->end(); ++levelIt) { |
| TToonzImageP img = lr->getFrameReader(levelIt->first)->load(); |
| assert(img); |
| lw->getFrameWriter(levelIt->first)->save(img); |
| } |
| lr = TLevelReaderP(); |
| lw = TLevelWriterP(); |
| |
| |
| |
| if (TSystem::doesExistFileOrLevel(tempPath)) { |
| assert(m_path != tempPath); |
| if (TSystem::doesExistFileOrLevel(m_path)) |
| TSystem::deleteFile(m_path); |
| TSystem::copyFile(m_path, tempPath); |
| TSystem::deleteFile(tempPath); |
| } else |
| return false; |
| return true; |
| } |
| |
| |
| |
| |
| |
| |
| |
| void TLevelReaderTzl::readPalette() { |
| TFilePath pltfp = m_path.withNoFrame().withType("tpl"); |
| TFileStatus fs(pltfp); |
| TPersist *p = 0; |
| TIStream is(pltfp); |
| TPalette *palette = 0; |
| |
| if (is && fs.doesExist()) { |
| is >> p; |
| palette = dynamic_cast<TPalette *>(p); |
| } |
| |
| if (!palette) { |
| int i; |
| palette = new TPalette(); |
| for (i = 1; i < 128 + 32; i++) palette->addStyle(TPixel32(127, 150, 255)); |
| |
| for (i = 0; i < 10; i++) palette->getPage(0)->addStyle(i + 1); |
| for (i = 0; i < 10; i++) palette->getPage(0)->addStyle(128 + i); |
| } |
| if (m_level) m_level->setPalette(palette); |
| } |
| |
| |
| |
| TLevelReaderTzl::TLevelReaderTzl(const TFilePath &path) |
| : TLevelReader(path) |
| , m_chan(0) |
| , m_res(0, 0) |
| , m_xDpi(0) |
| , m_yDpi(0) |
| , m_version(0) |
| , m_frameOffsTable() |
| , m_iconOffsTable() |
| , m_level() |
| , m_readPalette(true) { |
| m_chan = fopen(path, "rb"); |
| |
| if (!m_chan) return; |
| |
| if (!readHeaderAndOffsets(m_chan, m_frameOffsTable, m_iconOffsTable, m_res, |
| m_version, m_creator, 0, 0, 0, m_level)) |
| return; |
| |
| TFilePath historyFp = path.withNoFrame().withType("hst"); |
| FILE *historyChan = fopen(historyFp, "r"); |
| if (historyChan) { |
| |
| fseek(historyChan, 0, SEEK_END); |
| long lSize = ftell(historyChan); |
| rewind(historyChan); |
| std::string historyData(lSize, '\0'); |
| fread(&historyData[0], 1, lSize, historyChan); |
| fclose(historyChan); |
| |
| if (!m_contentHistory) m_contentHistory = new TContentHistory(true); |
| m_contentHistory->deserialize(QString::fromStdString(historyData)); |
| } |
| |
| |
| |
| |
| |
| } |
| |
| |
| |
| void TLevelReaderTzl::doReadPalette(bool doReadIt) { m_readPalette = doReadIt; } |
| |
| |
| |
| TLevelReaderTzl::~TLevelReaderTzl() { |
| if (m_chan) fclose(m_chan); |
| m_chan = 0; |
| } |
| |
| |
| |
| TLevelP TLevelReaderTzl::loadInfo() { |
| if (m_level && m_level->getPalette() == 0 && m_readPalette) readPalette(); |
| return m_level; |
| } |
| |
| |
| |
| TImageReaderP TLevelReaderTzl::getFrameReader(TFrameId fid) { |
| if (m_level && m_level->getPalette() == 0 && m_readPalette) readPalette(); |
| |
| return new TImageReaderTzl(getFilePath(), fid, this); |
| } |
| |
| |
| QString TLevelReaderTzl::getCreator() { |
| if (m_version < 14) return ""; |
| return m_creator; |
| } |
| |
| |
| bool TLevelReaderTzl::getIconSize(TDimension &iconSize) { |
| if (m_iconOffsTable.empty()) return false; |
| if (m_version < 13) return false; |
| assert(m_chan); |
| TINT32 currentPos = ftell(m_chan); |
| TzlOffsetMap::iterator it = m_iconOffsTable.begin(); |
| TINT32 offs = it->second.m_offs; |
| |
| fseek(m_chan, offs, SEEK_SET); |
| TINT32 iconLx = 0, iconLy = 0; |
| |
| fread(&iconLx, sizeof(TINT32), 1, m_chan); |
| fread(&iconLy, sizeof(TINT32), 1, m_chan); |
| assert(iconLx > 0 && iconLy > 0); |
| |
| fseek(m_chan, currentPos, SEEK_SET); |
| iconSize = TDimension(iconLx, iconLy); |
| return true; |
| } |
| |
| |
| |
| |
| |
| |
| |
| TImageReaderTzl::TImageReaderTzl(const TFilePath &f, const TFrameId &fid, |
| TLevelReaderTzl *lr) |
| : TImageReader(f) |
| , m_fid(fid) |
| , m_lrp(lr) |
| , m_lx(lr->m_res.lx) |
| , m_ly(lr->m_res.ly) |
| , m_isIcon(false) {} |
| |
| |
| |
| TImageP TImageReaderTzl::load10() { |
| FILE *chan = m_lrp->m_chan; |
| |
| if (!chan) return TImageP(); |
| |
| |
| TINT32 sbx0, sby0, sblx, sbly; |
| TINT32 actualBuffSize; |
| double xdpi = 1, ydpi = 1; |
| TINT32 imgBuffSize = 0; |
| UCHAR *imgBuff = 0; |
| int frameIndex = m_fid.getNumber(); |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| int k; |
| if (m_lrp->m_frameOffsTable[TFrameId(frameIndex)].m_offs == 0) { |
| int i; |
| for (i = 2; m_lrp->m_frameOffsTable[TFrameId(i)].m_offs != 0 && |
| i <= m_fid.getNumber(); |
| i++) |
| ; |
| if (i == frameIndex) i = 2; |
| |
| fseek(chan, m_lrp->m_frameOffsTable[TFrameId(i - 1)].m_offs, SEEK_SET); |
| k = i - 1; |
| } else { |
| fseek(chan, m_lrp->m_frameOffsTable[TFrameId(frameIndex)].m_offs, SEEK_SET); |
| k = frameIndex; |
| } |
| for (; k <= frameIndex; k++) { |
| m_lrp->m_frameOffsTable[TFrameId(k)] = TzlChunk(ftell(chan), 0); |
| |
| fread(&sbx0, sizeof(TINT32), 1, chan); |
| fread(&sby0, sizeof(TINT32), 1, chan); |
| fread(&sblx, sizeof(TINT32), 1, chan); |
| fread(&sbly, sizeof(TINT32), 1, chan); |
| fread(&actualBuffSize, sizeof(TINT32), 1, chan); |
| fread(&xdpi, sizeof(double), 1, chan); |
| fread(&ydpi, sizeof(double), 1, chan); |
| |
| #if !TNZ_LITTLE_ENDIAN |
| sbx0 = swapTINT32(sbx0); |
| sby0 = swapTINT32(sby0); |
| sblx = swapTINT32(sblx); |
| sbly = swapTINT32(sbly); |
| actualBuffSize = swapTINT32(actualBuffSize); |
| reverse((char *)&xdpi, sizeof(double)); |
| reverse((char *)&ydpi, sizeof(double)); |
| #endif |
| |
| imgBuffSize = m_lx * m_ly * sizeof(TPixelCM32); |
| assert(actualBuffSize <= imgBuffSize); |
| |
| delete[] imgBuff; |
| imgBuff = new UCHAR[imgBuffSize]; |
| |
| fread(imgBuff, actualBuffSize, 1, chan); |
| |
| } |
| |
| Header *header = (Header *)imgBuff; |
| |
| #if !TNZ_LITTLE_ENDIAN |
| header->m_lx = swapTINT32(header->m_lx); |
| header->m_ly = swapTINT32(header->m_ly); |
| header->m_rasType = (Header::RasType)swapTINT32(header->m_rasType); |
| #endif |
| |
| TRasterCodecLZO codec("LZO", false); |
| TRasterP ras; |
| if (!codec.decompress(imgBuff, actualBuffSize, ras, m_safeMode)) |
| return TImageP(); |
| assert((TRasterCM32P)ras); |
| assert(ras->getLx() == header->m_lx); |
| assert(ras->getLy() == header->m_ly); |
| |
| #if !TNZ_LITTLE_ENDIAN |
| ras->lock(); |
| for (int y = 0; y < ras->getLy(); ++y) { |
| TINT32 *pix = ((TINT32 *)ras->getRawData(0, y)); |
| TINT32 *endPix = pix + ras->getLx(); |
| while (pix < endPix) { |
| *pix = swapTINT32(*pix); |
| pix++; |
| } |
| } |
| ras->unlock(); |
| |
| #endif |
| |
| TRect savebox(TPoint(sbx0, sby0), TDimension(sblx, sbly)); |
| TDimension imgSize(m_lrp->m_res.lx, m_lrp->m_res.ly); |
| assert(TRect(imgSize).contains(savebox)); |
| if (imgSize != savebox.getSize() && !savebox.isEmpty()) { |
| assert(TRect(imgSize).contains(savebox)); |
| TRasterCM32P fullRas(imgSize); |
| TPixelCM32 bgColor; |
| fullRas->fillOutside(savebox, bgColor); |
| assert(savebox.getSize() == ras->getSize()); |
| fullRas->extractT(savebox)->copy(ras); |
| ras = fullRas; |
| } |
| |
| delete[] imgBuff; |
| |
| |
| |
| |
| |
| |
| TToonzImageP ti(ras, savebox); |
| |
| ti->setDpi(xdpi, ydpi); |
| |
| ti->setPalette(m_lrp->m_level->getPalette()); |
| |
| |
| return ti; |
| |
| |
| } |
| |
| |
| |
| TImageP TImageReaderTzl::load11() { |
| FILE *chan = m_lrp->m_chan; |
| |
| if (!chan) return TImageP(); |
| |
| |
| TINT32 sbx0, sby0, sblx, sbly; |
| TINT32 actualBuffSize; |
| double xdpi = 1, ydpi = 1; |
| TINT32 imgBuffSize = 0; |
| UCHAR *imgBuff = 0; |
| |
| assert(!m_lrp->m_frameOffsTable.empty()); |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| TzlOffsetMap::iterator it = m_lrp->m_frameOffsTable.find(m_fid); |
| |
| if (it == m_lrp->m_frameOffsTable.end()) return 0; |
| |
| fseek(chan, it->second.m_offs, SEEK_SET); |
| |
| fread(&sbx0, sizeof(TINT32), 1, chan); |
| fread(&sby0, sizeof(TINT32), 1, chan); |
| fread(&sblx, sizeof(TINT32), 1, chan); |
| fread(&sbly, sizeof(TINT32), 1, chan); |
| fread(&actualBuffSize, sizeof(TINT32), 1, chan); |
| |
| fread(&xdpi, sizeof(double), 1, chan); |
| fread(&ydpi, sizeof(double), 1, chan); |
| |
| #if !TNZ_LITTLE_ENDIAN |
| sbx0 = swapTINT32(sbx0); |
| sby0 = swapTINT32(sby0); |
| sblx = swapTINT32(sblx); |
| sbly = swapTINT32(sbly); |
| actualBuffSize = swapTINT32(actualBuffSize); |
| reverse((char *)&xdpi, sizeof(double)); |
| reverse((char *)&ydpi, sizeof(double)); |
| #endif |
| |
| imgBuffSize = m_lx * m_ly * sizeof(TPixelCM32); |
| assert(actualBuffSize <= imgBuffSize); |
| |
| imgBuff = new UCHAR[imgBuffSize]; |
| |
| fread(imgBuff, actualBuffSize, 1, chan); |
| |
| |
| Header *header = (Header *)imgBuff; |
| |
| #if !TNZ_LITTLE_ENDIAN |
| header->m_lx = swapTINT32(header->m_lx); |
| header->m_ly = swapTINT32(header->m_ly); |
| header->m_rasType = (Header::RasType)swapTINT32(header->m_rasType); |
| #endif |
| |
| TRasterCodecLZO codec("LZO", false); |
| TRasterP ras; |
| if (!codec.decompress(imgBuff, actualBuffSize, ras, m_safeMode)) |
| return TImageP(); |
| assert((TRasterCM32P)ras); |
| assert(ras->getLx() == header->m_lx); |
| assert(ras->getLy() == header->m_ly); |
| |
| #if !TNZ_LITTLE_ENDIAN |
| |
| for (int y = 0; y < ras->getLy(); ++y) { |
| ras->lock(); |
| TINT32 *pix = ((TINT32 *)ras->getRawData(0, y)); |
| TINT32 *endPix = pix + ras->getLx(); |
| while (pix < endPix) { |
| *pix = swapTINT32(*pix); |
| pix++; |
| } |
| ras->unlock(); |
| } |
| |
| |
| #endif |
| |
| TRect savebox(TPoint(sbx0, sby0), TDimension(sblx, sbly)); |
| TDimension imgSize(m_lrp->m_res.lx, m_lrp->m_res.ly); |
| assert(TRect(imgSize).contains(savebox)); |
| if (imgSize != savebox.getSize() && !savebox.isEmpty()) { |
| assert(TRect(imgSize).contains(savebox)); |
| TRasterCM32P fullRas(imgSize); |
| TPixelCM32 bgColor; |
| fullRas->fillOutside(savebox, bgColor); |
| assert(savebox.getSize() == ras->getSize()); |
| fullRas->extractT(savebox)->copy(ras); |
| ras = fullRas; |
| } |
| |
| delete[] imgBuff; |
| |
| |
| |
| |
| |
| |
| TToonzImageP ti(ras, savebox); |
| |
| ti->setDpi(xdpi, ydpi); |
| |
| ti->setPalette(m_lrp->m_level->getPalette()); |
| |
| |
| return ti; |
| |
| |
| } |
| |
| |
| |
| TImageP TImageReaderTzl::load13() { |
| FILE *chan = m_lrp->m_chan; |
| |
| if (!chan) return TImageP(); |
| |
| TINT32 sbx0, sby0, sblx, sbly; |
| TINT32 actualBuffSize; |
| double xdpi = 1, ydpi = 1; |
| TINT32 imgBuffSize = 0; |
| UCHAR *imgBuff = 0; |
| TINT32 iconLx = 0, iconLy = 0; |
| assert(!m_lrp->m_frameOffsTable.empty()); |
| assert(!m_lrp->m_iconOffsTable.empty()); |
| TzlOffsetMap::iterator it = m_lrp->m_frameOffsTable.find(m_fid); |
| TzlOffsetMap::iterator iconIt = m_lrp->m_iconOffsTable.find(m_fid); |
| |
| if (it == m_lrp->m_frameOffsTable.end() || |
| iconIt == m_lrp->m_iconOffsTable.end()) |
| return 0; |
| |
| fseek(chan, it->second.m_offs, SEEK_SET); |
| fread(&sbx0, sizeof(TINT32), 1, chan); |
| fread(&sby0, sizeof(TINT32), 1, chan); |
| fread(&sblx, sizeof(TINT32), 1, chan); |
| fread(&sbly, sizeof(TINT32), 1, chan); |
| fread(&actualBuffSize, sizeof(TINT32), 1, chan); |
| fread(&xdpi, sizeof(double), 1, chan); |
| fread(&ydpi, sizeof(double), 1, chan); |
| |
| #if !TNZ_LITTLE_ENDIAN |
| sbx0 = swapTINT32(sbx0); |
| sby0 = swapTINT32(sby0); |
| sblx = swapTINT32(sblx); |
| sbly = swapTINT32(sbly); |
| actualBuffSize = swapTINT32(actualBuffSize); |
| reverse((char *)&xdpi, sizeof(double)); |
| reverse((char *)&ydpi, sizeof(double)); |
| #endif |
| |
| if (m_isIcon) { |
| fseek(chan, iconIt->second.m_offs, SEEK_SET); |
| fread(&iconLx, sizeof(TINT32), 1, chan); |
| fread(&iconLy, sizeof(TINT32), 1, chan); |
| assert(iconLx > 0 && iconLy > 0); |
| if (iconLx <= 0 || iconLy <= 0) throw TException(); |
| fread(&actualBuffSize, sizeof(TINT32), 1, chan); |
| |
| imgBuffSize = (iconLx * iconLy * sizeof(TPixelCM32)); |
| imgBuff = new UCHAR[imgBuffSize]; |
| fread(imgBuff, actualBuffSize, 1, chan); |
| |
| #if !TNZ_LITTLE_ENDIAN |
| Header *header = (Header *)imgBuff; |
| header->m_lx = swapTINT32(header->m_lx); |
| header->m_ly = swapTINT32(header->m_ly); |
| header->m_rasType = (Header::RasType)swapTINT32(header->m_rasType); |
| #endif |
| TRasterCodecLZO codec("LZO", false); |
| TRasterP ras; |
| if (!codec.decompress(imgBuff, actualBuffSize, ras, m_safeMode)) |
| return TImageP(); |
| assert((TRasterCM32P)ras); |
| delete[] imgBuff; |
| |
| #if !TNZ_LITTLE_ENDIAN |
| |
| for (int y = 0; y < ras->getLy(); ++y) { |
| ras->lock(); |
| TINT32 *pix = ((TINT32 *)ras->getRawData(0, y)); |
| TINT32 *endPix = pix + ras->getLx(); |
| while (pix < endPix) { |
| *pix = swapTINT32(*pix); |
| pix++; |
| } |
| ras->unlock(); |
| } |
| #endif |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| TINT32 iconsbx0 = tround((double)iconLx * sbx0 / m_lrp->m_res.lx); |
| TINT32 iconsby0 = |
| tround((double)iconLy * sby0 / |
| m_lrp->m_res.ly); |
| TINT32 iconsblx = tround((double)iconLx * sblx / m_lrp->m_res.lx); |
| TINT32 iconsbly = tround((double)iconLy * sbly / m_lrp->m_res.ly); |
| TRect savebox(TPoint(iconsbx0, iconsby0), TDimension(iconsblx, iconsbly)); |
| |
| |
| |
| |
| |
| |
| TDimension imgSize(iconLx, iconLy); |
| assert(TRect(imgSize).contains(savebox)); |
| |
| if (imgSize != savebox.getSize() && !savebox.isEmpty()) { |
| assert(TRect(imgSize).contains(savebox)); |
| TRasterCM32P fullRas(imgSize); |
| TPixelCM32 bgColor; |
| |
| fullRas->fillOutside(savebox, bgColor); |
| |
| |
| assert(savebox.getSize() == ras->getSize()); |
| fullRas->extractT(savebox)->copy(ras); |
| ras = fullRas; |
| } |
| |
| TToonzImageP ti(ras, savebox); |
| ti->setDpi(xdpi, ydpi); |
| ti->setPalette(m_lrp->m_level->getPalette()); |
| return ti; |
| } |
| |
| TRasterCM32P raux = TRasterCM32P(m_lx, m_ly); |
| raux->lock(); |
| imgBuff = (UCHAR *)raux->getRawData(); |
| |
| |
| |
| |
| |
| |
| fread(imgBuff, actualBuffSize, 1, chan); |
| |
| |
| Header *header = (Header *)imgBuff; |
| |
| #if !TNZ_LITTLE_ENDIAN |
| header->m_lx = swapTINT32(header->m_lx); |
| header->m_ly = swapTINT32(header->m_ly); |
| header->m_rasType = (Header::RasType)swapTINT32(header->m_rasType); |
| #endif |
| |
| TRasterCodecLZO codec("LZO", false); |
| TRasterP ras; |
| if (!codec.decompress(imgBuff, actualBuffSize, ras, m_safeMode)) |
| return TImageP(); |
| assert((TRasterCM32P)ras); |
| assert(ras->getLx() == header->m_lx); |
| assert(ras->getLy() == header->m_ly); |
| |
| #if !TNZ_LITTLE_ENDIAN |
| |
| for (int y = 0; y < ras->getLy(); ++y) { |
| ras->lock(); |
| TINT32 *pix = ((TINT32 *)ras->getRawData(0, y)); |
| TINT32 *endPix = pix + ras->getLx(); |
| while (pix < endPix) { |
| *pix = swapTINT32(*pix); |
| pix++; |
| } |
| ras->unlock(); |
| } |
| |
| |
| #endif |
| |
| TRect savebox(TPoint(sbx0, sby0), TDimension(sblx, sbly)); |
| TDimension imgSize(m_lrp->m_res.lx, m_lrp->m_res.ly); |
| assert(TRect(imgSize).contains(savebox)); |
| if (imgSize != savebox.getSize() && !savebox.isEmpty()) { |
| assert(TRect(imgSize).contains(savebox)); |
| TRasterCM32P fullRas(imgSize); |
| TPixelCM32 bgColor; |
| fullRas->fillOutside(savebox, bgColor); |
| assert(savebox.getSize() == ras->getSize()); |
| fullRas->extractT(savebox)->copy(ras); |
| ras = fullRas; |
| } |
| raux->unlock(); |
| raux = TRasterCM32P(); |
| |
| |
| |
| |
| |
| |
| |
| |
| TToonzImageP ti(ras, savebox); |
| |
| ti->setDpi(xdpi, ydpi); |
| |
| ti->setPalette(m_lrp->m_level->getPalette()); |
| |
| |
| return ti; |
| |
| |
| } |
| |
| |
| TRect applyShrinkAndRegion(TRasterP &ras, int shrink, TRect region, |
| TRect savebox) { |
| |
| if (!region.isEmpty() && region != TRect() && region.getLx() > 0 && |
| region.getLy() > 0) |
| ras = ras->extract(region); |
| else |
| region = TRect(0, 0, ras->getLx() - 1, ras->getLy() - 1); |
| if (shrink > 1) { |
| ras = TRop::shrink(ras, shrink); |
| } |
| |
| savebox *= region; |
| if (savebox == TRect() || savebox.getLx() <= 0 || savebox.getLy() <= 0) |
| return TRect(); |
| int firstColIndexOfLayer = (savebox.x0 - region.x0) - 1 + shrink - |
| (abs(savebox.x0 - region.x0 - 1) % shrink); |
| int firstRowIndexOfLayer = (savebox.y0 - region.y0) - 1 + shrink - |
| (abs(savebox.y0 - region.y0 - 1) % shrink); |
| savebox.x0 = (firstColIndexOfLayer) / shrink; |
| savebox.y0 = (firstRowIndexOfLayer) / shrink; |
| savebox.x1 = savebox.x0 + (savebox.getLx()) / shrink - 1; |
| savebox.y1 = savebox.y0 + (savebox.getLy()) / shrink - 1; |
| return savebox; |
| } |
| |
| |
| |
| TImageP TImageReaderTzl::load14() { |
| FILE *chan = m_lrp->m_chan; |
| |
| if (!chan) return TImageP(); |
| |
| TINT32 sbx0 = 0, sby0 = 0, sblx, sbly; |
| TINT32 actualBuffSize; |
| double xdpi = 1, ydpi = 1; |
| |
| UCHAR *imgBuff = 0; |
| TINT32 iconLx = 0, iconLy = 0; |
| assert(!m_lrp->m_frameOffsTable.empty()); |
| assert(!m_lrp->m_iconOffsTable.empty()); |
| if (m_lrp->m_frameOffsTable.empty()) |
| throw TException("Loading tlv: the frames table is empty."); |
| if (m_lrp->m_iconOffsTable.empty()) |
| throw TException("Loading tlv: the frames icons table is empty."); |
| |
| TzlOffsetMap::iterator it = m_lrp->m_frameOffsTable.find(m_fid); |
| TzlOffsetMap::iterator iconIt = m_lrp->m_iconOffsTable.find(m_fid); |
| if (it == m_lrp->m_frameOffsTable.end() || |
| iconIt == m_lrp->m_iconOffsTable.end()) |
| throw TException("Loading tlv: frame ID not found."); |
| |
| fseek(chan, it->second.m_offs, SEEK_SET); |
| fread(&sbx0, sizeof(TINT32), 1, chan); |
| fread(&sby0, sizeof(TINT32), 1, chan); |
| fread(&sblx, sizeof(TINT32), 1, chan); |
| fread(&sbly, sizeof(TINT32), 1, chan); |
| fread(&actualBuffSize, sizeof(TINT32), 1, chan); |
| fread(&xdpi, sizeof(double), 1, chan); |
| fread(&ydpi, sizeof(double), 1, chan); |
| |
| if (sbx0 < 0 || sby0 < 0 || sblx < 0 || sbly < 0 || sblx > m_lx || |
| sbly > m_ly) |
| throw TException("Loading tlv: savebox dimension error."); |
| |
| #if !TNZ_LITTLE_ENDIAN |
| sbx0 = swapTINT32(sbx0); |
| sby0 = swapTINT32(sby0); |
| sblx = swapTINT32(sblx); |
| sbly = swapTINT32(sbly); |
| actualBuffSize = swapTINT32(actualBuffSize); |
| reverse((char *)&xdpi, sizeof(double)); |
| reverse((char *)&ydpi, sizeof(double)); |
| #endif |
| |
| |
| if (m_isIcon) { |
| fseek(chan, iconIt->second.m_offs, SEEK_SET); |
| fread(&iconLx, sizeof(TINT32), 1, chan); |
| fread(&iconLy, sizeof(TINT32), 1, chan); |
| assert(iconLx > 0 && iconLy > 0); |
| if (iconLx < 0 || iconLy < 0 || iconLx > m_lx || iconLy > m_ly) |
| throw TException("Loading tlv: bad icon size."); |
| fread(&actualBuffSize, sizeof(TINT32), 1, chan); |
| |
| if (actualBuffSize <= 0 || |
| actualBuffSize > (int)(iconLx * iconLx * sizeof(TPixelCM32))) |
| throw TException("Loading tlv: icon buffer size error."); |
| |
| TRasterCM32P raux = TRasterCM32P(iconLx, iconLy); |
| if (!raux) return TImageP(); |
| raux->lock(); |
| imgBuff = (UCHAR *)raux->getRawData(); |
| fread(imgBuff, actualBuffSize, 1, chan); |
| |
| #if !TNZ_LITTLE_ENDIAN |
| Header *header = (Header *)imgBuff; |
| header->m_lx = swapTINT32(header->m_lx); |
| header->m_ly = swapTINT32(header->m_ly); |
| header->m_rasType = (Header::RasType)swapTINT32(header->m_rasType); |
| #endif |
| |
| TRasterCodecLZO codec("LZO", false); |
| TRasterP ras; |
| if (!codec.decompress(imgBuff, actualBuffSize, ras, m_safeMode)) |
| return TImageP(); |
| assert((TRasterCM32P)ras); |
| raux->unlock(); |
| raux = TRasterCM32P(); |
| |
| #if !TNZ_LITTLE_ENDIAN |
| |
| for (int y = 0; y < ras->getLy(); ++y) { |
| ras->lock(); |
| TINT32 *pix = ((TINT32 *)ras->getRawData(0, y)); |
| TINT32 *endPix = pix + ras->getLx(); |
| while (pix < endPix) { |
| *pix = swapTINT32(*pix); |
| pix++; |
| } |
| ras->unlock(); |
| } |
| #endif |
| |
| |
| |
| |
| |
| |
| |
| if (m_lrp->m_res.lx == 0 || m_lrp->m_res.ly == 0) return TImageP(); |
| |
| if (m_lrp->m_res.lx < 0 || m_lrp->m_res.ly < 0) |
| throw TException("Loading tlv: icon resolution error"); |
| |
| TRect tmp_savebox; |
| TRect savebox; |
| TRop::computeBBox(ras, tmp_savebox); |
| if (tmp_savebox.isEmpty()) { |
| TINT32 iconsbx0 = tround((double)iconLx * sbx0 / m_lrp->m_res.lx); |
| TINT32 iconsby0 = tround((double)iconLy * sby0 / m_lrp->m_res.ly); |
| TINT32 iconsblx = |
| std::max(tround((double)iconLx * sblx / m_lrp->m_res.lx), 1); |
| TINT32 iconsbly = |
| std::max(tround((double)iconLy * sbly / m_lrp->m_res.ly), 1); |
| savebox = |
| TRect(TPoint(iconsbx0, iconsby0), TDimension(iconsblx, iconsbly)); |
| } else { |
| TINT32 iconsbx0 = tfloor((double)iconLx * sbx0 / m_lrp->m_res.lx); |
| TINT32 iconsby0 = tfloor((double)iconLy * sby0 / m_lrp->m_res.ly); |
| savebox = TRect(TPoint(iconsbx0, iconsby0), |
| TDimension(tmp_savebox.getLx(), tmp_savebox.getLy())); |
| } |
| |
| |
| |
| |
| |
| |
| TDimension imgSize(iconLx, iconLy); |
| if (!TRect(imgSize).contains( |
| savebox)) |
| savebox = savebox * TRect(imgSize); |
| |
| |
| |
| if (imgSize != savebox.getSize()) { |
| TRasterCM32P fullRas(imgSize); |
| TPixelCM32 bgColor; |
| |
| fullRas->fillOutside(savebox, bgColor); |
| |
| |
| |
| if (savebox.getSize() != ras->getSize()) |
| throw TException("Loading tlv: bad icon savebox size."); |
| fullRas->extractT(savebox)->copy(ras); |
| ras = fullRas; |
| } |
| |
| TToonzImageP ti(ras, savebox); |
| ti->setDpi(xdpi, ydpi); |
| ti->setPalette(m_lrp->m_level->getPalette()); |
| return ti; |
| } |
| if (actualBuffSize <= 0 || |
| actualBuffSize > (int)(m_lx * m_ly * sizeof(TPixelCM32))) |
| throw TException("Loading tlv: buffer size error"); |
| |
| TRasterCM32P raux = TRasterCM32P(m_lx, m_ly); |
| |
| |
| |
| raux->lock(); |
| imgBuff = (UCHAR *)raux->getRawData(); |
| |
| |
| fread(imgBuff, actualBuffSize, 1, chan); |
| |
| |
| Header *header = (Header *)imgBuff; |
| |
| #if !TNZ_LITTLE_ENDIAN |
| header->m_lx = swapTINT32(header->m_lx); |
| header->m_ly = swapTINT32(header->m_ly); |
| header->m_rasType = (Header::RasType)swapTINT32(header->m_rasType); |
| #endif |
| |
| TRasterCodecLZO codec("LZO", false); |
| TRasterP ras; |
| if (!codec.decompress(imgBuff, actualBuffSize, ras, m_safeMode)) |
| return TImageP(); |
| assert((TRasterCM32P)ras); |
| assert(ras->getLx() == header->m_lx); |
| assert(ras->getLy() == header->m_ly); |
| if (ras->getLx() != header->m_lx) |
| throw TException("Loading tlv: lx dimension error."); |
| if (ras->getLy() != header->m_ly) |
| throw TException("Loading tlv: ly dimension error."); |
| raux->unlock(); |
| raux = TRasterCM32P(); |
| |
| #if !TNZ_LITTLE_ENDIAN |
| |
| for (int y = 0; y < ras->getLy(); ++y) { |
| ras->lock(); |
| TINT32 *pix = ((TINT32 *)ras->getRawData(0, y)); |
| TINT32 *endPix = pix + ras->getLx(); |
| while (pix < endPix) { |
| *pix = swapTINT32(*pix); |
| pix++; |
| } |
| ras->unlock(); |
| } |
| |
| |
| #endif |
| |
| TRect savebox(TPoint(sbx0, sby0), TDimension(sblx, sbly)); |
| TDimension imgSize(m_lrp->m_res.lx, m_lrp->m_res.ly); |
| assert(TRect(imgSize).contains(savebox)); |
| if (!TRect(imgSize).contains(savebox)) |
| throw TException("Loading tlv: bad savebox size."); |
| if (imgSize != savebox.getSize()) { |
| TRasterCM32P fullRas(imgSize); |
| TPixelCM32 bgColor; |
| if (!savebox.isEmpty()) { |
| fullRas->fillOutside(savebox, bgColor); |
| assert(savebox.getSize() == ras->getSize()); |
| if (savebox.getSize() != ras->getSize()) |
| throw TException("Loading tlv: bad icon savebox size."); |
| fullRas->extractT(savebox)->copy(ras); |
| } else |
| fullRas->clear(); |
| ras = fullRas; |
| } |
| |
| TToonzImageP ti(ras, savebox); |
| |
| ti->setDpi(xdpi, ydpi); |
| |
| ti->setPalette(m_lrp->m_level->getPalette()); |
| |
| |
| return ti; |
| |
| |
| } |
| |
| |
| |
| TImageP TImageReaderTzl::load() { |
| int version = m_lrp->m_version; |
| TImageP image = TImageP(); |
| switch (version) { |
| case 11: |
| if (!m_lrp->m_frameOffsTable.empty()) image = load11(); |
| break; |
| case 12: |
| if (!m_lrp->m_frameOffsTable.empty()) image = load11(); |
| break; |
| case 13: |
| if (!m_lrp->m_frameOffsTable.empty() && !m_lrp->m_iconOffsTable.empty()) |
| image = load13(); |
| break; |
| case 14: |
| if (!m_lrp->m_frameOffsTable.empty() && !m_lrp->m_iconOffsTable.empty()) |
| image = load14(); |
| break; |
| default: |
| image = load10(); |
| } |
| if (image == TImageP()) return TImageP(); |
| |
| if (!m_isIcon) { |
| TToonzImageP ti = image; |
| if (!ti) return TImageP(); |
| TRasterP ras = ti->getRaster(); |
| TRect savebox = ti->getSavebox(); |
| if (m_region != TRect() && m_region.getLx() > 0 && m_region.getLy() > 0) { |
| m_region *= TRect(0, 0, ti->getSize().lx, ti->getSize().ly); |
| if (m_region.isEmpty() || m_region == TRect() || m_region.getLx() <= 0 || |
| m_region.getLy() <= 0) |
| return TImageP(); |
| } |
| savebox = applyShrinkAndRegion(ras, m_shrink, m_region, savebox); |
| if (savebox == TRect()) { |
| if (m_region != TRect()) { |
| ras = ras->create(m_region.getLx(), m_region.getLy()); |
| ras->clear(); |
| savebox = m_region; |
| } else { |
| |
| } |
| } |
| ti->setCMapped(ras); |
| ti->setSavebox(savebox); |
| return ti; |
| } |
| return image; |
| } |
| |
| |
| const TImageInfo *TImageReaderTzl::getImageInfo11() const { |
| assert(!m_lrp->m_frameOffsTable.empty()); |
| FILE *chan = m_lrp->m_chan; |
| if (!chan) return 0; |
| |
| TzlOffsetMap::iterator it = m_lrp->m_frameOffsTable.find(m_fid); |
| |
| if (it == m_lrp->m_frameOffsTable.end()) return 0; |
| |
| fseek(chan, it->second.m_offs, SEEK_SET); |
| |
| |
| TINT32 sbx0, sby0, sblx, sbly; |
| TINT32 actualBuffSize; |
| double xdpi = 1, ydpi = 1; |
| |
| |
| |
| |
| fread(&sbx0, sizeof(TINT32), 1, chan); |
| fread(&sby0, sizeof(TINT32), 1, chan); |
| fread(&sblx, sizeof(TINT32), 1, chan); |
| fread(&sbly, sizeof(TINT32), 1, chan); |
| fread(&actualBuffSize, sizeof(TINT32), 1, chan); |
| |
| fread(&xdpi, sizeof(double), 1, chan); |
| fread(&ydpi, sizeof(double), 1, chan); |
| |
| #if !TNZ_LITTLE_ENDIAN |
| sbx0 = swapTINT32(sbx0); |
| sby0 = swapTINT32(sby0); |
| sblx = swapTINT32(sblx); |
| sbly = swapTINT32(sbly); |
| actualBuffSize = swapTINT32(actualBuffSize); |
| reverse((char *)&xdpi, sizeof(double)); |
| reverse((char *)&ydpi, sizeof(double)); |
| #endif |
| |
| static TImageInfo info; |
| info.m_x0 = sbx0; |
| info.m_y0 = sby0; |
| info.m_x1 = sbx0 + sblx - 1; |
| info.m_y1 = sby0 + sbly - 1; |
| info.m_lx = m_lx; |
| info.m_ly = m_ly; |
| info.m_dpix = xdpi; |
| info.m_dpiy = ydpi; |
| |
| |
| return &info; |
| } |
| |
| |
| |
| const TImageInfo *TImageReaderTzl::getImageInfo10() const { |
| FILE *chan = m_lrp->m_chan; |
| if (!chan) return 0; |
| |
| |
| TINT32 sbx0, sby0, sblx, sbly; |
| TINT32 actualBuffSize; |
| double xdpi = 1, ydpi = 1; |
| TINT32 imgBuffSize = 0; |
| UCHAR *imgBuff = 0; |
| int frameIndex = m_fid.getNumber(); |
| |
| |
| assert(m_lrp->m_frameOffsTable[TFrameId(1)].m_offs > 0); |
| int k; |
| if (m_lrp->m_frameOffsTable[TFrameId(frameIndex)].m_offs == 0) { |
| int i; |
| for (i = 2; |
| m_lrp->m_frameOffsTable[TFrameId(i)].m_offs != 0 && i <= frameIndex; |
| i++) |
| ; |
| if (i == frameIndex) i = 2; |
| |
| fseek(chan, m_lrp->m_frameOffsTable[TFrameId(i - 1)].m_offs, SEEK_SET); |
| k = i - 1; |
| } else { |
| fseek(chan, m_lrp->m_frameOffsTable[TFrameId(frameIndex)].m_offs, SEEK_SET); |
| k = frameIndex; |
| } |
| |
| for (; k <= frameIndex; k++) { |
| m_lrp->m_frameOffsTable[TFrameId(k)] = TzlChunk(ftell(chan), 0); |
| fread(&sbx0, sizeof(TINT32), 1, chan); |
| fread(&sby0, sizeof(TINT32), 1, chan); |
| fread(&sblx, sizeof(TINT32), 1, chan); |
| fread(&sbly, sizeof(TINT32), 1, chan); |
| fread(&actualBuffSize, sizeof(TINT32), 1, chan); |
| |
| fread(&xdpi, sizeof(double), 1, chan); |
| fread(&ydpi, sizeof(double), 1, chan); |
| |
| #if !TNZ_LITTLE_ENDIAN |
| sbx0 = swapTINT32(sbx0); |
| sby0 = swapTINT32(sby0); |
| sblx = swapTINT32(sblx); |
| sbly = swapTINT32(sbly); |
| actualBuffSize = swapTINT32(actualBuffSize); |
| reverse((char *)&xdpi, sizeof(double)); |
| reverse((char *)&ydpi, sizeof(double)); |
| #endif |
| |
| imgBuffSize = m_lx * m_ly * sizeof(TPixelCM32); |
| assert(actualBuffSize <= imgBuffSize); |
| delete[] imgBuff; |
| imgBuff = new UCHAR[imgBuffSize]; |
| fread(imgBuff, actualBuffSize, 1, chan); |
| } |
| |
| Header *header = (Header *)imgBuff; |
| |
| #if !TNZ_LITTLE_ENDIAN |
| header->m_lx = swapTINT32(header->m_lx); |
| header->m_ly = swapTINT32(header->m_ly); |
| header->m_rasType = (Header::RasType)swapTINT32(header->m_rasType); |
| #endif |
| |
| delete[] imgBuff; |
| |
| static TImageInfo info; |
| info.m_x0 = sbx0; |
| info.m_y0 = sby0; |
| info.m_x1 = sbx0 + sblx - 1; |
| info.m_y1 = sby0 + sbly - 1; |
| info.m_lx = m_lx; |
| info.m_ly = m_ly; |
| info.m_dpix = xdpi; |
| info.m_dpiy = ydpi; |
| |
| |
| return &info; |
| } |
| |
| |
| |
| const TImageInfo *TImageReaderTzl::getImageInfo() const { |
| if (m_lrp->m_version > 10 && !m_lrp->m_frameOffsTable.empty()) |
| return getImageInfo11(); |
| else |
| return getImageInfo10(); |
| } |
| |
| |
| |
| TDimension TImageReaderTzl::getSize() const { return TDimension(m_lx, m_ly); } |
| |
| |
| |
| TRect TImageReaderTzl::getBBox() const { return TRect(getSize()); } |
| |