|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
#if _MSC_VER >= 1400
|
|
Toshihiro Shimizu |
890ddd |
#define _CRT_SECURE_NO_DEPRECATE 1
|
|
Toshihiro Shimizu |
890ddd |
#endif
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
#include "psd.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "trasterimage.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "trop.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tpixelutils.h"
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
/*
|
|
Toshihiro Shimizu |
890ddd |
The entire content of this file is ridden with LEAKS. A bug has been filed, will hopefully
|
|
Toshihiro Shimizu |
890ddd |
be dealt with ASAP.
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
L'intero contenuto del file e' pieno di LEAK. Ho inserito la cosa in Bugilla e non ho potuto
|
|
Toshihiro Shimizu |
890ddd |
fare altro sotto rilascio. Non solo, il codice dei distruttori e' SBAGLIATO - l'ho esplicitamente
|
|
Toshihiro Shimizu |
890ddd |
disabilitato, tanto non era chiamato cmq.
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
E' da rifare usando SMART POINTERS (boost::scoped_ptr<> o tcg::unique_ptr<>, o
|
|
Toshihiro Shimizu |
890ddd |
std::unique_ptr<> se facciamo l'upgrade del compilatore).
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
Da osservare che anche il campo FILE in TPSDReader leaka se viene sganciata un'eccezione...
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
#define LEVEL_NAME_INDEX_SEP "@"
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//----forward declarations
|
|
Toshihiro Shimizu |
890ddd |
std::string buildErrorString(int error);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void readChannel(FILE *f, TPSDLayerInfo *li,
|
|
Toshihiro Shimizu |
890ddd |
TPSDChannelInfo *chan, int channels,
|
|
Toshihiro Shimizu |
890ddd |
TPSDHeaderInfo *h);
|
|
Toshihiro Shimizu |
890ddd |
void readLongData(FILE *f, struct dictentry *parent, TPSDLayerInfo *li);
|
|
Toshihiro Shimizu |
890ddd |
void readByteData(FILE *f, struct dictentry *parent, TPSDLayerInfo *li);
|
|
Toshihiro Shimizu |
890ddd |
void readKey(FILE *f, struct dictentry *parent, TPSDLayerInfo *li);
|
|
Toshihiro Shimizu |
890ddd |
void readLayer16(FILE *f, struct dictentry *parent, TPSDLayerInfo *li);
|
|
Toshihiro Shimizu |
890ddd |
//----end forward declarations
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
char swapByte(unsigned char src)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
unsigned char out = 0;
|
|
Toshihiro Shimizu |
890ddd |
for (int i = 0; i < 8; ++i) {
|
|
Toshihiro Shimizu |
890ddd |
out = out << 1;
|
|
Toshihiro Shimizu |
890ddd |
out |= (src & 1);
|
|
Toshihiro Shimizu |
890ddd |
src = src >> 1;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
return out;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TPSDReader::TPSDReader(const TFilePath &path) : m_shrinkX(1),
|
|
Toshihiro Shimizu |
890ddd |
m_shrinkY(1),
|
|
Toshihiro Shimizu |
890ddd |
m_region(TRect())
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
m_layerId = 0;
|
|
Toshihiro Shimizu |
890ddd |
QString name = path.getName().c_str();
|
|
Toshihiro Shimizu |
890ddd |
name.append(path.getDottedType().c_str());
|
|
Toshihiro Shimizu |
890ddd |
int sepPos = name.indexOf("#");
|
|
Toshihiro Shimizu |
890ddd |
int dotPos = name.indexOf(".", sepPos);
|
|
Toshihiro Shimizu |
890ddd |
name.remove(sepPos, dotPos - sepPos);
|
|
Toshihiro Shimizu |
890ddd |
m_path = path.getParentDir() + TFilePath(name.toStdString());
|
|
Toshihiro Shimizu |
890ddd |
//m_path = path;
|
|
Toshihiro Shimizu |
890ddd |
QMutexLocker sl(&m_mutex);
|
|
Toshihiro Shimizu |
890ddd |
openFile();
|
|
Toshihiro Shimizu |
890ddd |
if (!doInfo()) {
|
|
Toshihiro Shimizu |
890ddd |
fclose(m_file);
|
|
Toshihiro Shimizu |
890ddd |
throw TImageException(m_path, "Do PSD INFO ERROR");
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
fclose(m_file);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
TPSDReader::~TPSDReader()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
/*for(int i=0; i
|
|
Toshihiro Shimizu |
890ddd |
free(m_headerInfo.linfo + i);*/
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// NO - L'istruzione sopra e' SBAGLIATA, si tratta di uno pseudo-array allocato in blocco
|
|
Toshihiro Shimizu |
890ddd |
// con una SINGOLA malloc() - quindi deve dovrebbe essere deallocato con una SINGOLA free().
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// Se fino ad ora funzionava e' perche' questa funzione NON VENIVA MAI CHIAMATA -
|
|
Toshihiro Shimizu |
890ddd |
// LEAKAVA TUTTO.
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// Non solo, ma il CONTENUTO delle singole strutture - tra cui altri array - non viene
|
|
Toshihiro Shimizu |
890ddd |
// deallocato. Non ho idea se sia garantito che venga deallocato prima di arrivare qui,
|
|
Toshihiro Shimizu |
890ddd |
// ma NON E' AFFATTO SICURO.
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
int TPSDReader::openFile()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
m_file = fopen(m_path, "rb");
|
|
Toshihiro Shimizu |
890ddd |
if (!m_file)
|
|
Toshihiro Shimizu |
890ddd |
throw TImageException(m_path, buildErrorString(2));
|
|
Toshihiro Shimizu |
890ddd |
return 0;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
bool TPSDReader::doInfo()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
// Read Header Block
|
|
Toshihiro Shimizu |
890ddd |
if (!doHeaderInfo())
|
|
Toshihiro Shimizu |
890ddd |
return false;
|
|
Toshihiro Shimizu |
890ddd |
// Read Color Mode Data Block
|
|
Toshihiro Shimizu |
890ddd |
if (!doColorModeData())
|
|
Toshihiro Shimizu |
890ddd |
return false;
|
|
Toshihiro Shimizu |
890ddd |
// Read Image Resources Block
|
|
Toshihiro Shimizu |
890ddd |
if (!doImageResources())
|
|
Toshihiro Shimizu |
890ddd |
return false;
|
|
Toshihiro Shimizu |
890ddd |
// Read Layer Info Block (Layers Number and merged alpha)
|
|
Toshihiro Shimizu |
890ddd |
if (!doLayerAndMaskInfo())
|
|
Toshihiro Shimizu |
890ddd |
return false;
|
|
Toshihiro Shimizu |
890ddd |
// Read Layers and Mask Information Block
|
|
Toshihiro Shimizu |
890ddd |
//if(!doLayersInfo()) return false;
|
|
Toshihiro Shimizu |
890ddd |
m_headerInfo.layerDataPos = ftell(m_file);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (m_headerInfo.layersCount == 0) //tento con extra data
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
fseek(m_file, m_headerInfo.layerDataPos, SEEK_SET);
|
|
Toshihiro Shimizu |
890ddd |
skipBlock(m_file); // skip global layer mask info
|
|
Toshihiro Shimizu |
890ddd |
psdByte currentPos = ftell(m_file);
|
|
Toshihiro Shimizu |
890ddd |
psdByte len = m_headerInfo.lmistart + m_headerInfo.lmilen - currentPos; // 4 = bytes skipped by global layer mask info
|
|
Toshihiro Shimizu |
890ddd |
doExtraData(NULL, len);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
return true;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
// Read Header Block
|
|
Toshihiro Shimizu |
890ddd |
bool TPSDReader::doHeaderInfo()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
fread(m_headerInfo.sig, 1, 4, m_file);
|
|
Toshihiro Shimizu |
890ddd |
m_headerInfo.version = read2UBytes(m_file);
|
|
Toshihiro Shimizu |
890ddd |
read4Bytes(m_file);
|
|
Toshihiro Shimizu |
890ddd |
read2Bytes(m_file); // reserved[6];
|
|
Toshihiro Shimizu |
890ddd |
m_headerInfo.channels = read2UBytes(m_file);
|
|
Toshihiro Shimizu |
890ddd |
m_headerInfo.rows = read4Bytes(m_file);
|
|
Toshihiro Shimizu |
890ddd |
m_headerInfo.cols = read4Bytes(m_file);
|
|
Toshihiro Shimizu |
890ddd |
m_headerInfo.depth = read2UBytes(m_file);
|
|
Toshihiro Shimizu |
890ddd |
m_headerInfo.mode = read2UBytes(m_file);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (!feof(m_file) && !memcmp(m_headerInfo.sig, "8BPS", 4)) {
|
|
Toshihiro Shimizu |
890ddd |
if (m_headerInfo.version == 1) {
|
|
Toshihiro Shimizu |
890ddd |
if (m_headerInfo.channels <= 0 || m_headerInfo.channels > 64 || m_headerInfo.rows <= 0 ||
|
|
Toshihiro Shimizu |
890ddd |
m_headerInfo.cols <= 0 || m_headerInfo.depth < 0 || m_headerInfo.depth > 32 || m_headerInfo.mode < 0) {
|
|
Toshihiro Shimizu |
890ddd |
throw TImageException(m_path, "Reading PSD Header Info error");
|
|
Toshihiro Shimizu |
890ddd |
return false;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
throw TImageException(m_path, "PSD Version not supported");
|
|
Toshihiro Shimizu |
890ddd |
return false;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
throw TImageException(m_path, "Cannot read Header");
|
|
Toshihiro Shimizu |
890ddd |
return false;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
return true;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
// Read Color Mode Data Block
|
|
Toshihiro Shimizu |
890ddd |
bool TPSDReader::doColorModeData()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
m_headerInfo.colormodepos = ftell(m_file);
|
|
Toshihiro Shimizu |
890ddd |
skipBlock(m_file); //skip "color mode data"
|
|
Toshihiro Shimizu |
890ddd |
return true;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
// Read Image Resources Block
|
|
Toshihiro Shimizu |
890ddd |
bool TPSDReader::doImageResources()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
//skipBlock(m_file); //skip "image resources"
|
|
Toshihiro Shimizu |
890ddd |
long len = read4Bytes(m_file); // lunghezza del blocco Image resources
|
|
Toshihiro Shimizu |
890ddd |
while (len > 0) {
|
|
Toshihiro Shimizu |
890ddd |
char type[4], name[0x100];
|
|
Toshihiro Shimizu |
890ddd |
int id, namelen;
|
|
Toshihiro Shimizu |
890ddd |
long size;
|
|
Toshihiro Shimizu |
890ddd |
fread(type, 1, 4, m_file);
|
|
Toshihiro Shimizu |
890ddd |
id = read2Bytes(m_file);
|
|
Toshihiro Shimizu |
890ddd |
namelen = fgetc(m_file);
|
|
Toshihiro Shimizu |
890ddd |
fread(name, 1, NEXT2(1 + namelen) - 1, m_file);
|
|
Toshihiro Shimizu |
890ddd |
name[namelen] = 0;
|
|
Toshihiro Shimizu |
890ddd |
size = read4Bytes(m_file);
|
|
Toshihiro Shimizu |
890ddd |
if (id == 1005) // ResolutionInfo
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
psdByte savepos = ftell(m_file);
|
|
Toshihiro Shimizu |
890ddd |
long hres, vres;
|
|
Toshihiro Shimizu |
890ddd |
double hresd, vresd;
|
|
Toshihiro Shimizu |
890ddd |
hresd = FIXDPI(hres = read4Bytes(m_file));
|
|
Toshihiro Shimizu |
890ddd |
read2Bytes(m_file);
|
|
Toshihiro Shimizu |
890ddd |
read2Bytes(m_file);
|
|
Toshihiro Shimizu |
890ddd |
vresd = FIXDPI(vres = read4Bytes(m_file));
|
|
Toshihiro Shimizu |
890ddd |
m_headerInfo.vres = vresd;
|
|
Toshihiro Shimizu |
890ddd |
m_headerInfo.hres = hresd;
|
|
Toshihiro Shimizu |
890ddd |
fseek(m_file, savepos, SEEK_SET);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
len -= 4 + 2 + NEXT2(1 + namelen) + 4 + NEXT2(size);
|
|
Toshihiro Shimizu |
890ddd |
fseek(m_file, NEXT2(size), SEEK_CUR); // skip resource block data
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
if (len != 0)
|
|
Toshihiro Shimizu |
890ddd |
return false;
|
|
Toshihiro Shimizu |
890ddd |
return true;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
// Read Layer Info Block (Layers Number and merged alpha)
|
|
Toshihiro Shimizu |
890ddd |
bool TPSDReader::doLayerAndMaskInfo()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
psdByte layerlen;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
m_headerInfo.layersCount = 0;
|
|
Toshihiro Shimizu |
890ddd |
m_headerInfo.lmilen = read4Bytes(m_file);
|
|
Toshihiro Shimizu |
890ddd |
m_headerInfo.lmistart = ftell(m_file);
|
|
Toshihiro Shimizu |
890ddd |
if (m_headerInfo.lmilen) {
|
|
Toshihiro Shimizu |
890ddd |
// process layer info section
|
|
Toshihiro Shimizu |
890ddd |
layerlen = read4Bytes(m_file);
|
|
Toshihiro Shimizu |
890ddd |
m_headerInfo.linfoBlockEmpty = false;
|
|
Toshihiro Shimizu |
890ddd |
m_headerInfo.mergedalpha = 0;
|
|
Toshihiro Shimizu |
890ddd |
if (layerlen) {
|
|
Toshihiro Shimizu |
890ddd |
doLayersInfo();
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
//WARNING: layer info section empty
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
//WARNING: layer & mask info section empty
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
return true;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// Read Layers Information Block
|
|
Toshihiro Shimizu |
890ddd |
// It is called by doLayerAndMaskInfo()
|
|
Toshihiro Shimizu |
890ddd |
bool TPSDReader::doLayersInfo()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
m_headerInfo.layersCount = read2Bytes(m_file);
|
|
Toshihiro Shimizu |
890ddd |
m_headerInfo.linfoBlockEmpty = false;
|
|
Toshihiro Shimizu |
890ddd |
m_headerInfo.mergedalpha = m_headerInfo.layersCount < 0;
|
|
Toshihiro Shimizu |
890ddd |
if (m_headerInfo.mergedalpha > 0) {
|
|
Toshihiro Shimizu |
890ddd |
m_headerInfo.layersCount = -m_headerInfo.layersCount;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
if (!m_headerInfo.linfoBlockEmpty) {
|
|
Toshihiro Shimizu |
890ddd |
m_headerInfo.linfo = (TPSDLayerInfo *)mymalloc(m_headerInfo.layersCount * sizeof(struct TPSDLayerInfo));
|
|
Toshihiro Shimizu |
890ddd |
int i = 0;
|
|
Toshihiro Shimizu |
890ddd |
for (i = 0; i < m_headerInfo.layersCount; i++) {
|
|
Toshihiro Shimizu |
890ddd |
readLayerInfo(i);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
return true;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
bool TPSDReader::readLayerInfo(int i)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
psdByte chlen, extralen, extrastart;
|
|
Toshihiro Shimizu |
890ddd |
int j, chid, namelen;
|
|
Toshihiro Shimizu |
890ddd |
TPSDLayerInfo *li = m_headerInfo.linfo + i;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// process layer record
|
|
Toshihiro Shimizu |
890ddd |
li->top = read4Bytes(m_file);
|
|
Toshihiro Shimizu |
890ddd |
li->left = read4Bytes(m_file);
|
|
Toshihiro Shimizu |
890ddd |
li->bottom = read4Bytes(m_file);
|
|
Toshihiro Shimizu |
890ddd |
li->right = read4Bytes(m_file);
|
|
Toshihiro Shimizu |
890ddd |
li->channels = read2UBytes(m_file);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (li->bottom < li->top || li->right < li->left || li->channels > 64) // sanity ck
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
// qualcosa รจ andato storto, skippo il livello
|
|
Toshihiro Shimizu |
890ddd |
fseek(m_file, 6 * li->channels + 12, SEEK_CUR);
|
|
Toshihiro Shimizu |
890ddd |
skipBlock(m_file); // skip "layer info: extra data";
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
li->chan = (TPSDChannelInfo *)mymalloc(li->channels * sizeof(struct TPSDChannelInfo));
|
|
Toshihiro Shimizu |
890ddd |
li->chindex = (int *)mymalloc((li->channels + 2) * sizeof(int));
|
|
Toshihiro Shimizu |
890ddd |
li->chindex += 2; //
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
for (j = -2; j < li->channels; ++j)
|
|
Toshihiro Shimizu |
890ddd |
li->chindex[j] = -1;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// fetch info on each of the layer's channels
|
|
Toshihiro Shimizu |
890ddd |
for (j = 0; j < li->channels; ++j) {
|
|
Toshihiro Shimizu |
890ddd |
chid = li->chan[j].id = read2Bytes(m_file);
|
|
Toshihiro Shimizu |
890ddd |
chlen = li->chan[j].length = read4Bytes(m_file);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (chid >= -2 && chid < li->channels)
|
|
Toshihiro Shimizu |
890ddd |
li->chindex[chid] = j;
|
|
Toshihiro Shimizu |
890ddd |
else {
|
|
Toshihiro Shimizu |
890ddd |
//WARNING: unexpected channel id
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
fread(li->blend.sig, 1, 4, m_file);
|
|
Toshihiro Shimizu |
890ddd |
fread(li->blend.key, 1, 4, m_file);
|
|
Toshihiro Shimizu |
890ddd |
li->blend.opacity = fgetc(m_file);
|
|
Toshihiro Shimizu |
890ddd |
li->blend.clipping = fgetc(m_file);
|
|
Toshihiro Shimizu |
890ddd |
li->blend.flags = fgetc(m_file);
|
|
Toshihiro Shimizu |
890ddd |
fgetc(m_file); // padding
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
extralen = read4Bytes(m_file);
|
|
Toshihiro Shimizu |
890ddd |
extrastart = ftell(m_file);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// layer mask data
|
|
Toshihiro Shimizu |
890ddd |
if ((li->mask.size = read4Bytes(m_file))) {
|
|
Toshihiro Shimizu |
890ddd |
li->mask.top = read4Bytes(m_file);
|
|
Toshihiro Shimizu |
890ddd |
li->mask.left = read4Bytes(m_file);
|
|
Toshihiro Shimizu |
890ddd |
li->mask.bottom = read4Bytes(m_file);
|
|
Toshihiro Shimizu |
890ddd |
li->mask.right = read4Bytes(m_file);
|
|
Toshihiro Shimizu |
890ddd |
li->mask.default_colour = fgetc(m_file);
|
|
Toshihiro Shimizu |
890ddd |
li->mask.flags = fgetc(m_file);
|
|
Toshihiro Shimizu |
890ddd |
fseek(m_file, li->mask.size - 18, SEEK_CUR); // skip remainder
|
|
Toshihiro Shimizu |
890ddd |
li->mask.rows = li->mask.bottom - li->mask.top;
|
|
Toshihiro Shimizu |
890ddd |
li->mask.cols = li->mask.right - li->mask.left;
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
//no layer mask data
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
skipBlock(m_file); // skip "layer blending ranges";
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// layer name
|
|
Toshihiro Shimizu |
890ddd |
li->nameno = (char *)malloc(16);
|
|
Toshihiro Shimizu |
890ddd |
sprintf(li->nameno, "layer%d", i + 1);
|
|
Toshihiro Shimizu |
890ddd |
namelen = fgetc(m_file);
|
|
Toshihiro Shimizu |
890ddd |
li->name = (char *)mymalloc(NEXT4(namelen + 1));
|
|
Toshihiro Shimizu |
890ddd |
fread(li->name, 1, NEXT4(namelen + 1) - 1, m_file);
|
|
Toshihiro Shimizu |
890ddd |
li->name[namelen] = 0;
|
|
Toshihiro Shimizu |
890ddd |
if (namelen) {
|
|
Toshihiro Shimizu |
890ddd |
if (li->name[0] == '.')
|
|
Toshihiro Shimizu |
890ddd |
li->name[0] = '_';
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// process layer's 'additional info'
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
li->additionalpos = ftell(m_file);
|
|
Toshihiro Shimizu |
890ddd |
li->additionallen = extrastart + extralen - li->additionalpos;
|
|
Toshihiro Shimizu |
890ddd |
doExtraData(li, li->additionallen);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// leave file positioned at end of layer's data
|
|
Toshihiro Shimizu |
890ddd |
fseek(m_file, extrastart + extralen, SEEK_SET);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
return true;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void TPSDReader::doImage(TRasterP &rasP, int layerId)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
m_layerId = layerId;
|
|
Toshihiro Shimizu |
890ddd |
int layerIndex = getLayerInfoIndexById(layerId);
|
|
Toshihiro Shimizu |
890ddd |
TPSDLayerInfo *li = getLayerInfo(layerIndex);
|
|
Toshihiro Shimizu |
890ddd |
psdByte imageDataEnd;
|
|
Toshihiro Shimizu |
890ddd |
// retrieve start data pos
|
|
Toshihiro Shimizu |
890ddd |
psdByte startPos = ftell(m_file);
|
|
Toshihiro Shimizu |
890ddd |
if (m_headerInfo.layersCount > 0) {
|
|
Toshihiro Shimizu |
890ddd |
struct TPSDLayerInfo *lilast = &m_headerInfo.linfo[m_headerInfo.layersCount - 1];
|
|
Toshihiro Shimizu |
890ddd |
startPos = lilast->additionalpos + lilast->additionallen;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
if (layerIndex > 0) {
|
|
Toshihiro Shimizu |
890ddd |
for (int j = 0; j < layerIndex; j++) {
|
|
Toshihiro Shimizu |
890ddd |
struct TPSDLayerInfo *liprev = &m_headerInfo.linfo[j];
|
|
Toshihiro Shimizu |
890ddd |
for (int ch = 0; ch < liprev->channels; ch++) {
|
|
Toshihiro Shimizu |
890ddd |
startPos += liprev->chan[ch].length;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
fseek(m_file, startPos, SEEK_SET);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
long pixw = li ? li->right - li->left : m_headerInfo.cols;
|
|
Toshihiro Shimizu |
890ddd |
long pixh = li ? li->bottom - li->top : m_headerInfo.rows;
|
|
Toshihiro Shimizu |
890ddd |
int channels = li ? li->channels : m_headerInfo.channels;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (li == NULL)
|
|
Toshihiro Shimizu |
890ddd |
fseek(m_file, m_headerInfo.lmistart + m_headerInfo.lmilen, SEEK_SET);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
psdPixel rows = pixh;
|
|
Toshihiro Shimizu |
890ddd |
psdPixel cols = pixw;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int ch = 0;
|
|
Toshihiro Shimizu |
890ddd |
psdByte **rowpos;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
rowpos = (psdByte **)mymalloc(channels * sizeof(psdByte *));
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
for (ch = 0; ch < channels; ++ch) {
|
|
Toshihiro Shimizu |
890ddd |
psdPixel chrows = li && !m_headerInfo.linfoBlockEmpty && li->chan[ch].id == -2 ? li->mask.rows : rows;
|
|
Toshihiro Shimizu |
890ddd |
rowpos[ch] = (psdByte *)mymalloc((chrows + 1) * sizeof(psdByte));
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int tnzchannels = 0;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int depth = m_headerInfo.depth;
|
|
Toshihiro Shimizu |
890ddd |
switch (m_headerInfo.mode) {
|
|
Toshihiro Shimizu |
890ddd |
//default: // multichannel, cmyk, lab etc
|
|
Toshihiro Shimizu |
890ddd |
// split = 1;
|
|
Toshihiro Shimizu |
890ddd |
case ModeBitmap:
|
|
Toshihiro Shimizu |
890ddd |
case ModeGrayScale:
|
|
Toshihiro Shimizu |
890ddd |
case ModeGray16:
|
|
Toshihiro Shimizu |
890ddd |
case ModeDuotone:
|
|
Toshihiro Shimizu |
890ddd |
case ModeDuotone16:
|
|
Toshihiro Shimizu |
890ddd |
tnzchannels = 1;
|
|
Toshihiro Shimizu |
890ddd |
// check if there is an alpha channel, or if merged data has alpha
|
|
Toshihiro Shimizu |
890ddd |
if (li ? li->chindex[-1] != -1 : channels > 1 && m_headerInfo.mergedalpha) {
|
|
Toshihiro Shimizu |
890ddd |
tnzchannels = 2;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
case ModeIndexedColor:
|
|
Toshihiro Shimizu |
890ddd |
tnzchannels = 1;
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
case ModeRGBColor:
|
|
Toshihiro Shimizu |
890ddd |
case ModeRGB48:
|
|
Toshihiro Shimizu |
890ddd |
tnzchannels = 3;
|
|
Toshihiro Shimizu |
890ddd |
if (li ? li->chindex[-1] != -1 : channels > 3 && m_headerInfo.mergedalpha) {
|
|
Toshihiro Shimizu |
890ddd |
tnzchannels = 4;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
default:
|
|
Toshihiro Shimizu |
890ddd |
tnzchannels = channels;
|
|
Toshihiro Shimizu |
890ddd |
//assert(0);
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (!li || m_headerInfo.linfoBlockEmpty) { // merged channel
|
|
Toshihiro Shimizu |
890ddd |
TPSDChannelInfo *mergedChans = (TPSDChannelInfo *)mymalloc(channels * sizeof(struct TPSDChannelInfo));
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
readChannel(m_file, NULL, mergedChans, channels, &m_headerInfo);
|
|
Toshihiro Shimizu |
890ddd |
imageDataEnd = ftell(m_file);
|
|
Toshihiro Shimizu |
890ddd |
readImageData(rasP, NULL, mergedChans, tnzchannels, rows, cols);
|
|
Toshihiro Shimizu |
890ddd |
free(mergedChans);
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
for (ch = 0; ch < channels; ++ch) {
|
|
Toshihiro Shimizu |
890ddd |
readChannel(m_file, li, li->chan + ch, 1, &m_headerInfo);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
imageDataEnd = ftell(m_file);
|
|
Toshihiro Shimizu |
890ddd |
readImageData(rasP, li, li->chan, tnzchannels, rows, cols);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
fseek(m_file, imageDataEnd, SEEK_SET);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
for (ch = 0; ch < channels; ++ch)
|
|
Toshihiro Shimizu |
890ddd |
free(rowpos[ch]);
|
|
Toshihiro Shimizu |
890ddd |
free(rowpos);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void TPSDReader::load(TRasterImageP &img, int layerId)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
QMutexLocker sl(&m_mutex);
|
|
Toshihiro Shimizu |
890ddd |
TPSDLayerInfo *li = NULL;
|
|
Toshihiro Shimizu |
890ddd |
int layerIndex = 0;
|
|
Toshihiro Shimizu |
890ddd |
if (layerId > 0) {
|
|
Toshihiro Shimizu |
890ddd |
layerIndex = getLayerInfoIndexById(layerId);
|
|
Toshihiro Shimizu |
890ddd |
li = getLayerInfo(layerIndex);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
if (layerId < 0)
|
|
Toshihiro Shimizu |
890ddd |
throw TImageException(m_path, "Layer ID not exists");
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (m_headerInfo.mode == 4 || m_headerInfo.depth == 32) {
|
|
Toshihiro Shimizu |
890ddd |
img = TRasterImageP();
|
|
Toshihiro Shimizu |
890ddd |
return;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
try {
|
|
Toshihiro Shimizu |
890ddd |
TRasterP rasP;
|
|
Toshihiro Shimizu |
890ddd |
openFile();
|
|
Toshihiro Shimizu |
890ddd |
doImage(rasP, layerId);
|
|
Toshihiro Shimizu |
890ddd |
fclose(m_file);
|
|
Toshihiro Shimizu |
890ddd |
/*
|
|
Toshihiro Shimizu |
890ddd |
// do savebox
|
|
Toshihiro Shimizu |
890ddd |
long sbx0 = li ? li->left : 0;
|
|
Toshihiro Shimizu |
890ddd |
long sby0 = li ? m_headerInfo.rows-li->bottom : 0;
|
|
Toshihiro Shimizu |
890ddd |
long sbx1 = li ? li->right - 1 : m_headerInfo.cols - 1;
|
|
Toshihiro Shimizu |
890ddd |
long sby1 = li ? m_headerInfo.rows - li->top - 1 : m_headerInfo.rows - 1;
|
|
Toshihiro Shimizu |
890ddd |
TRect layerSaveBox;
|
|
Toshihiro Shimizu |
890ddd |
layerSaveBox = TRect(sbx0,sby0,sbx1,sby1);
|
|
Toshihiro Shimizu |
890ddd |
TRect imageRect = TRect(0,0,m_headerInfo.cols-1,m_headerInfo.rows-1);
|
|
Toshihiro Shimizu |
890ddd |
// E' possibile che il layer sia in parte o tutto al di fuori della'immagine
|
|
Toshihiro Shimizu |
890ddd |
// in questo caso considero solo la parte visibile, cioรจ che rientra nell'immagine.
|
|
Toshihiro Shimizu |
890ddd |
// Se รจ tutta fuori restutuisco TRasterImageP()
|
|
Toshihiro Shimizu |
890ddd |
layerSaveBox *= imageRect;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if(layerSaveBox== TRect()) {
|
|
Toshihiro Shimizu |
890ddd |
img = TRasterImageP();
|
|
Toshihiro Shimizu |
890ddd |
return;
|
|
Toshihiro Shimizu |
890ddd |
} */
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (!rasP) {
|
|
Toshihiro Shimizu |
890ddd |
img = TRasterImageP();
|
|
Toshihiro Shimizu |
890ddd |
return;
|
|
Toshihiro Shimizu |
890ddd |
} // Happens if layer image has 0 rows and (or?)
|
|
Toshihiro Shimizu |
890ddd |
// cols (dont ask me why, but I've seen it)
|
|
Toshihiro Shimizu |
890ddd |
TRect layerSaveBox = m_layersSavebox[layerId];
|
|
Toshihiro Shimizu |
890ddd |
TRect savebox(layerSaveBox);
|
|
Toshihiro Shimizu |
890ddd |
TDimension imgSize(rasP->getLx(), rasP->getLy());
|
|
Toshihiro Shimizu |
890ddd |
assert(TRect(imgSize).contains(savebox));
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (TRasterGR8P ras = rasP) {
|
|
Toshihiro Shimizu |
890ddd |
TPixelGR8 bgColor;
|
|
Toshihiro Shimizu |
890ddd |
ras->fillOutside(savebox, bgColor);
|
|
Toshihiro Shimizu |
890ddd |
img = TRasterImageP(ras);
|
|
Toshihiro Shimizu |
890ddd |
} else if (TRaster32P ras = rasP) {
|
|
Toshihiro Shimizu |
890ddd |
TPixel32 bgColor(0, 0, 0, 0);
|
|
Toshihiro Shimizu |
890ddd |
if (savebox != TRect())
|
|
Toshihiro Shimizu |
890ddd |
ras->fillOutside(savebox, bgColor);
|
|
Toshihiro Shimizu |
890ddd |
else
|
|
Toshihiro Shimizu |
890ddd |
ras->fill(bgColor);
|
|
Toshihiro Shimizu |
890ddd |
img = TRasterImageP(ras);
|
|
Toshihiro Shimizu |
890ddd |
} else if ((TRaster64P)rasP) {
|
|
Toshihiro Shimizu |
890ddd |
TRaster32P raux(rasP->getLx(), rasP->getLy());
|
|
Toshihiro Shimizu |
890ddd |
TRop::convert(raux, rasP);
|
|
Toshihiro Shimizu |
890ddd |
TPixel32 bgColor(0, 0, 0, 0);
|
|
Toshihiro Shimizu |
890ddd |
raux->fillOutside(savebox, bgColor);
|
|
Toshihiro Shimizu |
890ddd |
img = TRasterImageP(raux);
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
throw TImageException(m_path, "Invalid Raster");
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
img->setDpi(m_headerInfo.hres, m_headerInfo.vres);
|
|
Toshihiro Shimizu |
890ddd |
img->setSavebox(savebox);
|
|
Toshihiro Shimizu |
890ddd |
} catch (...) {
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int TPSDReader::getLayerInfoIndexById(int layerId)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
int layerIndex = -1;
|
|
Toshihiro Shimizu |
890ddd |
for (int i = 0; i < m_headerInfo.layersCount; i++) {
|
|
Toshihiro Shimizu |
890ddd |
TPSDLayerInfo *litemp = m_headerInfo.linfo + i;
|
|
Toshihiro Shimizu |
890ddd |
if (litemp->layerId == layerId) {
|
|
Toshihiro Shimizu |
890ddd |
layerIndex = i;
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
if (layerIndex < 0 && layerId != 0)
|
|
Toshihiro Shimizu |
890ddd |
throw TImageException(m_path, "Layer ID not exists");
|
|
Toshihiro Shimizu |
890ddd |
return layerIndex;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
TPSDLayerInfo *TPSDReader::getLayerInfo(int index)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
if (index < 0 || index >= m_headerInfo.layersCount)
|
|
Toshihiro Shimizu |
890ddd |
return NULL;
|
|
Toshihiro Shimizu |
890ddd |
return m_headerInfo.linfo + index;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
TPSDHeaderInfo TPSDReader::getPSDHeaderInfo()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
return m_headerInfo;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void TPSDReader::readImageData(TRasterP &rasP, TPSDLayerInfo *li, TPSDChannelInfo *chan,
|
|
Toshihiro Shimizu |
890ddd |
int chancount, psdPixel rows, psdPixel cols)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
int channels = li ? li->channels : m_headerInfo.channels;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
short depth = m_headerInfo.depth;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
psdByte savepos = ftell(m_file);
|
|
Toshihiro Shimizu |
890ddd |
if (rows == 0 || cols == 0)
|
|
Toshihiro Shimizu |
890ddd |
return;
|
|
Toshihiro Shimizu |
890ddd |
psdPixel j;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
unsigned char *inrows[4], *rledata;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int ch, map[4];
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
rledata = (unsigned char *)mymalloc(chan->rowbytes * 2);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
for (ch = 0; ch < chancount; ++ch) {
|
|
Toshihiro Shimizu |
890ddd |
inrows[ch] = (unsigned char *)mymalloc(chan->rowbytes);
|
|
Toshihiro Shimizu |
890ddd |
map[ch] = li && chancount > 1 ? li->chindex[ch] : ch;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// find the alpha channel, if needed
|
|
Toshihiro Shimizu |
890ddd |
if (li && (chancount == 2 || chancount == 4)) { // grey+alpha
|
|
Toshihiro Shimizu |
890ddd |
if (li->chindex[-1] == -1) {
|
|
Toshihiro Shimizu |
890ddd |
//WARNING no alpha found?;
|
|
Toshihiro Shimizu |
890ddd |
} else
|
|
Toshihiro Shimizu |
890ddd |
map[chancount - 1] = li->chindex[-1];
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// region dimensions with shrink
|
|
Toshihiro Shimizu |
890ddd |
// x0 e x1 non tengono conto dello shrink.
|
|
Toshihiro Shimizu |
890ddd |
int x0 = 0;
|
|
Toshihiro Shimizu |
890ddd |
int x1 = m_headerInfo.cols - 1;
|
|
Toshihiro Shimizu |
890ddd |
int y0 = 0;
|
|
Toshihiro Shimizu |
890ddd |
int y1 = m_headerInfo.rows - 1;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (!m_region.isEmpty()) {
|
|
Toshihiro Shimizu |
890ddd |
x0 = m_region.getP00().x;
|
|
Toshihiro Shimizu |
890ddd |
// se x0 รจ fuori dalle dimensioni dell'immagine ritorna un'immagine vuota
|
|
Michaล Janiszewski |
f91771 |
if (x0 >= m_headerInfo.cols) {
|
|
Michaล Janiszewski |
f91771 |
free(rledata);
|
|
Toshihiro Shimizu |
890ddd |
return;
|
|
Michaล Janiszewski |
f91771 |
}
|
|
Toshihiro Shimizu |
890ddd |
x1 = x0 + m_region.getLx() - 1;
|
|
Toshihiro Shimizu |
890ddd |
// controllo che x1 rimanga all'interno dell'immagine
|
|
Toshihiro Shimizu |
890ddd |
if (x1 >= m_headerInfo.cols)
|
|
Toshihiro Shimizu |
890ddd |
x1 = m_headerInfo.cols - 1;
|
|
Toshihiro Shimizu |
890ddd |
y0 = m_region.getP00().y;
|
|
Toshihiro Shimizu |
890ddd |
// se y0 รจ fuori dalle dimensioni dell'immagine ritorna un'immagine vuota
|
|
Michaล Janiszewski |
f91771 |
if (y0 >= m_headerInfo.rows) {
|
|
Michaล Janiszewski |
f91771 |
free(rledata);
|
|
Toshihiro Shimizu |
890ddd |
return;
|
|
Michaล Janiszewski |
f91771 |
}
|
|
Toshihiro Shimizu |
890ddd |
y1 = y0 + m_region.getLy() - 1;
|
|
Toshihiro Shimizu |
890ddd |
// controllo che y1 rimanga all'interno dell'immagine
|
|
Toshihiro Shimizu |
890ddd |
if (y1 >= m_headerInfo.rows)
|
|
Toshihiro Shimizu |
890ddd |
y1 = m_headerInfo.rows - 1;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
if (m_shrinkX > x1 - x0)
|
|
Toshihiro Shimizu |
890ddd |
m_shrinkX = x1 - x0;
|
|
Toshihiro Shimizu |
890ddd |
if (m_shrinkY > y1 - y0)
|
|
Toshihiro Shimizu |
890ddd |
m_shrinkY = y1 - y0;
|
|
Toshihiro Shimizu |
890ddd |
assert(m_shrinkX > 0 && m_shrinkY > 0);
|
|
Toshihiro Shimizu |
890ddd |
if (m_shrinkX > 1) {
|
|
Toshihiro Shimizu |
890ddd |
x1 -= (x1 - x0) % m_shrinkX;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
if (m_shrinkY > 1) {
|
|
Toshihiro Shimizu |
890ddd |
y1 -= (y1 - y0) % m_shrinkY;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
assert(x0 <= x1 && y0 <= y1);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TDimension imgSize((x1 - x0) / m_shrinkX + 1, (y1 - y0) / m_shrinkY + 1);
|
|
Toshihiro Shimizu |
890ddd |
if (depth == 1 && chancount == 1) {
|
|
Toshihiro Shimizu |
890ddd |
rasP = TRasterGR8P(imgSize);
|
|
Toshihiro Shimizu |
890ddd |
} else if (depth == 8 && chancount > 1) {
|
|
Toshihiro Shimizu |
890ddd |
rasP = TRaster32P(imgSize);
|
|
Toshihiro Shimizu |
890ddd |
} else if (m_headerInfo.depth == 8 && chancount == 1) {
|
|
Toshihiro Shimizu |
890ddd |
rasP = TRasterGR8P(imgSize);
|
|
Toshihiro Shimizu |
890ddd |
} else if (m_headerInfo.depth == 16 && chancount == 1 && m_headerInfo.mergedalpha) {
|
|
Toshihiro Shimizu |
890ddd |
rasP = TRasterGR8P(imgSize);
|
|
Toshihiro Shimizu |
890ddd |
} else if (m_headerInfo.depth == 16) {
|
|
Toshihiro Shimizu |
890ddd |
rasP = TRaster64P(imgSize);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// do savebox
|
|
Toshihiro Shimizu |
890ddd |
// calcolo la savebox in coordinate dell'immagine
|
|
Toshihiro Shimizu |
890ddd |
long sbx0 = li ? li->left - x0 : 0;
|
|
Toshihiro Shimizu |
890ddd |
long sby0 = li ? m_headerInfo.rows - li->bottom - y0 : 0;
|
|
Toshihiro Shimizu |
890ddd |
long sbx1 = li ? li->right - 1 - x0 : x1 - x0;
|
|
Toshihiro Shimizu |
890ddd |
long sby1 = li ? m_headerInfo.rows - li->top - 1 - y0 : y1 - y0;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TRect layerSaveBox;
|
|
Toshihiro Shimizu |
890ddd |
layerSaveBox = TRect(sbx0, sby0, sbx1, sby1);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TRect imageRect;
|
|
Toshihiro Shimizu |
890ddd |
if (!m_region.isEmpty())
|
|
Toshihiro Shimizu |
890ddd |
imageRect = TRect(0, 0, m_region.getLx() - 1, m_region.getLy() - 1);
|
|
Toshihiro Shimizu |
890ddd |
else
|
|
Toshihiro Shimizu |
890ddd |
imageRect = TRect(0, 0, m_headerInfo.cols - 1, m_headerInfo.rows - 1);
|
|
Toshihiro Shimizu |
890ddd |
// E' possibile che il layer sia in parte o tutto al di fuori della'immagine
|
|
Toshihiro Shimizu |
890ddd |
// in questo caso considero solo la parte visibile, cioรจ che rientra nell'immagine.
|
|
Toshihiro Shimizu |
890ddd |
// Se รจ tutta fuori restutuisco TRasterImageP()
|
|
Toshihiro Shimizu |
890ddd |
layerSaveBox *= imageRect;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (layerSaveBox == TRect() || layerSaveBox.isEmpty()) {
|
|
Michaล Janiszewski |
f91771 |
free(rledata);
|
|
Toshihiro Shimizu |
890ddd |
return;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
// Estraggo da rasP solo il rettangolo che si interseca con il livello corrente
|
|
Toshihiro Shimizu |
890ddd |
// stando attento a prendere i pixel giusti.
|
|
Toshihiro Shimizu |
890ddd |
int firstXPixIndexOfLayer = layerSaveBox.getP00().x - 1 + m_shrinkX - (abs(layerSaveBox.getP00().x - 1) % m_shrinkX);
|
|
Toshihiro Shimizu |
890ddd |
int lrx0 = firstXPixIndexOfLayer / m_shrinkX;
|
|
Toshihiro Shimizu |
890ddd |
int firstLineIndexOfLayer = layerSaveBox.getP00().y - 1 + m_shrinkY - (abs(layerSaveBox.getP00().y - 1) % m_shrinkY);
|
|
Toshihiro Shimizu |
890ddd |
int lry0 = firstLineIndexOfLayer / m_shrinkY;
|
|
Toshihiro Shimizu |
890ddd |
int lrx1 = (layerSaveBox.getP11().x - abs(layerSaveBox.getP11().x % m_shrinkX)) / m_shrinkX;
|
|
Toshihiro Shimizu |
890ddd |
int lry1 = (layerSaveBox.getP11().y - abs(layerSaveBox.getP11().y % m_shrinkY)) / m_shrinkY;
|
|
Toshihiro Shimizu |
890ddd |
TRect layerSaveBox2 = TRect(lrx0, lry0, lrx1, lry1);
|
|
Toshihiro Shimizu |
890ddd |
if (layerSaveBox2.isEmpty())
|
|
Toshihiro Shimizu |
890ddd |
return;
|
|
Toshihiro Shimizu |
890ddd |
assert(TRect(imgSize).contains(layerSaveBox2));
|
|
Toshihiro Shimizu |
890ddd |
if (li)
|
|
Toshihiro Shimizu |
890ddd |
m_layersSavebox[li->layerId] = layerSaveBox2;
|
|
Toshihiro Shimizu |
890ddd |
else
|
|
Toshihiro Shimizu |
890ddd |
m_layersSavebox[0] = layerSaveBox2;
|
|
Toshihiro Shimizu |
890ddd |
TRasterP smallRas = rasP->extract(layerSaveBox2);
|
|
Toshihiro Shimizu |
890ddd |
assert(smallRas);
|
|
Toshihiro Shimizu |
890ddd |
if (!smallRas)
|
|
Toshihiro Shimizu |
890ddd |
return;
|
|
Toshihiro Shimizu |
890ddd |
// Trovo l'indice di colonna del primo pixel del livello che deve essere letto
|
|
Toshihiro Shimizu |
890ddd |
// L'indice รจ riferito al livello.
|
|
Toshihiro Shimizu |
890ddd |
int colOffset = firstXPixIndexOfLayer - layerSaveBox.getP00().x;
|
|
Toshihiro Shimizu |
890ddd |
assert(colOffset >= 0);
|
|
Toshihiro Shimizu |
890ddd |
// Trovo l'indice della prima riga del livello che deve essere letta
|
|
Toshihiro Shimizu |
890ddd |
// L'indice รจ riferito al livello.
|
|
Toshihiro Shimizu |
890ddd |
// Nota che nel file photoshop le righe sono memorizzate dall'ultima alla prima.
|
|
Toshihiro Shimizu |
890ddd |
int rowOffset = abs(sby1) % m_shrinkY;
|
|
Toshihiro Shimizu |
890ddd |
int rowCount = rowOffset;
|
|
Toshihiro Shimizu |
890ddd |
//if(m_shrinkY==3) rowCount--;
|
|
Toshihiro Shimizu |
890ddd |
for (j = 0; j < smallRas->getLy(); j++) {
|
|
Toshihiro Shimizu |
890ddd |
for (ch = 0; ch < chancount; ++ch) {
|
|
Toshihiro Shimizu |
890ddd |
/* get row data */
|
|
Toshihiro Shimizu |
890ddd |
if (map[ch] < 0 || map[ch] > chancount) {
|
|
Toshihiro Shimizu |
890ddd |
//warn("bad map[%d]=%d, skipping a channel", i, map[i]);
|
|
Toshihiro Shimizu |
890ddd |
memset(inrows[ch], 0, chan->rowbytes); // zero out the row
|
|
Toshihiro Shimizu |
890ddd |
} else
|
|
Toshihiro Shimizu |
890ddd |
readrow(m_file, chan + map[ch], rowCount, inrows[ch], rledata);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
// se la riga corrente non rientra nell'immagine salto la copia
|
|
Toshihiro Shimizu |
890ddd |
if (sby1 - rowCount < 0 || sby1 - rowCount > m_headerInfo.rows - 1) {
|
|
Toshihiro Shimizu |
890ddd |
rowCount += m_shrinkY;
|
|
Toshihiro Shimizu |
890ddd |
continue;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
if (depth == 1 && chancount == 1) {
|
|
Toshihiro Shimizu |
890ddd |
if (!(layerSaveBox.getP00().x - sbx0 >= 0 && layerSaveBox.getP00().x - sbx0 + smallRas->getLx() / 8 - 1 < chan->rowbytes))
|
|
Toshihiro Shimizu |
890ddd |
throw TImageException(m_path, "Unable to read image with this depth and channels values");
|
|
Toshihiro Shimizu |
890ddd |
smallRas->lock();
|
|
Toshihiro Shimizu |
890ddd |
unsigned char *rawdata = (unsigned char *)smallRas->getRawData(0, smallRas->getLy() - j - 1);
|
|
Toshihiro Shimizu |
890ddd |
TPixelGR8 *pix = (TPixelGR8 *)rawdata;
|
|
Toshihiro Shimizu |
890ddd |
int colCount = colOffset;
|
|
Toshihiro Shimizu |
890ddd |
for (int k = 0; k < smallRas->getLx(); k += 8) {
|
|
Toshihiro Shimizu |
890ddd |
char value = ~inrows[0][layerSaveBox.getP00().x - sbx0 + colCount];
|
|
Toshihiro Shimizu |
890ddd |
pix[k].setValue(value);
|
|
Toshihiro Shimizu |
890ddd |
pix[k + 1].setValue(value);
|
|
Toshihiro Shimizu |
890ddd |
pix[k + 2].setValue(value);
|
|
Toshihiro Shimizu |
890ddd |
pix[k + 3].setValue(value);
|
|
Toshihiro Shimizu |
890ddd |
pix[k + 4].setValue(value);
|
|
Toshihiro Shimizu |
890ddd |
pix[k + 5].setValue(value);
|
|
Toshihiro Shimizu |
890ddd |
pix[k + 6].setValue(value);
|
|
Toshihiro Shimizu |
890ddd |
pix[k + 7].setValue(value);
|
|
Toshihiro Shimizu |
890ddd |
colCount += m_shrinkX;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
smallRas->unlock();
|
|
Toshihiro Shimizu |
890ddd |
} else if (depth == 8 && chancount > 1) {
|
|
Toshihiro Shimizu |
890ddd |
if (!(layerSaveBox.getP00().x - sbx0 >= 0 && layerSaveBox.getP00().x - sbx0 + smallRas->getLx() - 1 < chan->rowbytes))
|
|
Toshihiro Shimizu |
890ddd |
throw TImageException(m_path, "Unable to read image with this depth and channels values");
|
|
Toshihiro Shimizu |
890ddd |
smallRas->lock();
|
|
Toshihiro Shimizu |
890ddd |
unsigned char *rawdata = (unsigned char *)smallRas->getRawData(0, smallRas->getLy() - j - 1);
|
|
Toshihiro Shimizu |
890ddd |
TPixel32 *pix = (TPixel32 *)rawdata;
|
|
Toshihiro Shimizu |
890ddd |
int colCount = colOffset;
|
|
Toshihiro Shimizu |
890ddd |
for (int k = 0; k < smallRas->getLx(); k++) {
|
|
Toshihiro Shimizu |
890ddd |
if (chancount >= 3) {
|
|
Toshihiro Shimizu |
890ddd |
pix[k].r = inrows[0][layerSaveBox.getP00().x - sbx0 + colCount];
|
|
Toshihiro Shimizu |
890ddd |
pix[k].g = inrows[1][layerSaveBox.getP00().x - sbx0 + colCount];
|
|
Toshihiro Shimizu |
890ddd |
pix[k].b = inrows[2][layerSaveBox.getP00().x - sbx0 + colCount];
|
|
Toshihiro Shimizu |
890ddd |
if (chancount == 4) // RGB + alpha
|
|
Toshihiro Shimizu |
890ddd |
pix[k].m = inrows[3][layerSaveBox.getP00().x - sbx0 + colCount];
|
|
Toshihiro Shimizu |
890ddd |
else
|
|
Toshihiro Shimizu |
890ddd |
pix[k].m = 255;
|
|
Toshihiro Shimizu |
890ddd |
} else if (chancount <= 2) // gray + alpha
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
pix[k].r = inrows[0][layerSaveBox.getP00().x - sbx0 + colCount];
|
|
Toshihiro Shimizu |
890ddd |
pix[k].g = inrows[0][layerSaveBox.getP00().x - sbx0 + colCount];
|
|
Toshihiro Shimizu |
890ddd |
pix[k].b = inrows[0][layerSaveBox.getP00().x - sbx0 + colCount];
|
|
Toshihiro Shimizu |
890ddd |
if (chancount == 2)
|
|
Toshihiro Shimizu |
890ddd |
pix[k].m = inrows[1][layerSaveBox.getP00().x - sbx0 + colCount];
|
|
Toshihiro Shimizu |
890ddd |
else
|
|
Toshihiro Shimizu |
890ddd |
pix[k].m = 255;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
colCount += m_shrinkX;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
smallRas->unlock();
|
|
Toshihiro Shimizu |
890ddd |
} else if (m_headerInfo.depth == 8 && chancount == 1) {
|
|
Toshihiro Shimizu |
890ddd |
if (!(layerSaveBox.getP00().x - sbx0 >= 0 && layerSaveBox.getP00().x - sbx0 + smallRas->getLx() - 1 < chan->rowbytes))
|
|
Toshihiro Shimizu |
890ddd |
throw TImageException(m_path, "Unable to read image with this depth and channels values");
|
|
Toshihiro Shimizu |
890ddd |
smallRas->lock();
|
|
Toshihiro Shimizu |
890ddd |
unsigned char *rawdata = (unsigned char *)smallRas->getRawData(0, smallRas->getLy() - j - 1);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TPixelGR8 *pix = (TPixelGR8 *)rawdata;
|
|
Toshihiro Shimizu |
890ddd |
int colCount = colOffset;
|
|
Toshihiro Shimizu |
890ddd |
for (int k = 0; k < smallRas->getLx(); k++) {
|
|
Toshihiro Shimizu |
890ddd |
pix[k].setValue(inrows[0][layerSaveBox.getP00().x - sbx0 + colCount]);
|
|
Toshihiro Shimizu |
890ddd |
colCount += m_shrinkX;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
smallRas->unlock();
|
|
Toshihiro Shimizu |
890ddd |
} else if (m_headerInfo.depth == 16 && chancount == 1 && m_headerInfo.mergedalpha) // mergedChannels
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
if (!(layerSaveBox.getP00().x - sbx0 >= 0 && layerSaveBox.getP00().x - sbx0 + smallRas->getLx() - 1 < chan->rowbytes))
|
|
Toshihiro Shimizu |
890ddd |
throw TImageException(m_path, "Unable to read image with this depth and channels values");
|
|
Toshihiro Shimizu |
890ddd |
smallRas->lock();
|
|
Toshihiro Shimizu |
890ddd |
unsigned char *rawdata = (unsigned char *)smallRas->getRawData(0, smallRas->getLy() - j - 1);
|
|
Toshihiro Shimizu |
890ddd |
TPixelGR8 *pix = (TPixelGR8 *)rawdata;
|
|
Toshihiro Shimizu |
890ddd |
int colCount = colOffset;
|
|
Toshihiro Shimizu |
890ddd |
for (int k = 0; k < smallRas->getLx(); k++) {
|
|
Toshihiro Shimizu |
890ddd |
pix[k].setValue(inrows[0][layerSaveBox.getP00().x - sbx0 + colCount]);
|
|
Toshihiro Shimizu |
890ddd |
colCount += m_shrinkX;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
smallRas->unlock();
|
|
Toshihiro Shimizu |
890ddd |
} else if (m_headerInfo.depth == 16) {
|
|
Toshihiro Shimizu |
890ddd |
if (!(layerSaveBox.getP00().x - sbx0 >= 0 && layerSaveBox.getP00().x - sbx0 + smallRas->getLx() - 1 < chan->rowbytes))
|
|
Toshihiro Shimizu |
890ddd |
throw TImageException(m_path, "Unable to read image with this depth and channels values");
|
|
Toshihiro Shimizu |
890ddd |
smallRas->lock();
|
|
Toshihiro Shimizu |
890ddd |
unsigned short *rawdata = (unsigned short *)smallRas->getRawData(0, smallRas->getLy() - j - 1);
|
|
Toshihiro Shimizu |
890ddd |
TPixel64 *pix = (TPixel64 *)rawdata;
|
|
Toshihiro Shimizu |
890ddd |
int colCount = colOffset;
|
|
Toshihiro Shimizu |
890ddd |
for (int k = 0; k < smallRas->getLx(); k++) {
|
|
Toshihiro Shimizu |
890ddd |
if (chancount >= 3) {
|
|
Toshihiro Shimizu |
890ddd |
pix[k].r = swapShort(((psdUint16 *)inrows[0])[layerSaveBox.getP00().x - sbx0 + colCount]);
|
|
Toshihiro Shimizu |
890ddd |
pix[k].g = swapShort(((psdUint16 *)inrows[1])[layerSaveBox.getP00().x - sbx0 + colCount]);
|
|
Toshihiro Shimizu |
890ddd |
pix[k].b = swapShort(((psdUint16 *)inrows[2])[layerSaveBox.getP00().x - sbx0 + colCount]);
|
|
Toshihiro Shimizu |
890ddd |
} else if (chancount <= 2) {
|
|
Toshihiro Shimizu |
890ddd |
pix[k].r = swapShort(((psdUint16 *)inrows[0])[layerSaveBox.getP00().x - sbx0 + colCount]);
|
|
Toshihiro Shimizu |
890ddd |
pix[k].g = swapShort(((psdUint16 *)inrows[0])[layerSaveBox.getP00().x - sbx0 + colCount]);
|
|
Toshihiro Shimizu |
890ddd |
pix[k].b = swapShort(((psdUint16 *)inrows[0])[layerSaveBox.getP00().x - sbx0 + colCount]);
|
|
Toshihiro Shimizu |
890ddd |
if (chancount == 2)
|
|
Toshihiro Shimizu |
890ddd |
pix[k].m = swapShort(((psdUint16 *)inrows[1])[layerSaveBox.getP00().x - sbx0 + colCount]);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
if (chancount == 4) {
|
|
Toshihiro Shimizu |
890ddd |
pix[k].m = swapShort(((psdUint16 *)inrows[3])[layerSaveBox.getP00().x - sbx0 + colCount]);
|
|
Toshihiro Shimizu |
890ddd |
} else
|
|
Toshihiro Shimizu |
890ddd |
pix[k].m = 0xffff;
|
|
Toshihiro Shimizu |
890ddd |
colCount += m_shrinkX;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
smallRas->unlock();
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
throw TImageException(m_path, "Unable to read image with this depth and channels values");
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
rowCount += m_shrinkY;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
fseek(m_file, savepos, SEEK_SET); // restoring filepos
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
free(rledata);
|
|
Toshihiro Shimizu |
890ddd |
for (ch = 0; ch < chancount; ++ch)
|
|
Toshihiro Shimizu |
890ddd |
free(inrows[ch]);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void TPSDReader::doExtraData(TPSDLayerInfo *li, psdByte length)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
static struct dictentry extradict[] = {
|
|
Toshihiro Shimizu |
890ddd |
// v4.0
|
|
Toshihiro Shimizu |
890ddd |
{0, "levl", "LEVELS", "Levels", NULL /*adj_levels*/},
|
|
Toshihiro Shimizu |
890ddd |
{0, "curv", "CURVES", "Curves", NULL /*adj_curves*/},
|
|
Toshihiro Shimizu |
890ddd |
{0, "brit", "BRIGHTNESSCONTRAST", "Brightness/contrast", NULL},
|
|
Toshihiro Shimizu |
890ddd |
{0, "blnc", "COLORBALANCE", "Color balance", NULL},
|
|
Toshihiro Shimizu |
890ddd |
{0, "hue ", "HUESATURATION4", "Old Hue/saturation, Photoshop 4.0", NULL /*adj_huesat4*/},
|
|
Toshihiro Shimizu |
890ddd |
{0, "hue2", "HUESATURATION5", "New Hue/saturation, Photoshop 5.0", NULL /*adj_huesat5*/},
|
|
Toshihiro Shimizu |
890ddd |
{0, "selc", "SELECTIVECOLOR", "Selective color", NULL /*adj_selcol*/},
|
|
Toshihiro Shimizu |
890ddd |
{0, "thrs", "THRESHOLD", "Threshold", NULL},
|
|
Toshihiro Shimizu |
890ddd |
{0, "nvrt", "INVERT", "Invert", NULL},
|
|
Toshihiro Shimizu |
890ddd |
{0, "post", "POSTERIZE", "Posterize", NULL},
|
|
Toshihiro Shimizu |
890ddd |
// v5.0
|
|
Toshihiro Shimizu |
890ddd |
{0, "lrFX", "EFFECT", "Effects layer", NULL /*ed_layereffects*/},
|
|
Toshihiro Shimizu |
890ddd |
{0, "tySh", "TYPETOOL5", "Type tool (5.0)", NULL /*ed_typetool*/},
|
|
Toshihiro Shimizu |
890ddd |
{0, "luni", "-UNICODENAME", "Unicode layer name", NULL /*ed_unicodename*/},
|
|
Toshihiro Shimizu |
890ddd |
{0, "lyid", "-LAYERID", "Layer ID", readLongData}, // '-' prefix means keep tag value on one line
|
|
Toshihiro Shimizu |
890ddd |
// v6.0
|
|
Toshihiro Shimizu |
890ddd |
{0, "lfx2", "OBJECTEFFECT", "Object based effects layer", NULL /*ed_objecteffects*/},
|
|
Toshihiro Shimizu |
890ddd |
{0, "Patt", "PATTERN", "Pattern", NULL},
|
|
Toshihiro Shimizu |
890ddd |
{0, "Pat2", "PATTERNCS", "Pattern (CS)", NULL},
|
|
Toshihiro Shimizu |
890ddd |
{0, "Anno", "ANNOTATION", "Annotation", NULL /*ed_annotation*/},
|
|
Toshihiro Shimizu |
890ddd |
{0, "clbl", "-BLENDCLIPPING", "Blend clipping", readByteData},
|
|
Toshihiro Shimizu |
890ddd |
{0, "infx", "-BLENDINTERIOR", "Blend interior", readByteData},
|
|
Toshihiro Shimizu |
890ddd |
{0, "knko", "-KNOCKOUT", "Knockout", readByteData},
|
|
Toshihiro Shimizu |
890ddd |
{0, "lspf", "-PROTECTED", "Protected", readLongData},
|
|
Toshihiro Shimizu |
890ddd |
{0, "lclr", "SHEETCOLOR", "Sheet color", NULL},
|
|
Toshihiro Shimizu |
890ddd |
{0, "fxrp", "-REFERENCEPOINT", "Reference point", NULL /*ed_referencepoint*/},
|
|
Toshihiro Shimizu |
890ddd |
{0, "grdm", "GRADIENT", "Gradient", NULL},
|
|
Toshihiro Shimizu |
890ddd |
{0, "lsct", "-SECTION", "Section divider", readLongData}, // CS doc
|
|
Toshihiro Shimizu |
890ddd |
{0, "SoCo", "SOLIDCOLORSHEET", "Solid color sheet", NULL /*ed_versdesc*/}, // CS doc
|
|
Toshihiro Shimizu |
890ddd |
{0, "PtFl", "PATTERNFILL", "Pattern fill", NULL /*ed_versdesc*/}, // CS doc
|
|
Toshihiro Shimizu |
890ddd |
{0, "GdFl", "GRADIENTFILL", "Gradient fill", NULL /*ed_versdesc*/}, // CS doc
|
|
Toshihiro Shimizu |
890ddd |
{0, "vmsk", "VECTORMASK", "Vector mask", NULL}, // CS doc
|
|
Toshihiro Shimizu |
890ddd |
{0, "TySh", "TYPETOOL6", "Type tool (6.0)", NULL /*ed_typetool*/}, // CS doc
|
|
Toshihiro Shimizu |
890ddd |
{0, "ffxi", "-FOREIGNEFFECTID", "Foreign effect ID", readLongData}, // CS doc (this is probably a key too, who knows)
|
|
Toshihiro Shimizu |
890ddd |
{0, "lnsr", "-LAYERNAMESOURCE", "Layer name source", readKey}, // CS doc (who knew this was a signature? docs fail again - and what do the values mean?)
|
|
Toshihiro Shimizu |
890ddd |
{0, "shpa", "PATTERNDATA", "Pattern data", NULL}, // CS doc
|
|
Toshihiro Shimizu |
890ddd |
{0, "shmd", "METADATASETTING", "Metadata setting", NULL /*ed_metadata*/}, // CS doc
|
|
Toshihiro Shimizu |
890ddd |
{0, "brst", "BLENDINGRESTRICTIONS", "Channel blending restrictions", NULL}, // CS doc
|
|
Toshihiro Shimizu |
890ddd |
// v7.0
|
|
Toshihiro Shimizu |
890ddd |
{0, "lyvr", "-LAYERVERSION", "Layer version", readLongData}, // CS doc
|
|
Toshihiro Shimizu |
890ddd |
{0, "tsly", "-TRANSPARENCYSHAPES", "Transparency shapes layer", readByteData}, // CS doc
|
|
Toshihiro Shimizu |
890ddd |
{0, "lmgm", "-LAYERMASKASGLOBALMASK", "Layer mask as global mask", readByteData}, // CS doc
|
|
Toshihiro Shimizu |
890ddd |
{0, "vmgm", "-VECTORMASKASGLOBALMASK", "Vector mask as global mask", readByteData}, // CS doc
|
|
Toshihiro Shimizu |
890ddd |
// CS
|
|
Toshihiro Shimizu |
890ddd |
{0, "mixr", "CHANNELMIXER", "Channel mixer", NULL}, // CS doc
|
|
Toshihiro Shimizu |
890ddd |
{0, "phfl", "PHOTOFILTER", "Photo Filter", NULL}, // CS doc
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
{0, "Lr16", "LAYER16", "Layer 16", readLayer16},
|
|
Toshihiro Shimizu |
890ddd |
{0, NULL, NULL, NULL, NULL}};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
while (length >= 12) {
|
|
Toshihiro Shimizu |
890ddd |
psdByte block = sigkeyblock(m_file, extradict, li);
|
|
Toshihiro Shimizu |
890ddd |
if (!block) {
|
|
Toshihiro Shimizu |
890ddd |
//warn("bad signature in layer's extra data, skipping the rest");
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
length -= block;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
struct dictentry *TPSDReader::findbykey(FILE *f, struct dictentry *parent, char *key, TPSDLayerInfo *li)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
struct dictentry *d;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
for (d = parent; d->key; ++d)
|
|
Toshihiro Shimizu |
890ddd |
if (!memcmp(key, d->key, 4)) {
|
|
Toshihiro Shimizu |
890ddd |
//char *tagname = d->tag + (d->tag[0] == '-');
|
|
Toshihiro Shimizu |
890ddd |
//fprintf(stderr, "matched tag %s\n", d->tag);
|
|
Toshihiro Shimizu |
890ddd |
if (d->func) {
|
|
Toshihiro Shimizu |
890ddd |
psdByte savepos = ftell(f);
|
|
Toshihiro Shimizu |
890ddd |
//int oneline = d->tag[0] == '-';
|
|
Toshihiro Shimizu |
890ddd |
//char *tagname = d->tag + oneline;
|
|
Toshihiro Shimizu |
890ddd |
if (memcmp(key, "Lr16", 4) == 0) {
|
|
Toshihiro Shimizu |
890ddd |
doLayersInfo();
|
|
Toshihiro Shimizu |
890ddd |
} else
|
|
Toshihiro Shimizu |
890ddd |
d->func(f, d, li); // parse contents of this datum
|
|
Toshihiro Shimizu |
890ddd |
fseek(f, savepos, SEEK_SET);
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
// there is no function to parse this block.
|
|
Toshihiro Shimizu |
890ddd |
// because tag is empty in this case, we only need to consider
|
|
Toshihiro Shimizu |
890ddd |
// parent's one-line-ness.
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
return d;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
return NULL;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int TPSDReader::sigkeyblock(FILE *f, struct dictentry *dict, TPSDLayerInfo *li)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
char sig[4], key[4];
|
|
Toshihiro Shimizu |
890ddd |
long len;
|
|
Toshihiro Shimizu |
890ddd |
struct dictentry *d;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
fread(sig, 1, 4, f);
|
|
Toshihiro Shimizu |
890ddd |
fread(key, 1, 4, f);
|
|
Toshihiro Shimizu |
890ddd |
len = read4Bytes(f);
|
|
Toshihiro Shimizu |
890ddd |
if (!memcmp(sig, "8BIM", 4)) {
|
|
Toshihiro Shimizu |
890ddd |
if (dict && (d = findbykey(f, dict, key, li)) && !d->func) {
|
|
Toshihiro Shimizu |
890ddd |
// there is no function to parse this block
|
|
Toshihiro Shimizu |
890ddd |
//UNQUIET(" (data: %s)\n", d->desc);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
fseek(f, len, SEEK_CUR);
|
|
Toshihiro Shimizu |
890ddd |
return len + 12; // return number of bytes consumed
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
return 0; // bad signature
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//---------------------------- Utility functions
|
|
Toshihiro Shimizu |
890ddd |
std::string buildErrorString(int error)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
std::string message = "";
|
|
Toshihiro Shimizu |
890ddd |
switch (error) {
|
|
Toshihiro Shimizu |
890ddd |
case 0:
|
|
Toshihiro Shimizu |
890ddd |
message = "NO Error Found";
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
case 1:
|
|
Toshihiro Shimizu |
890ddd |
message = "Reading File Error";
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
case 2:
|
|
Toshihiro Shimizu |
890ddd |
message = "Opening File Error";
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
default:
|
|
Toshihiro Shimizu |
890ddd |
message = "Unknown Error";
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
return message;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void readChannel(FILE *f, TPSDLayerInfo *li,
|
|
Toshihiro Shimizu |
890ddd |
TPSDChannelInfo *chan, //channel info array
|
|
Toshihiro Shimizu |
890ddd |
int channels,
|
|
Toshihiro Shimizu |
890ddd |
TPSDHeaderInfo *h)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
int comp, ch;
|
|
Toshihiro Shimizu |
890ddd |
psdByte pos, chpos, rb;
|
|
Toshihiro Shimizu |
890ddd |
unsigned char *zipdata;
|
|
Toshihiro Shimizu |
890ddd |
psdPixel count, last, j;
|
|
Toshihiro Shimizu |
890ddd |
chpos = ftell(f);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (li) {
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// If this is a layer mask, the pixel size is a special case
|
|
Toshihiro Shimizu |
890ddd |
if (chan->id == -2) {
|
|
Toshihiro Shimizu |
890ddd |
chan->rows = li->mask.rows;
|
|
Toshihiro Shimizu |
890ddd |
chan->cols = li->mask.cols;
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
// channel has dimensions of the layer
|
|
Toshihiro Shimizu |
890ddd |
chan->rows = li->bottom - li->top;
|
|
Toshihiro Shimizu |
890ddd |
chan->cols = li->right - li->left;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
// merged image, has dimensions of PSD
|
|
Toshihiro Shimizu |
890ddd |
chan->rows = h->rows;
|
|
Toshihiro Shimizu |
890ddd |
chan->cols = h->cols;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// Compute image row bytes
|
|
Toshihiro Shimizu |
890ddd |
rb = ((long)chan->cols * h->depth + 7) / 8;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// Read compression type
|
|
Toshihiro Shimizu |
890ddd |
comp = read2UBytes(f);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// Prepare compressed data for later access:
|
|
Toshihiro Shimizu |
890ddd |
pos = chpos + 2;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// skip rle counts, leave pos pointing to first compressed image row
|
|
Toshihiro Shimizu |
890ddd |
if (comp == RLECOMP)
|
|
Toshihiro Shimizu |
890ddd |
pos += (channels * chan->rows) << h->version;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
for (ch = 0; ch < channels; ++ch) {
|
|
Toshihiro Shimizu |
890ddd |
if (!li)
|
|
Toshihiro Shimizu |
890ddd |
chan[ch].id = ch;
|
|
Toshihiro Shimizu |
890ddd |
chan[ch].rowbytes = rb;
|
|
Toshihiro Shimizu |
890ddd |
chan[ch].comptype = comp;
|
|
Toshihiro Shimizu |
890ddd |
chan[ch].rows = chan->rows;
|
|
Toshihiro Shimizu |
890ddd |
chan[ch].cols = chan->cols;
|
|
Toshihiro Shimizu |
890ddd |
chan[ch].filepos = pos;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (!chan->rows)
|
|
Toshihiro Shimizu |
890ddd |
continue;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// For RLE, we read the row count array and compute file positions.
|
|
Toshihiro Shimizu |
890ddd |
// For ZIP, read and decompress whole channel.
|
|
Toshihiro Shimizu |
890ddd |
switch (comp) {
|
|
Toshihiro Shimizu |
890ddd |
case RAWDATA:
|
|
Toshihiro Shimizu |
890ddd |
pos += chan->rowbytes * chan->rows;
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
case RLECOMP:
|
|
Toshihiro Shimizu |
890ddd |
/* accumulate RLE counts, to make array of row start positions */
|
|
Toshihiro Shimizu |
890ddd |
chan[ch].rowpos = (psdByte *)mymalloc((chan[ch].rows + 1) * sizeof(psdByte));
|
|
Toshihiro Shimizu |
890ddd |
last = chan[ch].rowbytes;
|
|
Toshihiro Shimizu |
890ddd |
for (j = 0; j < chan[ch].rows && !feof(f); ++j) {
|
|
Toshihiro Shimizu |
890ddd |
count = h->version == 1 ? read2UBytes(f) : (unsigned long)read4Bytes(f);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (count > 2 * chan[ch].rowbytes) // this would be impossible
|
|
Toshihiro Shimizu |
890ddd |
count = last; // make a guess, to help recover
|
|
Toshihiro Shimizu |
890ddd |
last = count;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
chan[ch].rowpos[j] = pos;
|
|
Toshihiro Shimizu |
890ddd |
pos += count;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
if (j < chan[ch].rows) {
|
|
Toshihiro Shimizu |
890ddd |
// fatal error couldn't read RLE counts
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
chan[ch].rowpos[j] = pos; /* = end of last row */
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
case ZIPWITHOUTPREDICTION:
|
|
Toshihiro Shimizu |
890ddd |
case ZIPWITHPREDICTION:
|
|
Toshihiro Shimizu |
890ddd |
if (li) {
|
|
Toshihiro Shimizu |
890ddd |
pos += chan->length - 2;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
zipdata = (unsigned char *)mymalloc(chan->length);
|
|
Toshihiro Shimizu |
890ddd |
count = fread(zipdata, 1, chan->length - 2, f);
|
|
Toshihiro Shimizu |
890ddd |
//if(count < chan->length - 2)
|
|
Toshihiro Shimizu |
890ddd |
// alwayswarn("ZIP data short: wanted %d bytes, got %d", chan->length, count);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
chan->unzipdata = (unsigned char *)mymalloc(chan->rows * chan->rowbytes);
|
|
Toshihiro Shimizu |
890ddd |
if (comp == ZIPWITHOUTPREDICTION)
|
|
Toshihiro Shimizu |
890ddd |
psdUnzipWithoutPrediction(zipdata, count, chan->unzipdata,
|
|
Toshihiro Shimizu |
890ddd |
chan->rows * chan->rowbytes);
|
|
Toshihiro Shimizu |
890ddd |
else
|
|
Toshihiro Shimizu |
890ddd |
psdUnzipWithPrediction(zipdata, count, chan->unzipdata,
|
|
Toshihiro Shimizu |
890ddd |
chan->rows * chan->rowbytes,
|
|
Toshihiro Shimizu |
890ddd |
chan->cols, h->depth);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
free(zipdata);
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
// WARNING cannot process ZIP compression outside layer
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
default: {
|
|
Toshihiro Shimizu |
890ddd |
// BAD COMPRESSION TYPE
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
if (li)
|
|
Toshihiro Shimizu |
890ddd |
fseek(f, chan->length - 2, SEEK_CUR);
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//if(li && pos != chpos + chan->length)
|
|
Toshihiro Shimizu |
890ddd |
// alwayswarn("# channel data is %ld bytes, but length = %ld\n",
|
|
Toshihiro Shimizu |
890ddd |
// pos - chpos, chan->length);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// set at the end of channel's data
|
|
Toshihiro Shimizu |
890ddd |
fseek(f, pos, SEEK_SET);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void readLongData(FILE *f, struct dictentry *parent, TPSDLayerInfo *li)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
unsigned long id = read4Bytes(f);
|
|
Toshihiro Shimizu |
890ddd |
if (strcmp(parent->key, "lyid") == 0)
|
|
Toshihiro Shimizu |
890ddd |
li->layerId = id;
|
|
Toshihiro Shimizu |
890ddd |
else if (strcmp(parent->key, "lspf") == 0)
|
|
Toshihiro Shimizu |
890ddd |
li->protect = id;
|
|
Toshihiro Shimizu |
890ddd |
else if (strcmp(parent->key, "lsct") == 0)
|
|
Toshihiro Shimizu |
890ddd |
li->section = id;
|
|
Toshihiro Shimizu |
890ddd |
else if (strcmp(parent->key, "ffxi") == 0)
|
|
Toshihiro Shimizu |
890ddd |
li->foreignEffectID = id;
|
|
Toshihiro Shimizu |
890ddd |
else if (strcmp(parent->key, "lyvr") == 0)
|
|
Toshihiro Shimizu |
890ddd |
li->layerVersion = id;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void readByteData(FILE *f, struct dictentry *parent, TPSDLayerInfo *li)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
int id = fgetc(f);
|
|
Toshihiro Shimizu |
890ddd |
if (strcmp(parent->key, "clbl") == 0)
|
|
Toshihiro Shimizu |
890ddd |
li->blendClipping = id;
|
|
Toshihiro Shimizu |
890ddd |
else if (strcmp(parent->key, "infx") == 0)
|
|
Toshihiro Shimizu |
890ddd |
li->blendInterior = id;
|
|
Toshihiro Shimizu |
890ddd |
else if (strcmp(parent->key, "knko") == 0)
|
|
Toshihiro Shimizu |
890ddd |
li->knockout = id;
|
|
Toshihiro Shimizu |
890ddd |
else if (strcmp(parent->key, "tsly") == 0)
|
|
Toshihiro Shimizu |
890ddd |
li->transparencyShapes = id;
|
|
Toshihiro Shimizu |
890ddd |
else if (strcmp(parent->key, "lmgm") == 0)
|
|
Toshihiro Shimizu |
890ddd |
li->layerMaskAsGlobalMask = id;
|
|
Toshihiro Shimizu |
890ddd |
else if (strcmp(parent->key, "vmgm") == 0)
|
|
Toshihiro Shimizu |
890ddd |
li->vectorMaskAsGlobalMask = id;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void readKey(FILE *f, struct dictentry *parent, TPSDLayerInfo *li)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
static char key[5];
|
|
Toshihiro Shimizu |
890ddd |
if (fread(key, 1, 4, f) == 4)
|
|
Toshihiro Shimizu |
890ddd |
key[4] = 0;
|
|
Toshihiro Shimizu |
890ddd |
else
|
|
Toshihiro Shimizu |
890ddd |
key[0] = 0; // or return NULL?
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (strcmp(parent->key, "lnsr") == 0)
|
|
Toshihiro Shimizu |
890ddd |
li->layerNameSource = key;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void readLayer16(FILE *f, struct dictentry *parent, TPSDLayerInfo *li)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
//struct psd_header h2 = *psd_header; // a kind of 'nested' set of layers; don't alter main PSD header
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// overwrite main PSD header, mainly because of the 'merged alpha' flag
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// I *think* they mean us to respect the one in Lr16 because in my test data,
|
|
Toshihiro Shimizu |
890ddd |
// the main layer count is zero, so cannot convey this information.
|
|
Toshihiro Shimizu |
890ddd |
//dolayerinfo(f, psd_header);
|
|
Toshihiro Shimizu |
890ddd |
//processlayers(f, psd_header);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
//---------------------------- END Utility functions
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// TPSD PARSER
|
|
Toshihiro Shimizu |
890ddd |
TPSDParser::TPSDParser(const TFilePath &path)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
m_path = path;
|
|
Toshihiro Shimizu |
890ddd |
QString name = path.getName().c_str();
|
|
Toshihiro Shimizu |
890ddd |
name.append(path.getDottedType().c_str());
|
|
Toshihiro Shimizu |
890ddd |
int sepPos = name.indexOf("#");
|
|
Toshihiro Shimizu |
890ddd |
int dotPos = name.indexOf(".", sepPos);
|
|
Toshihiro Shimizu |
890ddd |
name.remove(sepPos, dotPos - sepPos);
|
|
Toshihiro Shimizu |
890ddd |
TFilePath psdpath = m_path.getParentDir() + TFilePath(name.toStdString());
|
|
Toshihiro Shimizu |
890ddd |
m_psdreader = new TPSDReader(psdpath);
|
|
Toshihiro Shimizu |
890ddd |
doLevels();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TPSDParser::~TPSDParser()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
delete m_psdreader;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void TPSDParser::doLevels()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
QString path = m_path.getName().c_str();
|
|
Toshihiro Shimizu |
890ddd |
QStringList list = path.split("#");
|
|
Toshihiro Shimizu |
890ddd |
m_levels.clear();
|
|
Toshihiro Shimizu |
890ddd |
if (list.size() > 1) {
|
|
Toshihiro Shimizu |
890ddd |
TPSDHeaderInfo psdheader = m_psdreader->getPSDHeaderInfo();
|
|
Toshihiro Shimizu |
890ddd |
if (list.contains("frames") && list.at(0) != "frames") {
|
|
Toshihiro Shimizu |
890ddd |
int firstLayerId = 0;
|
|
Toshihiro Shimizu |
890ddd |
Level level;
|
|
Toshihiro Shimizu |
890ddd |
for (int i = 0; i < psdheader.layersCount; i++) {
|
|
Toshihiro Shimizu |
890ddd |
TPSDLayerInfo *li = m_psdreader->getLayerInfo(i);
|
|
Toshihiro Shimizu |
890ddd |
long width = li->right - li->left;
|
|
Toshihiro Shimizu |
890ddd |
long height = li->bottom - li->top;
|
|
Toshihiro Shimizu |
890ddd |
if (width > 0 && height > 0) {
|
|
Toshihiro Shimizu |
890ddd |
assert(li->layerId >= 0);
|
|
Toshihiro Shimizu |
890ddd |
if (i == 0)
|
|
Toshihiro Shimizu |
890ddd |
firstLayerId = li->layerId;
|
|
Toshihiro Shimizu |
890ddd |
level.addFrame(li->layerId);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
// non ha importanza quale layerId assegno, l'importante รจ che esista
|
|
Toshihiro Shimizu |
890ddd |
level.setLayerId(0);
|
|
Toshihiro Shimizu |
890ddd |
if (psdheader.layersCount == 0)
|
|
Toshihiro Shimizu |
890ddd |
level.addFrame(firstLayerId); // succede nel caso in cui la psd non ha blocco layerInfo
|
|
Toshihiro Shimizu |
890ddd |
m_levels.push_back(level);
|
|
Toshihiro Shimizu |
890ddd |
} else if (list.size() == 3) {
|
|
Toshihiro Shimizu |
890ddd |
if (list.at(2) == "group") {
|
|
Toshihiro Shimizu |
890ddd |
int folderTagOpen = 0;
|
|
Toshihiro Shimizu |
890ddd |
int scavenge = 0;
|
|
Toshihiro Shimizu |
890ddd |
for (int i = 0; i < psdheader.layersCount; i++) {
|
|
Toshihiro Shimizu |
890ddd |
TPSDLayerInfo *li = m_psdreader->getLayerInfo(i);
|
|
Toshihiro Shimizu |
890ddd |
long width = li->right - li->left;
|
|
Toshihiro Shimizu |
890ddd |
long height = li->bottom - li->top;
|
|
Toshihiro Shimizu |
890ddd |
if (width > 0 && height > 0 && folderTagOpen == 0) {
|
|
Toshihiro Shimizu |
890ddd |
assert(li->layerId >= 0);
|
|
Toshihiro Shimizu |
890ddd |
Level level(li->name, li->layerId);
|
|
Toshihiro Shimizu |
890ddd |
level.addFrame(li->layerId);
|
|
Toshihiro Shimizu |
890ddd |
m_levels.push_back(level);
|
|
Toshihiro Shimizu |
890ddd |
scavenge = 0;
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
if (width != 0 && height != 0) {
|
|
Toshihiro Shimizu |
890ddd |
m_levels[m_levels.size() - 1 - (scavenge - folderTagOpen)].addFrame(li->layerId);
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
if (strcmp(li->name, "") == 0 || strcmp(li->name, "") == 0) {
|
|
Toshihiro Shimizu |
890ddd |
assert(li->layerId >= 0);
|
|
Toshihiro Shimizu |
890ddd |
Level level(li->name, li->layerId, true);
|
|
Toshihiro Shimizu |
890ddd |
m_levels.push_back(level);
|
|
Toshihiro Shimizu |
890ddd |
folderTagOpen++;
|
|
Toshihiro Shimizu |
890ddd |
scavenge = folderTagOpen;
|
|
Toshihiro Shimizu |
890ddd |
} else if (li->section > 0 && li->section <= 3) // vedi specifiche psd
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
assert(li->layerId >= 0);
|
|
Toshihiro Shimizu |
890ddd |
m_levels[m_levels.size() - 1 - (scavenge - folderTagOpen)].setName(li->name);
|
|
Toshihiro Shimizu |
890ddd |
m_levels[m_levels.size() - 1 - (scavenge - folderTagOpen)].setLayerId(li->layerId);
|
|
Toshihiro Shimizu |
890ddd |
folderTagOpen--;
|
|
Toshihiro Shimizu |
890ddd |
if (folderTagOpen > 0)
|
|
Toshihiro Shimizu |
890ddd |
m_levels[m_levels.size() - 1 - (scavenge - folderTagOpen)].addFrame(li->layerId, true);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
if (psdheader.layersCount == 0) // succede nel caso in cui la psd non ha blocco layerInfo
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
Level level;
|
|
Toshihiro Shimizu |
890ddd |
level.setLayerId(0);
|
|
Toshihiro Shimizu |
890ddd |
level.addFrame(0);
|
|
Toshihiro Shimizu |
890ddd |
m_levels.push_back(level);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
} else
|
|
Toshihiro Shimizu |
890ddd |
throw TImageException(m_path, "PSD code name error");
|
|
Toshihiro Shimizu |
890ddd |
} else if (list.size() == 2) // each psd layer is a tlevel
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
TPSDHeaderInfo psdheader = m_psdreader->getPSDHeaderInfo();
|
|
Toshihiro Shimizu |
890ddd |
for (int i = 0; i < psdheader.layersCount; i++) {
|
|
Toshihiro Shimizu |
890ddd |
TPSDLayerInfo *li = m_psdreader->getLayerInfo(i);
|
|
Toshihiro Shimizu |
890ddd |
long width = li->right - li->left;
|
|
Toshihiro Shimizu |
890ddd |
long height = li->bottom - li->top;
|
|
Toshihiro Shimizu |
890ddd |
if (width > 0 && height > 0) {
|
|
Toshihiro Shimizu |
890ddd |
assert(li->layerId >= 0);
|
|
Toshihiro Shimizu |
890ddd |
Level level(li->name, li->layerId);
|
|
Toshihiro Shimizu |
890ddd |
level.addFrame(li->layerId);
|
|
Toshihiro Shimizu |
890ddd |
m_levels.push_back(level);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
if (psdheader.layersCount == 0) // succede nel caso in cui la psd non ha blocco layerInfo
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
Level level;
|
|
Toshihiro Shimizu |
890ddd |
level.setLayerId(0);
|
|
Toshihiro Shimizu |
890ddd |
level.addFrame(0);
|
|
Toshihiro Shimizu |
890ddd |
m_levels.push_back(level);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
} else
|
|
Toshihiro Shimizu |
890ddd |
throw TImageException(m_path, "PSD code name error");
|
|
Toshihiro Shimizu |
890ddd |
} else // list.size()==1. float
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
Level level;
|
|
Toshihiro Shimizu |
890ddd |
level.setName(m_path.getName());
|
|
Toshihiro Shimizu |
890ddd |
level.addFrame(0);
|
|
Toshihiro Shimizu |
890ddd |
m_levels.push_back(level);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void TPSDParser::load(TRasterImageP &rasP, int layerId)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
m_psdreader->load(rasP, layerId);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int TPSDParser::getLevelIndexById(int layerId)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
int layerIndex = -1;
|
|
Toshihiro Shimizu |
890ddd |
for (int i = 0; i < (int)m_levels.size(); i++) {
|
|
Toshihiro Shimizu |
890ddd |
if (m_levels[i].getLayerId() == layerId) {
|
|
Toshihiro Shimizu |
890ddd |
layerIndex = i;
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
if (layerId == 0 && layerIndex < 0)
|
|
Toshihiro Shimizu |
890ddd |
layerIndex = 0;
|
|
Toshihiro Shimizu |
890ddd |
if (layerIndex < 0 && layerId != 0)
|
|
Toshihiro Shimizu |
890ddd |
throw TImageException(m_path, "Layer ID not exists");
|
|
Toshihiro Shimizu |
890ddd |
return layerIndex;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Shinya Kitaoka |
3bfa54 |
int TPSDParser::getLevelIdByName(std::string levelName)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
int pos = levelName.find_last_of(LEVEL_NAME_INDEX_SEP);
|
|
Toshihiro Shimizu |
890ddd |
int counter = 0;
|
|
Shinya Kitaoka |
3bfa54 |
if (pos != std::string::npos) {
|
|
Toshihiro Shimizu |
890ddd |
counter = atoi(levelName.substr(pos + 1).c_str());
|
|
Toshihiro Shimizu |
890ddd |
levelName = levelName.substr(0, pos);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
int lyid = -1;
|
|
Toshihiro Shimizu |
890ddd |
int levelNameCount = 0;
|
|
Toshihiro Shimizu |
890ddd |
for (int i = 0; i < (int)m_levels.size(); i++) {
|
|
Toshihiro Shimizu |
890ddd |
if (m_levels[i].getName() == levelName) {
|
|
Toshihiro Shimizu |
890ddd |
lyid = m_levels[i].getLayerId();
|
|
Toshihiro Shimizu |
890ddd |
if (counter == levelNameCount)
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
levelNameCount++;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
if (lyid == 0 && lyid < 0)
|
|
Toshihiro Shimizu |
890ddd |
lyid = 0;
|
|
Toshihiro Shimizu |
890ddd |
if (lyid < 0 && lyid != 0)
|
|
Toshihiro Shimizu |
890ddd |
throw TImageException(m_path, "Layer ID not exists");
|
|
Toshihiro Shimizu |
890ddd |
return lyid;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
int TPSDParser::getFramesCount(int levelId)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
int levelIndex = getLevelIndexById(levelId);
|
|
Toshihiro Shimizu |
890ddd |
assert(levelIndex >= 0 && levelIndex < (int)m_levels.size());
|
|
Toshihiro Shimizu |
890ddd |
return m_levels[levelIndex].getFrameCount();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Shinya Kitaoka |
3bfa54 |
std::string TPSDParser::getLevelName(int levelId)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
int levelIndex = getLevelIndexById(levelId);
|
|
Toshihiro Shimizu |
890ddd |
assert(levelIndex >= 0 && levelIndex < (int)m_levels.size());
|
|
Toshihiro Shimizu |
890ddd |
return m_levels[levelIndex].getName();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Shinya Kitaoka |
3bfa54 |
std::string TPSDParser::getLevelNameWithCounter(int levelId)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Shinya Kitaoka |
3bfa54 |
std::string levelName = getLevelName(levelId);
|
|
Toshihiro Shimizu |
890ddd |
int count = 0;
|
|
Toshihiro Shimizu |
890ddd |
for (int i = 0; i < (int)m_levels.size(); i++) {
|
|
Toshihiro Shimizu |
890ddd |
if (m_levels[i].getName() == levelName) {
|
|
Toshihiro Shimizu |
890ddd |
if (m_levels[i].getLayerId() == levelId) {
|
|
Toshihiro Shimizu |
890ddd |
break;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
count++;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
if (count > 0) {
|
|
Toshihiro Shimizu |
890ddd |
levelName.append(LEVEL_NAME_INDEX_SEP);
|
|
Shinya Kitaoka |
3bfa54 |
std::string c = QString::number(count).toStdString();
|
|
Toshihiro Shimizu |
890ddd |
levelName.append(c);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
return levelName;
|
|
Toshihiro Shimizu |
890ddd |
}
|