Rev 17163 |
Go to most recent revision |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
/*
For general Scribus (>=1.3.2) copyright and licensing information please refer
to the COPYING file provided with the program. Following this notice may exist
a copyright and/or license notice that predates the release of Scribus 1.3.2
for which a new license (GPL+exception) is in place.
*/
#include "scconfig.h"
#include "scimgdataloader_psd.h"
#include "sccolorengine.h"
#include "util_color.h"
#include "colormgmt/sccolormgmtengine.h"
#include <QFile>
#include <QFileInfo>
#include <QList>
static QDataStream & operator>> ( QDataStream & s, PSDHeader & header )
{
s >> header.signature;
s >> header.version;
for( int i = 0; i < 6; i++ )
{
s >> header.reserved[i];
}
s >> header.channel_count;
s >> header.height;
s >> header.width;
s >> header.depth;
s >> header.color_mode;
return s;
}
ScImgDataLoader_PSD::ScImgDataLoader_PSD(void)
{
initSupportedFormatList();
}
void ScImgDataLoader_PSD::initSupportedFormatList(void)
{
m_supportedFormats.clear();
m_supportedFormats.append( "psd" );
}
void ScImgDataLoader_PSD::loadEmbeddedProfile(const QString& fn, int /*page*/)
{
m_embeddedProfile.resize(0);
m_profileComponents = 0;
ScColorProfile prof;
QFileInfo fi = QFileInfo(fn);
if (!fi.exists())
return;
QString ext = fi.suffix().toLower();
if (ext == "psd")
{
QFile f(fn);
if (f.open(QIODevice::ReadOnly))
{
m_imageInfoRecord.xres = 72;
m_imageInfoRecord.yres = 72;
QDataStream s( &f );
s.setByteOrder( QDataStream::BigEndian );
PSDHeader header;
s >> header;
// Check image file format.
if( s.atEnd() || !IsValid( header ) )
return;
// Check if it's a supported format.
if( !IsSupported( header ) )
return;
if( !LoadPSDResources(s, header, s.device()->pos()) )
return;
if (m_embeddedProfile.size() > 0)
{
prof = ScColorMgmtEngine::openProfileFromMem(m_embeddedProfile);
if (prof)
{
if (prof.colorSpace() == ColorSpace_Rgb)
m_profileComponents = 3;
if (prof.colorSpace() == ColorSpace_Cmyk)
m_profileComponents = 4;
if (prof.colorSpace() == ColorSpace_Gray)
m_profileComponents = 1;
}
}
f.close();
}
else
return;
}
}
bool ScImgDataLoader_PSD::preloadAlphaChannel(const QString& fn, int /*page*/, int res, bool& hasAlpha)
{
bool valid = m_imageInfoRecord.isRequest;
QMap<int, ImageLoadRequest> req = m_imageInfoRecord.RequestProps;
initialize();
hasAlpha = false;
m_imageInfoRecord.RequestProps = req;
m_imageInfoRecord.isRequest = valid;
QFileInfo fi = QFileInfo(fn);
if (!fi.exists())
return false;
QFile f(fn);
if (f.open(QIODevice::ReadOnly))
{
QDataStream s( &f );
s.setByteOrder( QDataStream::BigEndian );
PSDHeader header;
s >> header;
// Check image file format.
if( s.atEnd() || !IsValid( header ) )
return false;
// Check if it's a supported format.
if( !IsSupported( header ) )
return false;
if( !LoadPSD(s, header) )
r_image.resize(0);
f.close();
m_imageInfoRecord.valid = true;
if (header.color_mode == CM_CMYK)
m_imageInfoRecord.valid = hasAlpha = (maxChannels > 4);
else if (header.color_mode == CM_GRAYSCALE)
m_imageInfoRecord.valid = hasAlpha = (maxChannels > 1);
else
m_imageInfoRecord.valid = hasAlpha = (maxChannels >= 4);
return true;
}
return false;
}
bool ScImgDataLoader_PSD::loadPicture(const QString& fn, int /*page*/, int res, bool thumbnail)
{
bool isCMYK = false;
float xres = 72.0, yres = 72.0;
if (!QFile::exists(fn))
return false;
bool valid = m_imageInfoRecord.isRequest;
QMap<int, ImageLoadRequest> req = m_imageInfoRecord.RequestProps;
initialize();
m_imageInfoRecord.RequestProps = req;
m_imageInfoRecord.isRequest = valid;
m_imageInfoRecord.type = ImageTypePSD;
m_imageInfoRecord.exifDataValid = false;
m_imageInfoRecord.layerInfo.clear();
m_imageInfoRecord.PDSpathData.clear();
QFile f(fn);
if (f.open(QIODevice::ReadOnly))
{
m_imageInfoRecord.xres = 72;
m_imageInfoRecord.yres = 72;
QDataStream s( &f );
s.setByteOrder( QDataStream::BigEndian );
PSDHeader header;
s >> header;
// Check image file format.
if( s.atEnd() || !IsValid( header ) )
return false;
// Check if it's a supported format.
if( !IsSupported( header ) )
return false;
if (thumbnail)
header.reserved[0] = 't';
if( !LoadPSD(s, header) )
return false;
if (m_embeddedProfile.size() > 0)
{
ScColorProfile prof = ScColorMgmtEngine::openProfileFromMem(m_embeddedProfile);
m_imageInfoRecord.profileName = prof.productDescription();
m_imageInfoRecord.isEmbedded = true;
}
if (header.color_mode == CM_CMYK)
isCMYK = true;
else
isCMYK = false;
if (header.color_mode == CM_CMYK)
m_imageInfoRecord.colorspace = ColorSpaceCMYK;
else if (header.color_mode == CM_RGB)
m_imageInfoRecord.colorspace = ColorSpaceRGB;
else if (header.color_mode == CM_GRAYSCALE)
m_imageInfoRecord.colorspace = ColorSpaceGray;
else if (header.color_mode == CM_DUOTONE)
m_imageInfoRecord.colorspace = ColorSpaceDuotone;
xres = m_imageInfoRecord.xres;
yres = m_imageInfoRecord.yres;
f.close();
if (thumbnail)
{
if (!m_imageInfoRecord.exifInfo.thumbnail.isNull())
{
if (isCMYK)
r_image.create(m_imageInfoRecord.exifInfo.thumbnail.width(), m_imageInfoRecord.exifInfo.thumbnail.height(), 5);
else
r_image.create(m_imageInfoRecord.exifInfo.thumbnail.width(), m_imageInfoRecord.exifInfo.thumbnail.height(), 4);
QRgb *s;
unsigned char cc, cm, cy, ck;
uchar *d;
for( int yit=0; yit < m_imageInfoRecord.exifInfo.thumbnail.height(); ++yit )
{
s = (QRgb*)(m_imageInfoRecord.exifInfo.thumbnail.scanLine( yit ));
d = r_image.scanLine( yit );
for(int xit=0; xit < m_imageInfoRecord.exifInfo.thumbnail.width(); ++xit )
{
if (isCMYK)
{
cc = 255 - qRed(*s);
cm = 255 - qGreen(*s);
cy = 255 - qBlue(*s);
ck = qMin(qMin(cc, cm), cy);
d[0] = cc-ck;
d[1] = cm-ck;
d[2] = cy-ck;
d[3] = ck;
d[4] = 255;
}
else
{
d[0] = qRed(*s);
d[1] = qGreen(*s);
d[2] = qBlue(*s);
d[3] = 255;
}
s++;
d += r_image.channels();
}
}
m_imageInfoRecord.exifInfo.width = header.width;
m_imageInfoRecord.exifInfo.height = header.height;
return true;
}
}
m_imageInfoRecord.exifInfo.width = header.width;
m_imageInfoRecord.exifInfo.height = header.height;
m_imageInfoRecord.BBoxX = 0;
m_imageInfoRecord.BBoxH = r_image.height();
return true;
}
return false;
}
bool ScImgDataLoader_PSD::LoadPSD( QDataStream & s, const PSDHeader & header)
{
// Create dst image.
m_imageInfoRecord.valid = false;
if (header.color_mode == CM_CMYK)
{
if (!r_image.create(header.width, header.height, 5))
return false;
}
else
{
if (!r_image.create(header.width, header.height, 4))
return false;
}
r_image.fill(0);
maxChannels = header.channel_count;
uint tmp;
uint cresStart;
uint cdataStart;
uint ressourceDataLen;
uint startRessource;
cresStart = s.device()->pos();
// Skip mode data. FIX: this is incorrect, it's the Colormap Data for indexed Images
s >> tmp;
cdataStart = s.device()->pos();
LoadPSDResources(s, header, cresStart);
s.device()->seek( cdataStart + tmp );
s >> ressourceDataLen;
startRessource = s.device()->pos();
if ((!m_imageInfoRecord.exifInfo.thumbnail.isNull()) && (header.reserved[0] == 't'))
return true;
bool ret = LoadPSDImgData(s, header, startRessource + ressourceDataLen);
return ret;
}
bool ScImgDataLoader_PSD::LoadPSDResources( QDataStream & s, const PSDHeader & header, uint dataOffset )
{
// Create dst image.
m_imageInfoRecord.valid = false;
uint tmp;
uint cdataStart;
uint ressourceDataLen;
uint startRessource;
s.device()->seek( dataOffset );
srand(314159265);
for (int i = 0; i < 4096; i++)
random_table[i] = rand();
int tmpd;
int swap;
for (int i = 0; i < 4096; i++)
{
swap = i + rand() % (4096 - i);
tmpd = random_table[i];
random_table[i] = random_table[swap];
random_table[swap] = tmpd;
}
// Skip mode data. FIX: this is incorrect, it's the Colormap Data for indexed Images
s >> tmp;
cdataStart = s.device()->pos();
if (tmp != 0)
{
if ((header.color_mode == CM_DUOTONE))
{
short signature;
short count;
unsigned short c, m, y, k;
uchar hc, sc, bc;
ScColor col;
s >> signature;
s >> count;
uint duodataStart = s.device()->pos();
bool specialColour = false;
for (int cda = 0; cda < count; cda++)
{
s >> signature;
s >> c >> m >> y >> k;
switch (signature)
{
case 0: // RGB colour
col.setColorRGB(c >> 8, m >> 8, y >> 8);
colorTableSc.append(col);
break;
case 1: // HSB colour
hc = c >> 8;
sc = m >> 8;
bc = y >> 8;
HSVTORGB(hc, sc, bc);
col.setColorRGB(hc, sc, bc);
colorTableSc.append(col);
break;
case 2: // CMYK colour
col.setColor(c >> 8, m >> 8, y >> 8, k >> 8);
colorTableSc.append(col);
break;
case 3: // Pantone
case 4: // Focoltone
case 5: // Truematch
case 6: // Toyo 88 colorfinder 1050
case 7: // LAB colour space
case 10: // HKS colors
if (colorTableSc.count() == 0)
colorTableSc.append(ScColor(0, 0, 0, 255));
else
colorTableSc.append(ScColor(0, 0, 0, 0));
specialColour = true;
break;
case 8: // Grayscale
c = qRound((c / 10000.0) * 255);
colorTableSc.append(ScColor(0, 0, 0, c));
break;
}
}
if (specialColour) // we will only load the grayscale image data and do the colorizing with the Image Effects;
{
s.device()->seek( duodataStart + 40 );
uint duoNameStart = s.device()->pos();
uint duoCurveStart = duoNameStart+256;
for (int cda = 0; cda < count; cda++)
{
QString colName;
s.device()->seek( duoNameStart + (64 * static_cast<uint>(cda)) );
colName = getPascalString(s);
s.device()->seek( duoCurveStart + (28 * static_cast<uint>(cda)) );
FPointArray tmcu;
tmcu.resize(0);
for (int cu = 0; cu < 13; cu++)
{
short val;
s >> val;
if (val != -1)
tmcu.addPoint(cu * 1.0 / 12.0, val / 1000.0);
}
PSDDuotone_Color colSpec;
colSpec.Name = colName;
colSpec.Color = colorTableSc[cda];
colSpec.Curve = tmcu;
m_imageInfoRecord.duotoneColors.append(colSpec);
}
// Initialize loading curve tables with default values
curveTable1.resize(256);
curveTable2.resize(256);
curveTable3.resize(256);
curveTable4.resize(256);
for (int x = 0 ; x < 256 ; x++)
{
curveTable1[x] = x;
curveTable2[x] = x;
curveTable3[x] = x;
curveTable4[x] = x;
}
}
else
{
s.device()->seek( duodataStart + 40 );
uint duoNameStart = s.device()->pos();
uint duoCurveStart = duoNameStart+256;
for (int cda = 0; cda < count; cda++)
{
s.device()->seek( duoCurveStart + (28 * static_cast<uint>(cda)) );
FPointArray tmcu;
tmcu.resize(0);
for (int cu = 0; cu < 13; cu++)
{
short val;
s >> val;
if (val != -1)
tmcu.addPoint(cu * 1.0 / 12.0, val / 1000.0);
}
if (cda == 0)
{
curveTable1.resize(256);
for (int x = 0 ; x < 256 ; x++)
{
curveTable1[x] = qMin(255, qMax(0, qRound(getCurveYValue(tmcu, x / 255.0) * 255)));
}
}
else if (cda == 1)
{
curveTable2.resize(256);
for (int x = 0 ; x < 256 ; x++)
{
curveTable2[x] = qMin(255, qMax(0, qRound(getCurveYValue(tmcu, x / 255.0) * 255)));
}
}
else if (cda == 2)
{
curveTable3.resize(256);
for (int x = 0 ; x < 256 ; x++)
{
curveTable3[x] = qMin(255, qMax(0, qRound(getCurveYValue(tmcu, x / 255.0) * 255)));
}
}
else if (cda == 3)
{
curveTable4.resize(256);
for (int x = 0 ; x < 256 ; x++)
{
curveTable4[x] = qMin(255, qMax(0, qRound(getCurveYValue(tmcu, x / 255.0) * 255)));
}
}
}
}
}
else
{
QList<uchar> colorTableR;
QList<uchar> colorTableG;
QList<uchar> colorTableB;
colorTableR.clear();
colorTableG.clear();
colorTableB.clear();
colorTable.clear();
uchar r;
for (uint cc = 0; cc < 256; cc++)
{
s >> r;
colorTableR.append(r);
}
for (uint cc = 0; cc < 256; cc++)
{
s >> r;
colorTableG.append(r);
}
for (uint cc = 0; cc < 256; cc++)
{
s >> r;
colorTableB.append(r);
}
for (uint cc = 0; cc < 256; cc++)
{
colorTable.append(qRgb(colorTableR[cc], colorTableG[cc], colorTableB[cc]));
}
}
}
s.device()->seek( cdataStart + tmp );
s >> ressourceDataLen;
startRessource = s.device()->pos();
if (ressourceDataLen != 0)
parseRessourceData(s, header, ressourceDataLen);
return true;
}
bool ScImgDataLoader_PSD::LoadPSDImgData( QDataStream & s, const PSDHeader & header, uint dataOffset )
{
uint layerDataLen;
uint startLayers;
s.device()->seek( dataOffset );
// Skip the reserved data. FIX: Also incorrect, this is the actual Layer Data for Images with Layers
s >> layerDataLen;
startLayers = s.device()->pos();
if (layerDataLen != 0)
{
bool re = parseLayer(s, header);
if (re)
{
m_imageInfoRecord.valid = true;
return re;
}
else
{
// Try to decode simple psd file, no layers
s.device()->seek(startLayers + layerDataLen);
if(s.atEnd())
return false;
return loadLayer( s, header);
}
}
else
{
// Decoding simple psd file, no layers
s.device()->seek( s.device()->pos() + layerDataLen );
loadLayer( s, header);
}
return true;
}
bool ScImgDataLoader_PSD::parseLayer( QDataStream & s, const PSDHeader & header )
{
uint addRes, layerinfo, channelLen, signature, extradata, layermasksize, layerRange, dummy;
int top, left, bottom, right;
short numLayers, numChannels;
short channelType;
uchar blendKey[4];
uchar opacity, clipping, flags, filler;
QString layerName, blend;
struct PSDLayer lay;
s >> layerinfo;
s >> numLayers;
if (numLayers < 0)
numLayers = -numLayers;
if (numLayers != 0)
{
for (int layer = 0; layer < numLayers; layer++)
{
s >> top;
lay.ypos = top;
s >> left;
lay.xpos = left;
s >> bottom;
lay.height = bottom - top;
s >> right;
lay.width = right - left;
s >> numChannels;
// Qt4 check these conversions
maxChannels = qMax(maxChannels, (int)numChannels);
if (numChannels > 6) // we don't support images with more than 6 channels yet
{
m_imageInfoRecord.layerInfo.clear();
return false;
}
lay.channelType.clear();
lay.channelLen.clear();
for (int channels = 0; channels < numChannels; channels++)
{
s >> channelType;
s >> channelLen;
lay.channelType.append(channelType);
lay.channelLen.append(channelLen);
}
s >> signature;
blend = "";
for( int i = 0; i < 4; i++ )
{
s >> blendKey[i];
blend += QChar(blendKey[i]);
}
lay.blend = blend;
s >> opacity;
lay.opacity = opacity;
s >> clipping;
lay.clipping = clipping;
s >> flags;
if (flags & 8)
{
if (flags & 16) // Unknown combination of layer flags, probably an adjustment or effects layer
{
m_imageInfoRecord.layerInfo.clear();
return false;
}
}
lay.flags = flags;
s >> filler;
s >> extradata;
s >> layermasksize;
lay.maskYpos = 0;
lay.maskXpos = 0;
lay.maskHeight = 0;
lay.maskWidth = 0;
if (layermasksize != 0)
{
s >> lay.maskYpos;
s >> lay.maskXpos;
s >> dummy;
lay.maskHeight = dummy - lay.maskYpos;
s >> dummy;
lay.maskWidth = dummy - lay.maskXpos;
s >> dummy;
}
s >> layerRange;
s.device()->seek( s.device()->pos() + layerRange );
lay.layerName = getLayerString(s);
m_imageInfoRecord.layerInfo.append(lay);
s >> signature;
if( signature == 0x3842494D )
{
while (signature == 0x3842494D )
{
s >> signature;
s >> addRes;
s.device()->seek( s.device()->pos() + addRes );
s >> signature;
}
s.device()->seek( s.device()->pos() - 4 );
}
else
{
s.device()->seek( s.device()->pos() - 2 );
s >> signature;
if( signature == 0x3842494D )
{
while (signature == 0x3842494D )
{
s >> signature;
s >> addRes;
s.device()->seek( s.device()->pos() + addRes );
s >> signature;
}
s.device()->seek( s.device()->pos() - 4 );
}
else
s.device()->seek( s.device()->pos() - 6 );
}
}
bool firstLayer = true;
for (int layer = 0; layer < numLayers; layer++)
{
loadLayerChannels( s, header, m_imageInfoRecord.layerInfo, layer, &firstLayer );
}
}
else
{
s >> numLayers;
loadLayer( s, header);
}
return true;
}
bool ScImgDataLoader_PSD::loadChannel( QDataStream & s, const PSDHeader & header, QList<PSDLayer> &layerInfo, uint layer, int channel, int component, RawImage &tmpImg)
{
uint base = s.device()->pos();
uchar cbyte;
ushort compression;
s >> compression;
if( compression > 1 )
return false;
if (compression == 0)
{
int count = layerInfo[layer].channelLen[channel]-2;
uchar *ptr;
for (int i = 0; i < tmpImg.height(); i++)
{
ptr = tmpImg.scanLine(i);
for (int j = 0; j < tmpImg.width(); j++)
{
s >> cbyte;
count--;
if ((header.color_mode == CM_CMYK) && (component < 4))
cbyte = 255 - cbyte;
if ((header.color_mode == CM_GRAYSCALE) && (component != 3))
{
ptr[0] = cbyte;
ptr[1] = cbyte;
ptr[2] = cbyte;
}
else if ((header.color_mode == CM_DUOTONE) && (component != 3))
{
ptr -= component;
putDuotone(ptr, cbyte);
ptr += component;
}
else if ((header.color_mode == CM_INDEXED) && (component != 3))
{
int ccol = colorTable[cbyte];
ptr[0] = qRed(ccol);
ptr[1] = qGreen(ccol);
ptr[2] = qBlue(ccol);
}
else
ptr[component] = cbyte;
if (count == 0)
break;
ptr += tmpImg.channels();
}
if (count == 0)
break;
}
}
else
{
s.device()->seek( s.device()->pos() + tmpImg.height() * 2 );
uint pixel_count = tmpImg.width();
uchar *ptr;
uchar *ptr2;
uint count, len;
uchar c;
for (int hh = 0; hh < tmpImg.height(); hh++)
{
count = 0;
ptr = tmpImg.scanLine(hh);
ptr2 = ptr+tmpImg.width() * tmpImg.channels();
ptr += component;
while( count < pixel_count )
{
if(s.atEnd())
return false;
s >> c;
len = c;
if( len < 128 )
{
// Copy next len+1 bytes literally.
len++;
count += len;
while( len != 0 )
{
s >> cbyte;
if (ptr < ptr2)
{
if ((header.color_mode == CM_CMYK) && (component < 4))
cbyte = 255 - cbyte;
if ((header.color_mode == CM_GRAYSCALE) && (component != 3))
{
ptr -= component;
ptr[0] = cbyte;
ptr[1] = cbyte;
ptr[2] = cbyte;
ptr += component;
}
else if ((header.color_mode == CM_DUOTONE) && (component != 3))
{
ptr -= component;
putDuotone(ptr, cbyte);
ptr += component;
}
else if ((header.color_mode == CM_INDEXED) && (component != 3))
{
ptr -= component;
int ccol = colorTable[cbyte];
ptr[0] = qRed(ccol);
ptr[1] = qGreen(ccol);
ptr[2] = qBlue(ccol);
ptr += component;
}
else
{
*ptr = cbyte;
}
}
ptr += tmpImg.channels();
len--;
}
}
else if( len > 128 )
{
// Next -len+1 bytes in the dest are replicated from next source byte.
// (Interpret len as a negative 8-bit int.)
len ^= 0xFF;
len += 2;
count += len;
uchar val;
s >> val;
if ((header.color_mode == CM_CMYK) && (component < 4))
val = 255 - val;
while( len != 0 )
{
if (ptr < ptr2)
{
if ((header.color_mode == CM_GRAYSCALE) && (component != 3))
{
ptr -= component;
ptr[0] = val;
ptr[1] = val;
ptr[2] = val;
ptr += component;
}
else if ((header.color_mode == CM_DUOTONE) && (component != 3))
{
ptr -= component;
putDuotone(ptr, val);
ptr += component;
}
else if ((header.color_mode == CM_INDEXED) && (component != 3))
{
ptr -= component;
int ccol = colorTable[val];
ptr[0] = qRed(ccol);
ptr[1] = qGreen(ccol);
ptr[2] = qBlue(ccol);
ptr += component;
}
else
*ptr = val;
}
ptr += tmpImg.channels();
len--;
}
}
else if( len == 128 )
{
// No-op.
}
}
}
}
s.device()->seek( base+layerInfo[layer].channelLen[channel] );
return true;
}
bool ScImgDataLoader_PSD::loadLayerChannels( QDataStream & s, const PSDHeader & header, QList<PSDLayer> &layerInfo, uint layer, bool* firstLayer)
{
// Find out if the data is compressed.
// Known values:
// 0: no compression
// 1: RLE compressed
uint base = s.device()->pos();
uint base2 = base;
uint channel_num = layerInfo[layer].channelLen.count();
bool hasMask = false;
bool hasAlpha = false;
RawImage r2_image;
RawImage mask;
bool createOk = false;
if (header.color_mode == CM_CMYK)
{
createOk = r2_image.create(layerInfo[layer].width, layerInfo[layer].height, qMax(channel_num, (uint)5));
r2_image.fill(0);
}
else
{
createOk = r2_image.create(layerInfo[layer].width, layerInfo[layer].height, qMax(channel_num, (uint)4));
r2_image.fill(0);
}
if( !createOk )
{
for(uint channel = 0; channel < channel_num; channel++)
{
base2 += layerInfo[layer].channelLen[channel];
}
s.device()->seek( base2 );
return false;
}
channel_num = qMin(channel_num, (uint)39);
uint components[40];
for(uint channel = 0; channel < channel_num; channel++)
{
switch(layerInfo[layer].channelType[channel])
{
case 0:
components[channel] = 0;
break;
case 1:
components[channel] = 1;
break;
case 2:
components[channel] = 2;
break;
case 3:
components[channel] = 3;
break;
case -1:
if (header.color_mode == CM_CMYK)
{
if (channel_num == 6)
components[channel] = channel_num-2;
else
components[channel] = channel_num-1;
}
else
{
if (channel_num == 5)
components[channel] = channel_num-2;
else
{
if (header.color_mode == CM_GRAYSCALE)
components[channel] = 3;
else
components[channel] = channel_num-1;
}
}
hasAlpha = true;
break;
case -2:
components[channel] = channel_num-1;
break;
}
}
if (!hasAlpha)
r2_image.fill(255);
for(uint channel = 0; channel < channel_num; channel++)
{
if (layerInfo[layer].channelType[channel] == -2)
{
if (!mask.create( layerInfo[layer].maskWidth, layerInfo[layer].maskHeight, 1 ))
break;
mask.fill(0);
if (!loadChannel(s, header, layerInfo, layer, channel, 0, mask))
break;
hasMask = true;
}
if (!loadChannel(s, header, layerInfo, layer, channel, components[channel], r2_image))
break;
}
for(uint channel = 0; channel < channel_num; channel++)
{
base2 += layerInfo[layer].channelLen[channel];
}
if (header.color_mode == CM_LABCOLOR)
{
ScColorProfile hsRGB = ScColorMgmtEngine::createProfile_sRGB();
ScColorProfile hLab = ScColorMgmtEngine::createProfile_Lab();
ScColorTransform xform = ScColorMgmtEngine::createTransform(hLab, Format_LabA_8, hsRGB, Format_RGBA_8, Intent_Perceptual, 0);
for (int i = 0; i < r2_image.height(); i++)
{
uchar* ptr = r2_image.scanLine(i);
xform.apply(ptr, ptr, r2_image.width());
}
}
s.device()->seek( base2 );
QImage tmpImg2;
if (header.color_mode == CM_CMYK)
tmpImg2 = r2_image.convertToQImage(true);
else
tmpImg2 = r2_image.convertToQImage(false);
QImage imt;
double sx = tmpImg2.width() / 40.0;
double sy = tmpImg2.height() / 40.0;
imt = sy < sx ? tmpImg2.scaled(qRound(tmpImg2.width() / sx), qRound(tmpImg2.height() / sx), Qt::IgnoreAspectRatio, Qt::SmoothTransformation) :
tmpImg2.scaled(qRound(tmpImg2.width() / sy), qRound(tmpImg2.height() / sy), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
layerInfo[layer].thumb = imt.copy();
if (hasMask)
{
QImage imt2;
QImage tmpImg;
tmpImg = mask.convertToQImage(true);
double sx = tmpImg.width() / 40.0;
double sy = tmpImg.height() / 40.0;
imt2 = sy < sx ? tmpImg.scaled(qRound(tmpImg.width() / sx), qRound(tmpImg.height() / sx), Qt::IgnoreAspectRatio, Qt::SmoothTransformation) :
tmpImg.scaled(qRound(tmpImg.width() / sy), qRound(tmpImg.height() / sy), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
imt2.invertPixels();
layerInfo[layer].thumb_mask = imt2.copy();
}
else
layerInfo[layer].thumb_mask = QImage();
if (!m_imageInfoRecord.isRequest || !m_imageInfoRecord.RequestProps.contains(layer))
m_imageInfoRecord.RequestProps[layer].useMask = true;
bool visible = !(layerInfo[layer].flags & 2);
if ((m_imageInfoRecord.isRequest) && (m_imageInfoRecord.RequestProps.contains(layer)))
visible = m_imageInfoRecord.RequestProps[layer].visible;
if (visible)
{
unsigned int startSrcY, startSrcX, startDstY, startDstX;
if (layerInfo[layer].ypos < 0)
{
startSrcY = abs(layerInfo[layer].ypos);
startDstY = 0;
}
else
{
startSrcY = 0;
startDstY = layerInfo[layer].ypos;
}
if (layerInfo[layer].xpos < 0)
{
startSrcX = abs(layerInfo[layer].xpos);
startDstX = 0;
}
else
{
startSrcX = 0;
startDstX = layerInfo[layer].xpos;
}
unsigned int startSrcYm, startSrcXm, startDstYm, startDstXm;
if (layerInfo[layer].maskYpos < 0)
{
startSrcYm = abs(layerInfo[layer].maskYpos);
startDstYm = 0;
}
else
{
startSrcYm = 0;
startDstYm = layerInfo[layer].maskYpos;
}
if (layerInfo[layer].maskXpos < 0)
{
startSrcXm = abs(layerInfo[layer].maskXpos);
startDstXm = 0;
}
else
{
startSrcXm = 0;
startDstXm = layerInfo[layer].maskXpos;
}
QString layBlend2 = layerInfo[layer].blend;
if ((m_imageInfoRecord.isRequest) && (m_imageInfoRecord.RequestProps.contains(layer)))
layBlend2 = m_imageInfoRecord.RequestProps[layer].blend;
if (layBlend2 == "diss")
{
hasAlpha = true;
int layOpa = layerInfo[layer].opacity;
if ((m_imageInfoRecord.isRequest) && (m_imageInfoRecord.RequestProps.contains(layer)))
layOpa = m_imageInfoRecord.RequestProps[layer].opacity;
for (int l = 0; l < r2_image.height(); l++)
{
srand(random_table[ l % 4096]);
for (int k = 0; k < r2_image.width(); k++)
{
int rand_val = rand() & 0xff;
if (rand_val > layOpa)
r2_image.setAlpha(k, l, 0);
}
}
}
if (*firstLayer)
{
unsigned char *s;
unsigned char *d;
for( int yi=static_cast<int>(startSrcY); yi < qMin(r2_image.height(), r_image.height()); ++yi )
{
s = r2_image.scanLine( yi );
d = r_image.scanLine( qMin(static_cast<int>(startDstY), r_image.height()-1) );
d += qMin(static_cast<int>(startDstX), r_image.width()-1) * r_image.channels();
s += qMin(static_cast<int>(startSrcX), r2_image.width()-1) * r2_image.channels();
for(int xi=static_cast<int>(startSrcX); xi < qMin(r2_image.width(), r_image.width()); ++xi )
{
d[0] = s[0];
d[1] = s[1];
d[2] = s[2];
if (header.color_mode != CM_CMYK)
{
if (hasAlpha)
d[3] = s[3];
else
d[3] = 255;
}
else
{
d[3] = s[3];
if (hasAlpha)
d[4] = s[4];
else
d[4] = 255;
}
s += r2_image.channels();
d += r_image.channels();
}
startDstY++;
}
}
else
{
unsigned char *s;
unsigned char *d;
unsigned char *sm = 0;
unsigned char r, g, b, src_r, src_g, src_b, src_a, src_alpha, dst_alpha;
unsigned char a = 0;
uchar new_r, new_g, new_b;
unsigned int maxDestX;
for (int i = static_cast<int>(startSrcY); i < layerInfo[layer].height; i++)
{
d = r_image.scanLine(qMin(static_cast<int>(startDstY), r_image.height()-1));
s = r2_image.scanLine(qMin(i, r2_image.height()-1));
d += qMin(static_cast<int>(startDstX), r_image.width()-1) * r_image.channels();
s += qMin(static_cast<int>(startSrcX), r2_image.width()-1) * r2_image.channels();
sm = 0;
if (hasMask)
{
sm = mask.scanLine(qMin(i, mask.height()-1));
sm += qMin(static_cast<int>(startSrcXm), mask.width()-1) * mask.channels();
}
startDstY++;
maxDestX = r_image.width() - startDstX + startSrcX - 1;
for (unsigned int j = startSrcX; j < qMin(maxDestX, static_cast<unsigned int>(layerInfo[layer].width)); j++)
{
src_r = s[0];
src_g = s[1];
src_b = s[2];
src_a = s[3];
if (hasAlpha)
{
if (hasMask)
{
if (m_imageInfoRecord.RequestProps[layer].useMask)
src_alpha = sm[0];
else
src_alpha = s[channel_num - 2];
}
else
{
if (header.color_mode == CM_GRAYSCALE)
src_alpha = s[3];
else
src_alpha = s[channel_num - 1];
}
}
else
src_alpha = 255;
if ((hasMask) && (m_imageInfoRecord.RequestProps[layer].useMask))
src_alpha = sm[0];
int layOpa = layerInfo[layer].opacity;
if ((m_imageInfoRecord.isRequest) && (m_imageInfoRecord.RequestProps.contains(layer)))
layOpa = m_imageInfoRecord.RequestProps[layer].opacity;
QString layBlend = layerInfo[layer].blend;
if ((m_imageInfoRecord.isRequest) && (m_imageInfoRecord.RequestProps.contains(layer)))
layBlend = m_imageInfoRecord.RequestProps[layer].blend;
if (layBlend != "diss")
src_alpha = INT_MULT(src_alpha, layOpa);
if (header.color_mode == CM_CMYK)
dst_alpha = d[4];
else
dst_alpha = d[3];
if ((dst_alpha > 0) && (src_alpha > 0))
{
if (layBlend == "mul ")
{
src_r = INT_MULT(src_r, d[0]);
src_g = INT_MULT(src_g, d[1]);
src_b = INT_MULT(src_b, d[2]);
if (header.color_mode == CM_CMYK)
src_a = INT_MULT(src_a, d[3]);
}
else if (layBlend == "scrn")
{
src_r = 255 - ((255-src_r) * (255-d[0]) / 128);
src_g = 255 - ((255-src_g) * (255-d[1]) / 128);
src_b = 255 - ((255-src_b) * (255-d[2]) / 128);
if (header.color_mode == CM_CMYK)
src_a = 255 - ((255-src_a) * (255-d[3]) / 128);
}
else if (layBlend == "over")
{
src_g = d[1] < 128 ? src_g * d[1] / 128 : 255 - ((255-src_g) * (255-d[1]) / 128);
src_b = d[2] < 128 ? src_b * d[2] / 128 : 255 - ((255-src_b) * (255-d[2]) / 128);
src_a = d[3] < 128 ? src_a * d[3] / 128 : 255 - ((255-src_a) * (255-d[3]) / 128);
if (header.color_mode == CM_CMYK)
src_r = d[0] < 128 ? src_r * d[0] / 128 : 255 - ((255-src_r) * (255-d[0]) / 128);
}
else if (layBlend == "diff")
{
src_r = d[0] > src_r ? d[0] - src_r : src_r - d[0];
src_g = d[1] > src_g ? d[1] - src_g : src_g - d[1];
src_b = d[2] > src_b ? d[2] - src_b : src_b - d[2];
if (header.color_mode == CM_CMYK)
src_a = d[3] > src_a ? d[3] - src_a : src_a - d[3];
}
else if (layBlend == "dark")
{
src_r = d[0] < src_r ? d[0] : src_r;
src_g = d[1] < src_g ? d[1] : src_g;
src_b = d[2] < src_b ? d[2] : src_b;
if (header.color_mode == CM_CMYK)
src_a = d[3] < src_a ? d[3] : src_a;
}
else if (layBlend == "hLit")
{
src_r = src_r < 128 ? src_r * d[0] / 128 : 255 - ((255-src_r) * (255-d[0]) / 128);
src_g = src_g < 128 ? src_g * d[1] / 128 : 255 - ((255-src_g) * (255-d[1]) / 128);
src_b = src_b < 128 ? src_b * d[2] / 128 : 255 - ((255-src_b) * (255-d[2]) / 128);
if (header.color_mode == CM_CMYK)
src_a = src_a < 128 ? src_a * d[3] / 128 : 255 - ((255-src_a) * (255-d[3]) / 128);
}
else if (layBlend == "sLit")
{
src_r = src_r * d[0] / 256 + src_r * (255 - ((255-src_r)*(255-d[0]) / 256) - src_r * d[0] / 256) / 256;
src_g = src_g * d[1] / 256 + src_g * (255 - ((255-src_g)*(255-d[1]) / 256) - src_g * d[1] / 256) / 256;
src_b = src_b * d[2] / 256 + src_b * (255 - ((255-src_b)*(255-d[2]) / 256) - src_b * d[2] / 256) / 256;
if (header.color_mode == CM_CMYK)
src_a = src_a * d[3] / 256 + src_a * (255 - ((255-src_a)*(255-d[3]) / 256) - src_a * d[3] / 256) / 256;
}
else if (layBlend == "lite")
{
src_r = d[0] < src_r ? src_r : d[0];
src_g = d[1] < src_g ? src_g : d[1];
src_b = d[2] < src_b ? src_b : d[2];
if (header.color_mode == CM_CMYK)
src_a = d[3] < src_a ? src_a : d[3];
}
else if (layBlend == "smud")
{
src_r = d[0] + src_r - src_r * d[0] / 128;
src_g = d[1] + src_g - src_g * d[1] / 128;
src_b = d[2] + src_b - src_b * d[2] / 128;
if (header.color_mode == CM_CMYK)
src_a = d[3] + src_a - src_a * d[3] / 128;
}
else if (layBlend == "div ")
{
src_r = src_r == 255 ? 255 : ((d[0] * 256) / (255-src_r)) > 255 ? 255 : (d[0] * 256) / (255-src_r);
src_g = src_g == 255 ? 255 : ((d[1] * 256) / (255-src_g)) > 255 ? 255 : (d[1] * 256) / (255-src_g);
src_b = src_b == 255 ? 255 : ((d[2] * 256) / (255-src_b)) > 255 ? 255 : (d[2] * 256) / (255-src_b);
if (header.color_mode == CM_CMYK)
src_a = src_a == 255 ? 255 : ((d[3] * 256) / (255-src_a)) > 255 ? 255 : (d[3] * 256) / (255-src_a);
}
else if (layBlend == "idiv")
{
src_r = src_r == 0 ? 0 : (255 - (((255-d[0]) * 256) / src_r)) < 0 ? 0 : 255 - (((255-d[0]) * 256) / src_r);
src_g = src_g == 0 ? 0 : (255 - (((255-d[1]) * 256) / src_g)) < 0 ? 0 : 255 - (((255-d[1]) * 256) / src_g);
src_b = src_b == 0 ? 0 : (255 - (((255-d[2]) * 256) / src_b)) < 0 ? 0 : 255 - (((255-d[2]) * 256) / src_b);
if (header.color_mode == CM_CMYK)
src_a = src_a == 0 ? 0 : (255 - (((255-d[3]) * 256) / src_a)) < 0 ? 0 : 255 - (((255-d[3]) * 256) / src_a);
}
else if (layBlend == "hue ")
{
if (header.color_mode != CM_CMYK)
{
new_r = d[0];
new_g = d[1];
new_b = d[2];
RGBTOHSV(src_r, src_g, src_b);
RGBTOHSV(new_r, new_g, new_b);
new_r = src_r;
HSVTORGB(new_r, new_g, new_b);
src_r = new_r;
src_g = new_g;
src_b = new_b;
}
}
else if (layBlend == "sat ")
{
if (header.color_mode != CM_CMYK)
{
new_r = d[0];
new_g = d[1];
new_b = d[2];
RGBTOHSV(src_r, src_g, src_b);
RGBTOHSV(new_r, new_g, new_b);
new_g = src_g;
HSVTORGB(new_r, new_g, new_b);
src_r = new_r;
src_g = new_g;
src_b = new_b;
}
}
else if (layBlend == "lum ")
{
if (header.color_mode != CM_CMYK)
{
new_r = d[0];
new_g = d[1];
new_b = d[2];
RGBTOHSV(src_r, src_g, src_b);
RGBTOHSV(new_r, new_g, new_b);
new_b = src_b;
HSVTORGB(new_r, new_g, new_b);
src_r = new_r;
src_g = new_g;
src_b = new_b;
}
}
else if (layBlend == "colr")
{
if (header.color_mode != CM_CMYK)
{
new_r = d[0];
new_g = d[1];
new_b = d[2];
RGBTOHLS(src_r, src_g, src_b);
RGBTOHLS(new_r, new_g, new_b);
new_r = src_r;
new_b = src_b;
HLSTORGB(new_r, new_g, new_b);
src_r = new_r;
src_g = new_g;
src_b = new_b;
}
}
}
if (dst_alpha == 0)
{
r = src_r;
g = src_g;
b = src_b;
a = src_a;
}
else
{
if (src_alpha > 0)
{
r = (d[0] * (255 - src_alpha) + src_r * src_alpha) / 255;
g = (d[1] * (255 - src_alpha) + src_g * src_alpha) / 255;
b = (d[2] * (255 - src_alpha) + src_b * src_alpha) / 255;
if (header.color_mode == CM_CMYK)
a = (d[3] * (255 - src_alpha) + src_a * src_alpha) / 255;
if (layBlend != "diss")
src_alpha = dst_alpha + INT_MULT(255 - dst_alpha, src_alpha);
}
}
if (src_alpha > 0)
{
d[0] = r;
d[1] = g;
d[2] = b;
if (header.color_mode == CM_CMYK)
{
d[3] = a;
d[4] = src_alpha;
}
else
d[3] = src_alpha;
}
s += r2_image.channels();
d += r_image.channels();
if (hasMask)
sm += mask.channels();
}
}
}
}
*firstLayer = false;
return true;
}
bool ScImgDataLoader_PSD::loadLayer( QDataStream & s, const PSDHeader & header )
{
// Find out if the data is compressed.
// Known values:
// 0: no compression
// 1: RLE compressed
ushort compression;
uchar cbyte;
s >> compression;
if( compression > 1 )
{
// Unknown compression type.
return false;
}
uint channel_num = header.channel_count;
r_image.fill(255);
const uint pixel_count = header.height * header.width;
static const uint components[5] = {0, 1, 2, 3, 4};
if( compression )
{
// Skip row lengths.
ushort w;
for(uint i = 0; i < header.height * header.channel_count; i++)
{
s >> w;
}
// Read RLE data.
uchar * ptr;
uint count = 0;
uchar c;
uint len;
for(uint channel = 0; channel < channel_num; channel++)
{
ptr = r_image.bits() + components[channel];
count = 0;
while( count < pixel_count )
{
if(s.atEnd())
return false;
s >> c;
len = c;
if( len < 128 )
{
// Copy next len+1 bytes literally.
len++;
count += len;
if ( count > pixel_count )
return false;
while( len != 0 )
{
s >> cbyte;
if ((header.color_mode == CM_CMYK) && (components[channel] < 4))
cbyte = 255 - cbyte;
if ((header.color_mode == CM_GRAYSCALE) && (components[channel] != 3))
{
ptr -= components[channel];
ptr[0] = cbyte;
ptr[1] = cbyte;
ptr[2] = cbyte;
ptr += components[channel];
}
else if ((header.color_mode == CM_DUOTONE) && (components[channel] != 3))
{
ptr -= components[channel];
putDuotone(ptr, cbyte);
ptr += components[channel];
}
else if ((header.color_mode == CM_INDEXED) && (components[channel] != 3))
{
ptr -= components[channel];
int ccol = colorTable[cbyte];
ptr[0] = qRed(ccol);
ptr[1] = qGreen(ccol);
ptr[2] = qBlue(ccol);
ptr += components[channel];
}
else
*ptr = cbyte;
ptr += r_image.channels();
len--;
}
}
else if( len > 128 )
{
// Next -len+1 bytes in the dest are replicated from next source byte.
// (Interpret len as a negative 8-bit int.)
len ^= 0xFF;
len += 2;
count += len;
if(s.atEnd() || count > pixel_count)
return false;
uchar val;
s >> val;
if ((header.color_mode == CM_CMYK) && (components[channel] < 4))
val = 255 - val;
while( len != 0 )
{
if ((header.color_mode == CM_GRAYSCALE) && (components[channel] != 3))
{
ptr -= components[channel];
ptr[0] = val;
ptr[1] = val;
ptr[2] = val;
ptr += components[channel];
}
else if ((header.color_mode == CM_DUOTONE) && (components[channel] != 3))
{
ptr -= components[channel];
putDuotone(ptr, val);
ptr += components[channel];
}
else if ((header.color_mode == CM_INDEXED) && (components[channel] != 3))
{
ptr -= components[channel];
int ccol = colorTable[val];
ptr[0] = qRed(ccol);
ptr[1] = qGreen(ccol);
ptr[2] = qBlue(ccol);
ptr += components[channel];
}
else
*ptr = val;
ptr += r_image.channels();
len--;
}
}
else if( len == 128 )
{
// No-op.
}
}
}
}
else
{
// We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...)
// where each channel consists of an 8-bit value for each pixel in the image.
// Read the data by channel.
uchar * ptr;
uint count = 0;
for(uint channel = 0; channel < channel_num; channel++)
{
ptr = r_image.bits() + components[channel];
// Read the data.
count = pixel_count;
while( count != 0 )
{
s >> cbyte;
if ((header.color_mode == CM_CMYK) && (components[channel] < 4))
cbyte = 255 - cbyte;
if ((header.color_mode == CM_GRAYSCALE) && (components[channel] != 3))
{
ptr -= components[channel];
ptr[0] = cbyte;
ptr[1] = cbyte;
ptr[2] = cbyte;
ptr += components[channel];
}
else if ((header.color_mode == CM_DUOTONE) && (components[channel] != 3))
{
ptr -= components[channel];
putDuotone(ptr, cbyte);
ptr += components[channel];
}
else if ((header.color_mode == CM_INDEXED) && (components[channel] != 3))
{
ptr -= components[channel];
int ccol = colorTable[cbyte];
ptr[0] = qRed(ccol);
ptr[1] = qGreen(ccol);
ptr[2] = qBlue(ccol);
ptr += components[channel];
}
else
*ptr = cbyte;
ptr += r_image.channels();
count--;
}
}
}
if (header.color_mode == CM_LABCOLOR)
{
ScColorProfile hsRGB = ScColorMgmtEngine::createProfile_sRGB();
ScColorProfile hLab = ScColorMgmtEngine::createProfile_Lab();
ScColorTransform xform = ScColorMgmtEngine::createTransform(hLab, Format_LabA_8, hsRGB, Format_RGBA_8, Intent_Perceptual, 0);
for (int i = 0; i < r_image.height(); i++)
{
uchar* ptr = r_image.scanLine(i);
xform.apply(ptr, ptr, r_image.width());
}
}
return true;
}
QString ScImgDataLoader_PSD::getLayerString(QDataStream & s)
{
uchar len, tmp;
uint adj;
QString ret = "";
s >> len;
if (len == 0)
{
s >> tmp;
s >> tmp;
s >> tmp;
return ret;
}
for( int i = 0; i < len; i++ )
{
s >> tmp;
ret += QChar(tmp);
}
adj = 0;
if (((ret.length()+1) % 4) != 0)
adj = 4 - ((ret.length()+1) % 4);
s.device()->seek( s.device()->pos() + adj );
return ret;
}
bool ScImgDataLoader_PSD::IsValid( const PSDHeader & header )
{
if( header.signature != 0x38425053 )
return false;
return true;
}
// Check that the header is supported.
bool ScImgDataLoader_PSD::IsSupported( const PSDHeader & header )
{
if ( header.version != 1 )
return false;
if ( header.channel_count > 16 )
return false;
if ( header.depth != 8 )
return false;
if ((header.color_mode == CM_RGB) || (header.color_mode == CM_CMYK) || (header.color_mode == CM_LABCOLOR)
|| (header.color_mode == CM_GRAYSCALE) || (header.color_mode == CM_INDEXED) || (header.color_mode == CM_DUOTONE))
return true;
return false;
}
void ScImgDataLoader_PSD::putDuotone(uchar *ptr, uchar cbyte)
{
CMYKColor cmyk;
int c, c1, c2, c3, m, m1, m2, m3, y, y1, y2, y3, k, k1, k2, k3;
uchar cb = 255 - cbyte;
ScColor col;
if (colorTableSc.count() == 1)
{
colorTableSc[0].getRawRGBColor(&c, &m, &y);
ptr[0] = qMin((c * curveTable1[(int)cbyte]) >> 8, 255);
ptr[1] = qMin((m * curveTable1[(int)cbyte]) >> 8, 255);
ptr[2] = qMin((y * curveTable1[(int)cbyte]) >> 8, 255);
}
else if (colorTableSc.count() == 2)
{
ScColorEngine::getCMYKValues(colorTableSc[0], NULL, cmyk);
cmyk.getValues(c, m, y, k);
c = qMin((c * curveTable1[(int)cb]) >> 8, 255);
m = qMin((m * curveTable1[(int)cb]) >> 8, 255);
y = qMin((y * curveTable1[(int)cb]) >> 8, 255);
k = qMin((k * curveTable1[(int)cb]) >> 8, 255);
ScColorEngine::getCMYKValues(colorTableSc[1], NULL, cmyk);
cmyk.getValues(c1, m1, y1, k1);
c1 = qMin((c1 * curveTable2[(int)cb]) >> 8, 255);
m1 = qMin((m1 * curveTable2[(int)cb]) >> 8, 255);
y1 = qMin((y1 * curveTable2[(int)cb]) >> 8, 255);
k1 = qMin((k1 * curveTable2[(int)cb]) >> 8, 255);
col = ScColor(qMin(c+c1, 255), qMin(m+m1, 255), qMin(y+y1, 255), qMin(k+k1, 255));
col.getRawRGBColor(&c, &m, &y);
ptr[0] = c;
ptr[1] = m;
ptr[2] = y;
}
else if (colorTableSc.count() == 3)
{
ScColorEngine::getCMYKValues(colorTableSc[0], NULL, cmyk);
cmyk.getValues(c, m, y, k);
c = qMin((c * curveTable1[(int)cb]) >> 8, 255);
m = qMin((m * curveTable1[(int)cb]) >> 8, 255);
y = qMin((y * curveTable1[(int)cb]) >> 8, 255);
k = qMin((k * curveTable1[(int)cb]) >> 8, 255);
ScColorEngine::getCMYKValues(colorTableSc[1], NULL, cmyk);
cmyk.getValues(c1, m1, y1, k1);
c1 = qMin((c1 * curveTable2[(int)cb]) >> 8, 255);
m1 = qMin((m1 * curveTable2[(int)cb]) >> 8, 255);
y1 = qMin((y1 * curveTable2[(int)cb]) >> 8, 255);
k1 = qMin((k1 * curveTable2[(int)cb]) >> 8, 255);
ScColorEngine::getCMYKValues(colorTableSc[2], NULL, cmyk);
cmyk.getValues(c2, m2, y2, k2);
c2 = qMin((c2 * curveTable3[(int)cb]) >> 8, 255);
m2 = qMin((m2 * curveTable3[(int)cb]) >> 8, 255);
y2 = qMin((y2 * curveTable3[(int)cb]) >> 8, 255);
k2 = qMin((k2 * curveTable3[(int)cb]) >> 8, 255);
col = ScColor(qMin(c+c1+c2, 255), qMin(m+m1+m2, 255), qMin(y+y1+y2, 255), qMin(k+k1+k2, 255));
col.getRawRGBColor(&c, &m, &y);
ptr[0] = c;
ptr[1] = m;
ptr[2] = y;
}
else if (colorTableSc.count() == 4)
{
ScColorEngine::getCMYKValues(colorTableSc[0], NULL, cmyk);
cmyk.getValues(c, m, y, k);
c = qMin((c * curveTable1[(int)cb]) >> 8, 255);
m = qMin((m * curveTable1[(int)cb]) >> 8, 255);
y = qMin((y * curveTable1[(int)cb]) >> 8, 255);
k = qMin((k * curveTable1[(int)cb]) >> 8, 255);
ScColorEngine::getCMYKValues(colorTableSc[1], NULL, cmyk);
cmyk.getValues(c1, m1, y1, k1);
c1 = qMin((c1 * curveTable2[(int)cb]) >> 8, 255);
m1 = qMin((m1 * curveTable2[(int)cb]) >> 8, 255);
y1 = qMin((y1 * curveTable2[(int)cb]) >> 8, 255);
k1 = qMin((k1 * curveTable2[(int)cb]) >> 8, 255);
ScColorEngine::getCMYKValues(colorTableSc[2], NULL, cmyk);
cmyk.getValues(c2, m2, y2, k2);
c2 = qMin((c2 * curveTable3[(int)cb]) >> 8, 255);
m2 = qMin((m2 * curveTable3[(int)cb]) >> 8, 255);
y2 = qMin((y2 * curveTable3[(int)cb]) >> 8, 255);
k2 = qMin((k2 * curveTable3[(int)cb]) >> 8, 255);
ScColorEngine::getCMYKValues(colorTableSc[3], NULL, cmyk);
cmyk.getValues(c3, m3, y3, k3);
c3 = qMin((c3 * curveTable4[(int)cb]) >> 8, 255);
m3 = qMin((m3 * curveTable4[(int)cb]) >> 8, 255);
y3 = qMin((y3 * curveTable4[(int)cb]) >> 8, 255);
k3 = qMin((k3 * curveTable4[(int)cb]) >> 8, 255);
col = ScColor(qMin(c+c1+c2+c3, 255), qMin(m+m1+m2+m3, 255), qMin(y+y1+y2+y3, 255), qMin(k+k1+k2+k3, 255));
col.getRawRGBColor(&c, &m, &y);
ptr[0] = c;
ptr[1] = m;
ptr[2] = y;
}
}