#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 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;
}
// switch the saving version according to the file path property
int currentVersion() {
if (TFilePath::useStandard()) return 14;
return 15;
}
} // namespace
static int tfwrite(const char *data, const unsigned int count, FILE *f) {
return fwrite(data, sizeof(char), count, f);
}
static int tfwrite(UCHAR *data, const unsigned int count, FILE *f) {
return fwrite(data, sizeof(char), count, f);
}
static 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;
}
static 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;
}
static 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;
}
//===================================================================
//
// TImageReaderTzl
//
//-------------------------------------------------------------------
namespace {
bool erasedFrame; // True if at least one frame has been removed.
bool writeVersionAndCreator(FILE *chan, const char *version, QString creator) {
if (!chan) return false;
tfwrite(version, strlen(version), chan);
// creator : CREATOR_LENGTH character
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 (memcmp(magic, "TLV10", 5) == 0) {
version = 10;
} else if (memcmp(magic, "TLV11", 5) == 0) {
version = 11;
} else if (memcmp(magic, "TLV12", 5) == 0) {
version = 12;
} else if (memcmp(magic, "TLV13", 5) == 0) {
version = 13;
} else if (memcmp(magic, "TLV14", 5) == 0) {
version = 14;
} else if (memcmp(magic, "TLV15", 5) == 0) {
version = 15;
} else {
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;
// char magic[8];
assert(frameOffsTable.empty());
assert(iconOffsTable.empty());
if (!readVersion(chan, version)) return false;
// read creator
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(offsetTablePos>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;
QByteArray suffix;
fread(&number, sizeof(TINT32), 1, chan);
if (version >= 15) {
TINT32 suffixLength;
fread(&suffixLength, sizeof(TINT32), 1, chan);
suffix.resize(suffixLength);
fread(suffix.data(), sizeof(char), suffixLength, chan);
} else {
char letter;
fread(&letter, sizeof(char), 1, chan);
suffix = QByteArray(&letter, 1);
}
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
// std::cout << "#" << i << std::hex << " n 0x" << number
//<< " l 0x" << letter << " o 0x" << offs << std::dec << std::endl;
TFrameId fid(number, QString::fromUtf8(suffix));
// assert(i==0 || oldFid<fid);
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) {
// Build IconOffsetTable
fseek(chan, iconOffsetTablePos, SEEK_SET);
for (int i = 0; i < (int)frameCount; i++) {
TINT32 number, thumbnailOffs, thumbnailLength;
QByteArray suffix;
fread(&number, sizeof(TINT32), 1, chan);
if (version >= 15) {
TINT32 suffixLength;
fread(&suffixLength, sizeof(TINT32), 1, chan);
suffix.resize(suffixLength);
fread(suffix.data(), sizeof(char), suffixLength, chan);
} else {
char letter;
fread(&letter, sizeof(char), 1, chan);
suffix = QByteArray(&letter, 1);
}
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, QString::fromUtf8(suffix));
iconOffsTable[fid] = TzlChunk(thumbnailOffs, thumbnailLength);
}
}
} else {
// m_frameOffsTable.resize(frameCount);
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;
}
} // namespace
static 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;
}
static 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:
// not implemented
TImageReaderTzl(const TImageReaderTzl &);
TImageReaderTzl &operator=(const TImageReaderTzl &src);
TImageP load10();
TImageP load11();
TImageP load13(); // Aggiunta iconcine
TImageP load14(); // Aggiunto creator con lunghezza fissa
const TImageInfo *getImageInfo10() const;
const TImageInfo *getImageInfo11() const; // vale anche le versioni > di 11
public:
//! Indice del frame del livello
TFrameId m_fid;
TImageP load() override;
TImageP loadIcon() override {
m_isIcon = true;
return load();
}
const TImageInfo *getImageInfo() const override;
// TImageP doLoad();
TDimension getSize() const;
TRect getBBox() const;
private:
//! Size of image
int m_lx, m_ly;
bool m_isIcon;
//! Reference to level reader
TLevelReaderTzl *m_lrp;
};
//===================================================================
//
// TImageWriterTzl
//
//-------------------------------------------------------------------
class TImageWriterTzl final : public TImageWriter {
//! Reference to level writer
TLevelWriterTzl *m_lwp;
TFrameId m_fid;
TDimension
m_iconSize; // Dimensioni dell'iconcina salvata all'interno del file tlv
// In genere questo parametro viene settato come quello impostato
// dall'utente
// nelle preferenze.
public:
TImageWriterTzl(TLevelWriterTzl *lw, TFrameId fid)
: TImageWriter(TFilePath())
, m_lwp(lw)
, m_fid(fid)
, m_iconSize(TDimension(80, 60)) {}
~TImageWriterTzl() {}
private:
// not implemented
TImageWriterTzl(const TImageWriterTzl &);
TImageWriterTzl &operator=(const TImageWriterTzl &src);
public:
void save(const TImageP &img) override { m_lwp->save(img, m_fid); }
};
/*
//===================================================================
//
// TWriterInfo
//
//-------------------------------------------------------------------
TWriterInfo *TWriterInfoTzl::create(const std::string &ext)
{
return new TWriterInfoTzl();
}
//-------------------------------------------------------------------
TWriterInfo *TWriterInfoTzl::clone() const
{
return new TWriterInfoTzl(*this);
}
//-------------------------------------------------------------------
*/
namespace {
class Header {
public:
enum RasType {
Raster32RGBM,
Raster64RGBM,
Raster32CM,
RasterGR8,
RasterUnknown
};
int m_lx;
int m_ly;
RasType m_rasType;
};
} // namespace
//-------------------------------------------------------------------
//-------------------------------------------------------------------
void TLevelWriterTzl::buildFreeChunksTable() {
std::set<TzlChunk> occupiedChunks;
TzlOffsetMap::const_iterator it1 = m_frameOffsTable.begin();
TINT32 lastOccupiedPos = 0; // ultima posizione all'interno del file occupata
// dall'ultima immagine(grande o icona)
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; // prima posizione utile nel file in cui vengono memorizzati i
// dati relativi alle immagini
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::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(currentVersion())
, 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 = (m_version == 14) ? "TLV14B1a" : "TLV15B1a"; // actual version
erasedFrame = false;
// version TLV10B1a: first version
// version TLV11B1a: added frameIds
// version TLV12B1a: incremental writings
// version TLV13B1a: added thumbnails
// version TLV14B1a: add creator string (fixed size = CREATOR_LENGTH char)
// version TLV15B1a: support multiple suffixes
if (fs.doesExist()) {
// if (!fs.isWritable())
m_chan = fopen(path, "rb+");
/*--- 誰かが開いている、または権限が無いとき ---*/
if (!m_chan) {
throw TSystemException(path, "can't fopen.");
}
/*--- TLVファイルのヘッダが正しく読めなかった場合 ---*/
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 < currentVersion()) {
if (!convertToLatestVersion()) return;
assert(m_version == currentVersion());
}
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();
QByteArray suffix = fid.getLetter().toUtf8();
TINT32 offs = it->second.m_offs;
TINT32 length = it->second.m_length;
tfwrite(&num, 1, m_chan);
if (m_version >= 15) { // write the suffix length before data
TINT32 suffixLength = suffix.size();
tfwrite(&suffixLength, 1, m_chan);
tfwrite(suffix.constData(), suffixLength, m_chan);
} else // write only the first byte
tfwrite(suffix.constData(), 1, m_chan);
tfwrite(&offs, 1, m_chan);
tfwrite(&length, 1, m_chan);
}
// Write Icon Offset Table after frameOffsTable
iconOffsetMapPos =
ftell(m_chan); //(m_exists?m_iconOffsetTablePos: 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();
QByteArray suffix = fid.getLetter().toUtf8();
TINT32 thumbnailOffs = iconIt->second.m_offs;
TINT32 thumbnailLength = iconIt->second.m_length;
tfwrite(&num, 1, m_chan);
if (m_version >= 15) { // write the suffix length before data
TINT32 suffixLength = suffix.size();
tfwrite(&suffixLength, 1, m_chan);
tfwrite(suffix.constData(), suffixLength, m_chan);
} else // write only the first byte
tfwrite(suffix.constData(), 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);
}
}
// Se lo spazio libero (cioè la somma di tutti i buchi che si sono creati tra
// i frame)
// è maggiore di una certa soglia oppure è stato rimosso almeno un frame
// allora ottimizzo il file
// (in pratica risalvo il file da capo senza buchi).
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));
// I put the place for the frameCount, which I will write in this position at
// the end (see in the destructor)
tfwrite(&intval, 1, m_chan);
// I put the place for the offsetTableOffset, which I will write in this
// position at the end (see in the destructor)
intval = 0;
tfwrite(&intval, 1, m_chan);
// I put the place for the iconOffsetTableOffset, which I will write in this
// position at the end (see in the destructor)
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>offs+length+1)
// break;
if (it->m_offs + it->m_length == offs) // accorpo due chunks in uno
{
TzlChunk chunk(it->m_offs, it->m_length + length);
m_freeChunks.erase(it);
m_freeChunks.insert(chunk);
// it->m_length += length;
return;
} else if (offs + length == it->m_offs) {
TzlChunk chunk(offs, it->m_length + length);
m_freeChunks.erase(it);
m_freeChunks.insert(chunk);
// it->m_offs = offs;
// it->m_length += length;
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;
// prima libero il chunk del fid, se c'e'. accorpo con altro chunk se trovo
// uno contiguo.
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);
}
}
// ora cerco un cioncone libero con la piu' piccola memoria sufficiente
std::set<TzlChunk>::iterator it1 = m_freeChunks.begin(),
found = m_freeChunks.end();
for (; it1 != m_freeChunks.end(); it1++) {
// TINT32 _length = it1->m_length;
if (it1->m_length >= length &&
(found == m_freeChunks.end() || found->m_length > it1->m_length))
found = it1;
}
if (found != m_freeChunks.end()) {
// TINT32 _length = found->m_length;
TINT32 _offset = found->m_offs;
if (found->m_length > length) {
TzlChunk chunk(found->m_offs + length, found->m_length - length);
m_freeChunks.insert(chunk);
// found->m_offs+=length;
// found->m_length-=length;
} 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);
// se il file è di una versione precedente deve necessariamente già esistere
// su disco
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 = currentVersion();
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();
QByteArray suffix = fid.getLetter().toUtf8();
TINT32 offs = it2->second.m_offs;
TINT32 length = it2->second.m_length;
tfwrite(&num, 1, m_chan);
if (m_version >= 15) { // write the suffix length before data
TINT32 suffixLength = suffix.size();
tfwrite(&suffixLength, 1, m_chan);
tfwrite(suffix.constData(), suffixLength, m_chan);
} else // write only the first byte
tfwrite(suffix.constData(), 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();
QByteArray suffix = fid.getLetter().toUtf8();
TINT32 thumbnailOffs = iconIt->second.m_offs;
TINT32 thumbnailLength = iconIt->second.m_length;
tfwrite(&num, 1, m_chan);
if (m_version >= 15) { // write the suffix length before data
TINT32 suffixLength = suffix.size();
tfwrite(&suffixLength, 1, m_chan);
tfwrite(suffix.constData(), suffixLength, m_chan);
} else // write only the first byte
tfwrite(suffix.constData(), 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;
}
// else
// m_palette = 0;
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 == currentVersion());
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;
// se il file è di una versione precedente allora lo converto prima
if (m_version < currentVersion()) {
if (!convertToLatestVersion()) return;
assert(m_version == currentVersion());
}
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; // = ti->getCompressedBuffer(buffSize);
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;
// MessageBox( NULL, "Cannot save level, out of memory!", "Warning!",
// MB_OK);
}
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, false);
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();
//#if !TNZ_LITTLE_ENDIAN
// delete [] buff;
//#endif
}
//-------------------------------------------------------------------
void TLevelWriterTzl::doSave(const TImageP &img, const TFrameId &_fid) {
// salvo l'immagine grande
saveImage(img, _fid);
if (!img)
throw(TException(
"Saving tlv: it is not possible to create the image frame."));
// creo l'iconcina
TImageP icon = TImageP();
createIcon(img, icon);
assert(icon);
if (!icon)
throw(
TException("Saving tlv: it is not possible to create the image icon."));
// salvo l'iconcina
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) {
// salvo su file come icona
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;
// Rimozione dei frame non presenti nella prima colonna di renumberTable
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;
// Renumber Frame
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();
// buildFreeChunksTable();
}
//-------------------------------------------------------------------
void TLevelWriterTzl::createIcon(const TImageP &imgIn, TImageP &imgOut) {
// Creo iconcina e poi la salvo
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) {
// Do thumbnail
TRop::makeIcon(thumbnailRas, TRasterCM32P(cmras));
assert(thumbnailRas);
if (!thumbnailRas) return;
}
// Compute savebox
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)) // it should be better to use
// tfloor instead of tround in the
// previous lines:
// sometimes, for rounding problems, the savebox is outside the 1 pixel
// raster size.
// the best solution should be to replace tround with tfloor here
// and in the icon reading of tzl 1.4 (method load14),
// but this way the old 1.4 tzl are not read correctly (crash!)
// so, this 'if' is a patch. vinz
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);
// se il fid non esiste non faccio nulla
if (it == m_frameOffsTable.end()) return;
// aggiungo spazio vuoto
// m_freeChunks.insert(TzlChunk(it->second.m_offs, it->second.m_length));
addFreeChunk(it->second.m_offs, it->second.m_length);
// cancello l'immagine dalla tabella
m_frameOffsTable.erase(it);
if (m_iconOffsTable.size() > 0) {
TzlOffsetMap::iterator iconIt = m_iconOffsTable.find(fid);
// deve necessariamente esserci anche l'iconcina
assert(iconIt != m_iconOffsTable.end());
if (iconIt == m_iconOffsTable.end()) return;
// aggiungo spazio vuoto
// m_freeChunks.insert(TzlChunk(iconIt->second.m_offs,
// iconIt->second.m_length));
addFreeChunk(iconIt->second.m_offs, iconIt->second.m_length);
// Cancello la relativa icona
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); // Used in TLevelWriterTzl::optimize().
// Observe that m_iconSize may change below.
if (m_version >= 13 && m_exists) {
// A supported level file already exists at the specified path
// Check whether icons stored in the file already
// have the required size
if (!m_updatedIconsSize) // m_updatedIconsSize tells whether
m_updatedIconsSize =
checkIconSize(m_iconSize); // icon sizes in the file match m_iconSize
if (!m_updatedIconsSize) {
// Icons in the stored file mismatch with the
// required size. They need to be resized.
m_updatedIconsSize = resizeIcons(m_iconSize);
assert(m_updatedIconsSize);
}
}
}
//-------------------------------------------------------------------
/*!
\brief Checks the icons size stored inside an already existing level
file, and compares it with the specified newSize.
\return Whether the specified newSize \a matches the icons size in
the level file.
*/
bool TLevelWriterTzl::checkIconSize(const TDimension &newSize) {
assert(m_version >= 13);
if (!m_exists || m_iconOffsTable.empty() || !m_chan || m_version < 13)
return false;
// Read the size of icons in the file
TINT32 iconLx = 0, iconLy = 0;
long currentPos =
ftell(m_chan); // Backup current reading position in the file
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); // Reset to the original position in the file
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); // This is not performed if the above pre-emptive
// bailout kicks in. BTW, m_currentIconSize
// is currently UNUSED! Should be cleaned up...
// Compare newSize against read icon size in the file
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);
// make a copy of m_path and then use it for the resizeIcons()
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();
/*
if(m_currentIconSize.lx>newSize.lx && m_currentIconSize.ly>newSize.ly)
{
for(TLevel::Iterator it=level->begin(); it != level->end(); ++it)
{
TImageReaderP ir = lr->getFrameReader(it->first);
// carico l'iconcina
TImageP img = ir->loadIcon();
TImageP icon;
createIcon(img,icon);
saveIcon(icon,it->first);
}
}
else
{ */
// leggo tutte le immagini da file e creo le iconcine da da zero
for (TLevel::Iterator it = level->begin(); it != level->end(); ++it) {
// carico l'iconcina
TImageP img = lr->getFrameReader(it->first)->load();
// creo e salvo
TImageP icon;
createIcon(img, icon);
saveIcon(icon, it->first);
}
//}
lr = TLevelReaderP();
// delete m_tempPath
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;
}
// creo il file ottimizzato, cioè senza spazi liberi
bool TLevelWriterTzl::optimize() {
TFileStatus fs(m_path);
assert(fs.doesExist());
std::string tempName = "~" + m_path.getName() + "tmp&.tlv";
TFilePath tempPath =
TSystem::getTempDir() + tempName; // Path temporaneo del file ottimizzato
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 != level->end(); ++levelIt) {
TToonzImageP img = lr->getFrameReader(levelIt->first)->load();
assert(img);
lw->getFrameWriter(levelIt->first)->save(img);
}
lr = TLevelReaderP();
lw = TLevelWriterP();
// Se il file tempPath (ottimizzato) è stato creato
// lo copio sostituendolo ad m_path
if (TSystem::doesExistFileOrLevel(tempPath)) {
assert(m_path != tempPath);
if (TSystem::doesExistFileOrLevel(m_path))
TSystem::deleteFile(m_path); // Cancello il file non ottimizzato
TSystem::copyFile(m_path, tempPath);
TSystem::deleteFile(tempPath);
} else
return false;
return true;
}
//===================================================================
//
// TLevelReaderTzl
//
//-------------------------------------------------------------------
void TLevelReaderTzl::readPalette() {
TFilePath pltfp = m_path.withNoFrame().withType("tpl");
TPersist *p = 0;
TIStream is(pltfp);
TPalette *palette = 0;
if (is) {
std::string tagName;
if (is.matchTag(tagName) && tagName == "palette") {
std::string gname;
is.getTagParam("name", gname);
palette = new TPalette();
palette->loadData(is);
palette->setGlobalName(::to_wstring(gname));
is.matchEndTag();
}
}
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) {
// read the whole file into historyData string
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));
}
// UCHAR *imgBuff = new UCHAR[imgBuffSize];
// fclose(m_chan);
// m_chan = 0;
}
//-------------------------------------------------------------------
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;
// leggo la dimensione delle iconcine nel file
fread(&iconLx, sizeof(TINT32), 1, m_chan);
fread(&iconLy, sizeof(TINT32), 1, m_chan);
assert(iconLx > 0 && iconLy > 0);
// return to the current position
fseek(m_chan, currentPos, SEEK_SET);
iconSize = TDimension(iconLx, iconLy);
return true;
}
//===================================================================
//
// TImageReaderTzl
//
//-------------------------------------------------------------------
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();
// SAVEBOX_X0 SAVEBOX_Y0 SAVEBOX_LX SAVEBOX_LY BUFFER_SIZE
TINT32 sbx0, sby0, sblx, sbly;
TINT32 actualBuffSize;
double xdpi = 1, ydpi = 1;
TINT32 imgBuffSize = 0;
UCHAR *imgBuff = 0;
int frameIndex = m_fid.getNumber();
// int pos = ftell(chan);
/*if(m_lrp->m_frameIndex>=m_frameIndex)
{
fseek(chan, m_lrp->m_framesOffset, SEEK_SET);
m_lrp->m_frameIndex = 0;
}
int k = m_lrp->m_frameIndex + 1;
m_lrp->m_frameIndex = m_frameIndex;*/
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];
// int ret =
fread(imgBuff, actualBuffSize, 1, chan);
// assert(ret==1);
}
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();
// codec.compress(ras, 1, &imgBuff, actualBuffSize);
#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;
// codec.decompress(m_compressedBuffer, m_compressedBufferSize, ras);
// assert(0);
// TToonzImageP ti; // = new
// TToonzImage(m_lx,m_ly,savebox,imgBuff,actualBuffSize);
TToonzImageP ti(ras, savebox);
// if(dpiflag)
ti->setDpi(xdpi, ydpi);
// m_lrp->m_level->setFrame(TFrameId(m_frameIndex+1), ti);
ti->setPalette(m_lrp->m_level->getPalette());
// delete [] imgBuff;
// imgBuff = 0;
return ti;
// ToonzImageUtils::updateRas32(ti);
}
//-------------------------------------------------------------------
TImageP TImageReaderTzl::load11() {
FILE *chan = m_lrp->m_chan;
if (!chan) return TImageP();
// SAVEBOX_X0 SAVEBOX_Y0 SAVEBOX_LX SAVEBOX_LY BUFFER_SIZE
TINT32 sbx0, sby0, sblx, sbly;
TINT32 actualBuffSize;
double xdpi = 1, ydpi = 1;
TINT32 imgBuffSize = 0;
UCHAR *imgBuff = 0;
assert(!m_lrp->m_frameOffsTable.empty());
// int pos = ftell(chan);
/*if(m_lrp->m_frameIndex>=m_frameIndex)
{
fseek(chan, m_lrp->m_framesOffset, SEEK_SET);
m_lrp->m_frameIndex = 0;
}
int k = m_lrp->m_frameIndex + 1;
m_lrp->m_frameIndex = m_frameIndex;*/
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];
// int ret =
fread(imgBuff, actualBuffSize, 1, chan);
// assert(ret==1);
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();
}
// codec.compress(ras, 1, &imgBuff, actualBuffSize);
#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;
// codec.decompress(m_compressedBuffer, m_compressedBufferSize, ras);
// assert(0);
// TToonzImageP ti; // = new
// TToonzImage(m_lx,m_ly,savebox,imgBuff,actualBuffSize);
TToonzImageP ti(ras, savebox);
// if(dpiflag)
ti->setDpi(xdpi, ydpi);
// m_lrp->m_level->setFrame(TFrameId(m_frameIndex+1), ti);
ti->setPalette(m_lrp->m_level->getPalette());
// delete [] imgBuff;
// imgBuff = 0;
return ti;
// ToonzImageUtils::updateRas32(ti);
}
//-------------------------------------------------------------------
TImageP TImageReaderTzl::load13() {
FILE *chan = m_lrp->m_chan;
if (!chan) return TImageP();
// SAVEBOX_X0 SAVEBOX_Y0 SAVEBOX_LX SAVEBOX_LY BUFFER_SIZE
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
// Carico l'icona dal file
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);
TRect savebox(TPoint(iconsbx0,iconsby0),
TDimension(ras->getLx(),ras->getLy()));
*/
// Compute savebox
TINT32 iconsbx0 = tround((double)iconLx * sbx0 / m_lrp->m_res.lx);
TINT32 iconsby0 =
tround((double)iconLy * sby0 /
m_lrp->m_res.ly); //+tround((double)(iconLy-ly)/2);
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));
// int ly = tround((double)m_lrp->m_res.ly*iconLx/m_lrp->m_res.lx);
// TRect
// rect(TPoint(0,tround((double)(iconLy-ly)/2)),TDimension(iconLx,ly));
// TPixelCM32 bgColorRect(1,0,100);
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);
// fullRas->extractT(rect)->fill(bgColorRect);
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(); // new UCHAR[imgBuffSize];
// imgBuff = new UCHAR[imgBuffSize];
// imgBuffSize = m_lx*m_ly*sizeof(TPixelCM32);
// assert(actualBuffSize <= imgBuffSize);
// imgBuff = new UCHAR[imgBuffSize];
// int ret =
fread(imgBuff, actualBuffSize, 1, chan);
// assert(ret==1);
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();
}
// codec.compress(ras, 1, &imgBuff, actualBuffSize);
#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();
// delete [] imgBuff;
// codec.decompress(m_compressedBuffer, m_compressedBufferSize, ras);
// assert(0);
// TToonzImageP ti; // = new
// TToonzImage(m_lx,m_ly,savebox,imgBuff,actualBuffSize);
TToonzImageP ti(ras, savebox);
// if(dpiflag)
ti->setDpi(xdpi, ydpi);
// m_lrp->m_level->setFrame(TFrameId(m_frameIndex+1), ti);
ti->setPalette(m_lrp->m_level->getPalette());
// delete [] imgBuff;
// imgBuff = 0;
return ti;
// ToonzImageUtils::updateRas32(ti);
}
// Restituisce la regione del raster shrinkata e la relativa savebox.
static TRect applyShrinkAndRegion(TRasterP &ras, int shrink, TRect region,
TRect savebox) {
// estraggo la regione solo se essa ha coordinate valide.
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);
}
// calculate the new savebox
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();
// SAVEBOX_X0 SAVEBOX_Y0 SAVEBOX_LX SAVEBOX_LY BUFFER_SIZE
TINT32 sbx0 = 0, sby0 = 0, 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());
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
// Carico l'icona dal file
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(); // 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);
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
/*
TINT32 iconsbx0 = tround((double)iconLx*sbx0/m_lrp->m_res.lx);
TINT32 iconsby0 = tround((double)iconLy*sby0/m_lrp->m_res.ly);
TRect savebox(TPoint(iconsbx0,iconsby0),
TDimension(ras->getLx(),ras->getLy()));
*/
if (m_lrp->m_res.lx == 0 || m_lrp->m_res.ly == 0) return TImageP();
// Compute savebox
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()));
}
// int ly = tround((double)m_lrp->m_res.ly*iconLx/m_lrp->m_res.lx);
// TRect
// rect(TPoint(0,tround((double)(iconLy-ly)/2)),TDimension(iconLx,ly));
// TPixelCM32 bgColorRect(1,0,100);
TDimension imgSize(iconLx, iconLy);
if (!TRect(imgSize).contains(
savebox)) // for this 'if', see comment in createIcon method. vinz
savebox = savebox * TRect(imgSize);
// if(!TRect(imgSize).contains(savebox)) throw TException("Loading tlv: bad
// icon savebox size.");
if (imgSize != savebox.getSize()) {
TRasterCM32P fullRas(imgSize);
TPixelCM32 bgColor;
fullRas->fillOutside(savebox, bgColor);
// fullRas->extractT(rect)->fill(bgColorRect);
// assert(savebox.getSize() == ras->getSize());
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);
// imgBuffSize = m_lx*m_ly*sizeof(TPixelCM32);
raux->lock();
imgBuff = (UCHAR *)raux->getRawData(); // new UCHAR[imgBuffSize];
// int ret =
fread(imgBuff, actualBuffSize, 1, chan);
// assert(ret==1);
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();
}
// codec.compress(ras, 1, &imgBuff, actualBuffSize);
#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);
// if(dpiflag)
ti->setDpi(xdpi, ydpi);
// m_lrp->m_level->setFrame(TFrameId(m_frameIndex+1), ti);
ti->setPalette(m_lrp->m_level->getPalette());
// delete [] imgBuff;
// imgBuff = 0;
return ti;
// ToonzImageUtils::updateRas32(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;
case 15: // same as v14
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 {
// if both the savebox and the region are empty, do nothing
}
}
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);
// SAVEBOX_X0 SAVEBOX_Y0 SAVEBOX_LX SAVEBOX_LY BUFFER_SIZE
TINT32 sbx0, sby0, sblx, sbly;
TINT32 actualBuffSize;
double xdpi = 1, ydpi = 1;
// TINT32 imgBuffSize = 0;
// int pos = ftell(chan);
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;
// m_lrp->m_frameIndex = m_frameIndex;
return &info;
}
//-------------------------------------------------------------------
const TImageInfo *TImageReaderTzl::getImageInfo10() const {
FILE *chan = m_lrp->m_chan;
if (!chan) return 0;
// SAVEBOX_X0 SAVEBOX_Y0 SAVEBOX_LX SAVEBOX_LY BUFFER_SIZE
TINT32 sbx0, sby0, sblx, sbly;
TINT32 actualBuffSize;
double xdpi = 1, ydpi = 1;
TINT32 imgBuffSize = 0;
UCHAR *imgBuff = 0;
int frameIndex = m_fid.getNumber();
// int pos = ftell(chan);
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;
// m_lrp->m_frameIndex = m_frameIndex;
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()); }