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
Toshihiro Shimizu 890ddd
		if (x0 >= m_headerInfo.cols)
Toshihiro Shimizu 890ddd
			return;
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
Toshihiro Shimizu 890ddd
		if (y0 >= m_headerInfo.rows)
Toshihiro Shimizu 890ddd
			return;
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()) {
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
}
Toshihiro Shimizu 890ddd
int TPSDParser::getLevelIdByName(string levelName)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	int pos = levelName.find_last_of(LEVEL_NAME_INDEX_SEP);
Toshihiro Shimizu 890ddd
	int counter = 0;
Toshihiro Shimizu 890ddd
	if (pos != 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
}
Toshihiro Shimizu 890ddd
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
}
Toshihiro Shimizu 890ddd
string TPSDParser::getLevelNameWithCounter(int levelId)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	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);
Toshihiro Shimizu 890ddd
		string c = QString::number(count).toStdString();
Toshihiro Shimizu 890ddd
		levelName.append(c);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	return levelName;
Toshihiro Shimizu 890ddd
}