Scribus Developer Documentation - API
logo-pen

Scribus Developer Documentation - API

scimgdataloader_psd.cpp

Go to the documentation of this file.
00001 /*
00002 For general Scribus (>=1.3.2) copyright and licensing information please refer
00003 to the COPYING file provided with the program. Following this notice may exist
00004 a copyright and/or license notice that predates the release of Scribus 1.3.2
00005 for which a new license (GPL+exception) is in place.
00006 */
00007 #include "scconfig.h"
00008 #include "scimgdataloader_psd.h"
00009 #include "util_color.h"
00010 #include "sccolorengine.h"
00011 
00012 #include <QFile>
00013 #include <QFileInfo>
00014 #include <QList>
00015 
00016 #include CMS_INC
00017 
00018 static QDataStream & operator>> ( QDataStream & s, PSDHeader & header )
00019 {
00020     s >> header.signature;
00021     s >> header.version;
00022     for( int i = 0; i < 6; i++ )
00023     {
00024         s >> header.reserved[i];
00025     }
00026     s >> header.channel_count;
00027     s >> header.height;
00028     s >> header.width;
00029     s >> header.depth;
00030     s >> header.color_mode;
00031     return s;
00032 }
00033 
00034 ScImgDataLoader_PSD::ScImgDataLoader_PSD(void)
00035 {
00036     initSupportedFormatList();
00037 }
00038 
00039 void ScImgDataLoader_PSD::initSupportedFormatList(void)
00040 {
00041     m_supportedFormats.clear();
00042     m_supportedFormats.append( "psd" );
00043 }
00044 
00045 void ScImgDataLoader_PSD::loadEmbeddedProfile(const QString& fn)
00046 {
00047     m_embeddedProfile.resize(0);
00048     m_profileComponents = 0;
00049     cmsHPROFILE prof = 0;
00050     QFileInfo fi = QFileInfo(fn);
00051     if (!fi.exists())
00052         return;
00053     QString ext = fi.suffix().toLower();
00054     if (ext == "psd")
00055     {
00056         QFile f(fn);
00057         if (f.open(QIODevice::ReadOnly))
00058         {
00059             m_imageInfoRecord.xres = 72;
00060             m_imageInfoRecord.yres = 72;
00061             QDataStream s( &f );
00062             s.setByteOrder( QDataStream::BigEndian );
00063             PSDHeader header;
00064             s >> header;
00065             // Check image file format.
00066             if( s.atEnd() || !IsValid( header ) )
00067                 return;
00068             // Check if it's a supported format.
00069             if( !IsSupported( header ) )
00070                 return;
00071             if( !LoadPSDResources(s, header, s.device()->pos()) )
00072                 return;
00073             if (m_embeddedProfile.size() > 0)
00074             {
00075                 prof = cmsOpenProfileFromMem(m_embeddedProfile.data(), m_embeddedProfile.size());
00076                 if (prof)
00077                 {
00078                     if (static_cast<int>(cmsGetColorSpace(prof)) == icSigRgbData)
00079                         m_profileComponents = 3;
00080                     if (static_cast<int>(cmsGetColorSpace(prof)) == icSigCmykData)
00081                         m_profileComponents = 4;
00082                 }
00083                 cmsCloseProfile(prof);
00084             }
00085             f.close();
00086         }
00087         else
00088             return;
00089     }
00090 }
00091 
00092 bool ScImgDataLoader_PSD::preloadAlphaChannel(const QString& fn, int res, bool& hasAlpha)
00093 {
00094     bool valid = m_imageInfoRecord.isRequest;
00095     QMap<int, ImageLoadRequest> req = m_imageInfoRecord.RequestProps;
00096     initialize();
00097     hasAlpha = false;
00098     m_imageInfoRecord.RequestProps = req;
00099     m_imageInfoRecord.isRequest = valid;
00100     QFileInfo fi = QFileInfo(fn);
00101     if (!fi.exists())
00102         return false;
00103 
00104     QFile f(fn);
00105     if (f.open(QIODevice::ReadOnly))
00106     {
00107         QDataStream s( &f );
00108         s.setByteOrder( QDataStream::BigEndian );
00109         PSDHeader header;
00110         s >> header;
00111         // Check image file format.
00112         if( s.atEnd() || !IsValid( header ) )
00113             return false;
00114         // Check if it's a supported format.
00115         if( !IsSupported( header ) )
00116             return false;
00117         if( !LoadPSD(s, header) )
00118             r_image.resize(0);
00119         f.close();
00120         m_imageInfoRecord.valid = true;
00121         if (header.color_mode == CM_CMYK)
00122         {
00123             if ( maxChannels == 4)
00124                 m_imageInfoRecord.valid = hasAlpha = false;
00125         }
00126         else
00127         {
00128             if ( maxChannels == 3)
00129                 m_imageInfoRecord.valid = hasAlpha = false;
00130         }
00131         return true;
00132     }
00133     return false;
00134 }
00135 
00136 bool ScImgDataLoader_PSD::loadPicture(const QString& fn, int res, bool thumbnail)
00137 {
00138     bool isCMYK = false;
00139     float xres = 72.0, yres = 72.0;
00140     if (!QFile::exists(fn))
00141         return false;
00142     bool valid = m_imageInfoRecord.isRequest;
00143     QMap<int, ImageLoadRequest> req = m_imageInfoRecord.RequestProps;
00144     initialize();
00145     m_imageInfoRecord.RequestProps = req;
00146     m_imageInfoRecord.isRequest = valid;
00147     m_imageInfoRecord.type = ImageTypePSD;
00148     m_imageInfoRecord.exifDataValid = false;
00149     m_imageInfoRecord.layerInfo.clear();
00150     m_imageInfoRecord.PDSpathData.clear();
00151     QFile f(fn);
00152     if (f.open(QIODevice::ReadOnly))
00153     {
00154         m_imageInfoRecord.xres = 72;
00155         m_imageInfoRecord.yres = 72;
00156         QDataStream s( &f );
00157         s.setByteOrder( QDataStream::BigEndian );
00158         PSDHeader header;
00159         s >> header;
00160         // Check image file format.
00161         if( s.atEnd() || !IsValid( header ) )
00162             return false;
00163         // Check if it's a supported format.
00164         if( !IsSupported( header ) )
00165             return false;
00166         if (thumbnail)
00167             header.reserved[0] = 't';
00168         if( !LoadPSD(s, header) )
00169             return false;
00170         if (m_embeddedProfile.size() > 0)
00171         {
00172             cmsHPROFILE prof = cmsOpenProfileFromMem(m_embeddedProfile.data(), m_embeddedProfile.size());
00173             const char *Descriptor;
00174             Descriptor = cmsTakeProductDesc(prof);
00175             m_imageInfoRecord.profileName = QString(Descriptor);
00176             m_imageInfoRecord.isEmbedded = true;
00177         }
00178         if (header.color_mode == CM_CMYK)
00179             isCMYK = true;
00180         else
00181             isCMYK = false;
00182         if (header.color_mode == CM_CMYK)
00183             m_imageInfoRecord.colorspace = ColorSpaceCMYK;
00184         else if (header.color_mode == CM_RGB)
00185             m_imageInfoRecord.colorspace = ColorSpaceRGB;
00186         else if (header.color_mode == CM_GRAYSCALE)
00187             m_imageInfoRecord.colorspace = ColorSpaceGray;
00188         else if (header.color_mode == CM_DUOTONE)
00189             m_imageInfoRecord.colorspace = ColorSpaceDuotone;
00190         xres = m_imageInfoRecord.xres;
00191         yres = m_imageInfoRecord.yres;
00192         f.close();
00193         if (thumbnail)
00194         {
00195             if (!m_imageInfoRecord.exifInfo.thumbnail.isNull())
00196             {
00197                 if (isCMYK)
00198                     r_image.create(m_imageInfoRecord.exifInfo.thumbnail.width(), m_imageInfoRecord.exifInfo.thumbnail.height(), 5);
00199                 else
00200                     r_image.create(m_imageInfoRecord.exifInfo.thumbnail.width(), m_imageInfoRecord.exifInfo.thumbnail.height(), 4);
00201                 QRgb *s;
00202                 unsigned char cc, cm, cy, ck;
00203                 uchar *d;
00204                 for( int yit=0; yit < m_imageInfoRecord.exifInfo.thumbnail.height(); ++yit )
00205                 {
00206                     s = (QRgb*)(m_imageInfoRecord.exifInfo.thumbnail.scanLine( yit ));
00207                     d = r_image.scanLine( yit );
00208                     for(int xit=0; xit < m_imageInfoRecord.exifInfo.thumbnail.width(); ++xit )
00209                     {
00210                         if (isCMYK)
00211                         {
00212                             cc = 255 - qRed(*s);
00213                             cm = 255 - qGreen(*s);
00214                             cy = 255 - qBlue(*s);
00215                             ck = qMin(qMin(cc, cm), cy);
00216                             d[0] = cc-ck;
00217                             d[1] = cm-ck;
00218                             d[2] = cy-ck;
00219                             d[3] = ck;
00220                             d[4] = 255;
00221                         }
00222                         else
00223                         {
00224                             d[0] = qRed(*s);
00225                             d[1] = qGreen(*s);
00226                             d[2] = qBlue(*s);
00227                             d[3] = 255;
00228                         }
00229                         s++;
00230                         d += r_image.channels();
00231                     }
00232                 }
00233                 m_imageInfoRecord.exifInfo.width = header.width;
00234                 m_imageInfoRecord.exifInfo.height = header.height;
00235                 return true;
00236             }
00237         }
00238         m_imageInfoRecord.exifInfo.width = header.width;
00239         m_imageInfoRecord.exifInfo.height = header.height;
00240         m_imageInfoRecord.BBoxX = 0;
00241         m_imageInfoRecord.BBoxH = r_image.height();
00242         return true;
00243     }
00244     return false;
00245 }
00246 
00247 bool ScImgDataLoader_PSD::LoadPSD( QDataStream & s, const PSDHeader & header)
00248 {
00249     // Create dst image.
00250     m_imageInfoRecord.valid = false;
00251     if (header.color_mode == CM_CMYK)
00252     {
00253         if (!r_image.create(header.width, header.height, 5))
00254             return false;
00255     }
00256     else
00257     {
00258         if (!r_image.create(header.width, header.height, 4))
00259             return false;
00260     }
00261     r_image.fill(0);
00262     maxChannels = header.channel_count;
00263     uint tmp;
00264     uint cresStart;
00265     uint cdataStart;
00266     uint ressourceDataLen;
00267     uint startRessource;
00268 
00269     cresStart = s.device()->pos();
00270     // Skip mode data. FIX: this is incorrect, it's the Colormap Data for indexed Images
00271     s >> tmp;
00272     cdataStart = s.device()->pos();
00273 
00274     LoadPSDResources(s, header, cresStart); 
00275     
00276     s.device()->seek( cdataStart + tmp );
00277     s >> ressourceDataLen;
00278     startRessource = s.device()->pos();
00279 
00280     if  ((!m_imageInfoRecord.exifInfo.thumbnail.isNull()) && (header.reserved[0] == 't'))
00281         return true;
00282     bool ret = LoadPSDImgData(s, header, startRessource + ressourceDataLen);
00283     return ret;
00284 }
00285 
00286 bool ScImgDataLoader_PSD::LoadPSDResources( QDataStream & s, const PSDHeader & header, uint dataOffset )
00287 {
00288     // Create dst image.
00289     m_imageInfoRecord.valid = false;
00290 
00291     uint tmp;
00292     uint cdataStart;
00293     uint ressourceDataLen;
00294     uint startRessource;
00295 
00296     s.device()->seek( dataOffset );
00297 
00298     srand(314159265);
00299     for (int i = 0; i < 4096; i++)
00300         random_table[i] = rand();
00301     int tmpd;
00302     int swap;
00303     for (int i = 0; i < 4096; i++)
00304     {
00305         swap = i + rand() % (4096 - i);
00306         tmpd = random_table[i];
00307         random_table[i] = random_table[swap];
00308         random_table[swap] = tmpd;
00309     }
00310     // Skip mode data. FIX: this is incorrect, it's the Colormap Data for indexed Images
00311     s >> tmp;
00312     cdataStart = s.device()->pos();
00313     if (tmp != 0)
00314     {
00315         if ((header.color_mode == CM_DUOTONE))
00316         {
00317             short signature;
00318             short count;
00319             unsigned short c, m, y, k;
00320             uchar hc, sc, bc;
00321             ScColor col;
00322             s >> signature;
00323             s >> count;
00324             uint duodataStart = s.device()->pos();
00325             bool specialColour = false;
00326             for (int cda = 0; cda < count; cda++)
00327             {
00328                 s >> signature;
00329                 s >> c >> m >> y >> k;
00330                 switch (signature)
00331                 {
00332                     case 0: // RGB colour
00333                         col.setColorRGB(c >> 8, m >> 8, y >> 8);
00334                         colorTableSc.append(col);
00335                         break;
00336                     case 1: // HSB colour
00337                         hc = c >> 8;
00338                         sc = m >> 8;
00339                         bc = y >> 8;
00340                         HSVTORGB(hc, sc, bc);
00341                         col.setColorRGB(hc, sc, bc);
00342                         colorTableSc.append(col);
00343                         break;
00344                     case 2: // CMYK colour
00345                         col.setColor(c >> 8, m >> 8, y >> 8, k >> 8);
00346                         colorTableSc.append(col);
00347                         break;
00348                     case 3: // Pantone
00349                     case 4: // Focoltone
00350                     case 5: // Truematch
00351                     case 6: // Toyo 88 colorfinder 1050
00352                     case 7: // LAB colour space
00353                     case 10: // HKS colors
00354                         if (colorTableSc.count() == 0)
00355                             colorTableSc.append(ScColor(0, 0, 0, 255));
00356                         else
00357                             colorTableSc.append(ScColor(0, 0, 0, 0));
00358                         specialColour = true;
00359                         break;
00360                     case 8: // Grayscale
00361                         c = qRound((c / 10000.0) * 255);
00362                         colorTableSc.append(ScColor(0, 0, 0, c));
00363                         break;
00364                 }
00365             }
00366             if (specialColour) // we will only load the grayscale image data and do the colorizing with the Image Effects;
00367             {
00368                 s.device()->seek( duodataStart + 40 );
00369                 uint duoNameStart = s.device()->pos();
00370                 uint duoCurveStart = duoNameStart+256;
00371                 for (int cda = 0; cda < count; cda++)
00372                 {
00373                     QString colName;
00374                     s.device()->seek( duoNameStart + (64 * static_cast<uint>(cda)) );
00375                     colName = getPascalString(s);
00376                     s.device()->seek( duoCurveStart + (28 * static_cast<uint>(cda)) );
00377                     FPointArray tmcu;
00378                     tmcu.resize(0);
00379                     for (int cu = 0; cu < 13; cu++)
00380                     {
00381                         short val;
00382                         s >> val;
00383                         if (val != -1)
00384                             tmcu.addPoint(cu * 1.0 / 12.0, val / 1000.0);
00385                     }
00386                     PSDDuotone_Color colSpec;
00387                     colSpec.Name = colName;
00388                     colSpec.Color = colorTableSc[cda];
00389                     colSpec.Curve = tmcu;
00390                     m_imageInfoRecord.duotoneColors.append(colSpec);
00391                 }
00392                 // Initialize loading curve tables with default values
00393                 curveTable1.resize(256);
00394                 curveTable2.resize(256);
00395                 curveTable3.resize(256);
00396                 curveTable4.resize(256);
00397                 for (int x = 0 ; x < 256 ; x++)
00398                 {
00399                     curveTable1[x] = x;
00400                     curveTable2[x] = x;
00401                     curveTable3[x] = x;
00402                     curveTable4[x] = x;
00403                 }
00404             }
00405             else
00406             {
00407                 s.device()->seek( duodataStart + 40 );
00408                 uint duoNameStart = s.device()->pos();
00409                 uint duoCurveStart = duoNameStart+256;
00410                 for (int cda = 0; cda < count; cda++)
00411                 {
00412                     s.device()->seek( duoCurveStart + (28 * static_cast<uint>(cda)) );
00413                     FPointArray tmcu;
00414                     tmcu.resize(0);
00415                     for (int cu = 0; cu < 13; cu++)
00416                     {
00417                         short val;
00418                         s >> val;
00419                         if (val != -1)
00420                             tmcu.addPoint(cu * 1.0 / 12.0, val / 1000.0);
00421                     }
00422                     if (cda == 0)
00423                     {
00424                         curveTable1.resize(256);
00425                         for (int x = 0 ; x < 256 ; x++)
00426                         {
00427                             curveTable1[x] = qMin(255, qMax(0, qRound(getCurveYValue(tmcu, x / 255.0) * 255)));
00428                         }
00429                     }
00430                     else if (cda == 1)
00431                     {
00432                         curveTable2.resize(256);
00433                         for (int x = 0 ; x < 256 ; x++)
00434                         {
00435                             curveTable2[x] = qMin(255, qMax(0, qRound(getCurveYValue(tmcu, x / 255.0) * 255)));
00436                         }
00437                     }
00438                     else if (cda == 2)
00439                     {
00440                         curveTable3.resize(256);
00441                         for (int x = 0 ; x < 256 ; x++)
00442                         {
00443                             curveTable3[x] = qMin(255, qMax(0, qRound(getCurveYValue(tmcu, x / 255.0) * 255)));
00444                         }
00445                     }
00446                     else if (cda == 3)
00447                     {
00448                         curveTable4.resize(256);
00449                         for (int x = 0 ; x < 256 ; x++)
00450                         {
00451                             curveTable4[x] = qMin(255, qMax(0, qRound(getCurveYValue(tmcu, x / 255.0) * 255)));
00452                         }
00453                     }
00454                 }
00455             }
00456         }
00457         else
00458         {
00459             QList<uchar> colorTableR;
00460             QList<uchar> colorTableG;
00461             QList<uchar> colorTableB;
00462             colorTableR.clear();
00463             colorTableG.clear();
00464             colorTableB.clear();
00465             colorTable.clear();
00466             uchar r;
00467             for (uint cc = 0; cc < 256; cc++)
00468             {
00469                 s >> r;
00470                 colorTableR.append(r);
00471             }
00472             for (uint cc = 0; cc < 256; cc++)
00473             {
00474                 s >> r;
00475                 colorTableG.append(r);
00476             }
00477             for (uint cc = 0; cc < 256; cc++)
00478             {
00479                 s >> r;
00480                 colorTableB.append(r);
00481             }
00482             for (uint cc = 0; cc < 256; cc++)
00483             {
00484                 colorTable.append(qRgb(colorTableR[cc], colorTableG[cc], colorTableB[cc]));
00485             }
00486         }
00487     }
00488     s.device()->seek( cdataStart + tmp );
00489     s >> ressourceDataLen;
00490     startRessource = s.device()->pos();
00491     if (ressourceDataLen != 0)
00492         parseRessourceData(s, header, ressourceDataLen);
00493     return true;
00494 }
00495 
00496 bool ScImgDataLoader_PSD::LoadPSDImgData( QDataStream & s, const PSDHeader & header, uint dataOffset )
00497 {
00498     uint layerDataLen;
00499     uint startLayers;
00500     s.device()->seek( dataOffset );
00501     // Skip the reserved data. FIX: Also incorrect, this is the actual Layer Data for Images with Layers
00502     s >> layerDataLen;
00503     startLayers = s.device()->pos();
00504     if (layerDataLen != 0)
00505     {
00506         bool re = parseLayer(s, header);
00507         if (re)
00508         {
00509             m_imageInfoRecord.valid = true;
00510             return re;
00511         }
00512         else
00513         {
00514             // Try to decode simple psd file, no layers
00515             s.device()->seek(startLayers + layerDataLen);
00516             if(s.atEnd())
00517                 return false;
00518             return loadLayer( s, header);
00519         }
00520     }
00521     else
00522     {
00523         // Decoding simple psd file, no layers
00524         s.device()->seek( s.device()->pos() + layerDataLen );
00525         loadLayer( s, header);
00526     }
00527     return true;
00528 }
00529 
00530 bool ScImgDataLoader_PSD::parseLayer( QDataStream & s, const PSDHeader & header )
00531 {
00532     uint addRes, layerinfo, channelLen, signature, extradata, layermasksize, layerRange, dummy;
00533     int top, left, bottom, right;
00534     short numLayers, numChannels;
00535     short channelType;
00536     uchar blendKey[4];
00537     uchar opacity, clipping, flags, filler;
00538     QString layerName, blend;
00539     struct PSDLayer lay;
00540     s >> layerinfo;
00541     s >> numLayers;
00542     if (numLayers < 0)
00543         numLayers = -numLayers;
00544     if (numLayers != 0)
00545     {
00546         for (int layer = 0; layer < numLayers; layer++)
00547         {
00548             s >> top;
00549             lay.ypos = top;
00550             s >> left;
00551             lay.xpos = left;
00552             s >> bottom;
00553             lay.height = bottom - top;
00554             s >> right;
00555             lay.width = right - left;
00556             s >> numChannels;
00557             // Qt4 check these conversions
00558             maxChannels = qMax(maxChannels, (int)numChannels);
00559             if (numChannels > 6)    // we don't support images with more than 6 channels yet
00560             {
00561                 m_imageInfoRecord.layerInfo.clear();
00562                 return false;
00563             }
00564             lay.channelType.clear();
00565             lay.channelLen.clear();
00566             for (int channels = 0; channels < numChannels; channels++)
00567             {
00568                 s >> channelType;
00569                 s >> channelLen;
00570                 lay.channelType.append(channelType);
00571                 lay.channelLen.append(channelLen);
00572             }
00573             s >> signature;
00574             blend = "";
00575             for( int i = 0; i < 4; i++ )
00576             {
00577                 s >> blendKey[i];
00578                 blend += QChar(blendKey[i]);
00579             }
00580             lay.blend = blend;
00581             s >> opacity;
00582             lay.opacity = opacity;
00583             s >> clipping;
00584             lay.clipping = clipping;
00585             s >> flags;
00586             if (flags & 8)
00587             {
00588                 if (flags & 16) // Unknown combination of layer flags, probably an adjustment or effects layer
00589                 {
00590                     m_imageInfoRecord.layerInfo.clear();
00591                     return false;
00592                 }
00593             }
00594             lay.flags = flags;
00595             s >> filler;
00596             s >> extradata;
00597             s >> layermasksize;
00598             lay.maskYpos = 0;
00599             lay.maskXpos = 0;
00600             lay.maskHeight = 0;
00601             lay.maskWidth = 0;
00602             if (layermasksize != 0)
00603             {
00604                 s >> lay.maskYpos;
00605                 s >> lay.maskXpos;
00606                 s >> dummy;
00607                 lay.maskHeight = dummy - lay.maskYpos;
00608                 s >> dummy;
00609                 lay.maskWidth = dummy - lay.maskXpos;
00610                 s >> dummy;
00611             }
00612             s >> layerRange;
00613             s.device()->seek( s.device()->pos() + layerRange );
00614             lay.layerName = getLayerString(s);
00615             m_imageInfoRecord.layerInfo.append(lay);
00616             s >> signature;
00617             if( signature == 0x3842494D )
00618             {
00619                 while (signature == 0x3842494D )
00620                 {
00621                     s >> signature;
00622                     s >> addRes;
00623                     s.device()->seek( s.device()->pos() + addRes );
00624                     s >> signature;
00625                 }
00626                 s.device()->seek( s.device()->pos() - 4 );
00627             }
00628             else
00629             {
00630                 s.device()->seek( s.device()->pos() - 2 );
00631                 s >> signature;
00632                 if( signature == 0x3842494D )
00633                 {
00634                     while (signature == 0x3842494D )
00635                     {
00636                         s >> signature;
00637                         s >> addRes;
00638                         s.device()->seek( s.device()->pos() + addRes );
00639                         s >> signature;
00640                     }
00641                     s.device()->seek( s.device()->pos() - 4 );
00642                 }
00643                 else
00644                     s.device()->seek( s.device()->pos() - 6 );
00645             }
00646         }
00647         bool firstLayer = true;
00648         for (int layer = 0; layer < numLayers; layer++)
00649         {
00650             loadLayerChannels( s, header, m_imageInfoRecord.layerInfo, layer, &firstLayer );
00651         }
00652     }
00653     else
00654     {
00655         s >> numLayers;
00656         loadLayer( s, header);
00657     }
00658     return true;
00659 }
00660 
00661 bool ScImgDataLoader_PSD::loadChannel( QDataStream & s, const PSDHeader & header, QList<PSDLayer> &layerInfo, uint layer, int channel, int component, RawImage &tmpImg)
00662 {
00663     uint base = s.device()->pos();
00664     uchar cbyte;
00665     ushort compression;
00666     s >> compression;
00667     if( compression > 1 )
00668         return false;
00669     if (compression == 0)
00670     {
00671         int count = layerInfo[layer].channelLen[channel]-2;
00672         uchar *ptr;
00673         for (int i = 0; i < tmpImg.height(); i++)
00674         {
00675             ptr =  tmpImg.scanLine(i);
00676             for (int j = 0; j < tmpImg.width(); j++)
00677             {
00678                 s >> cbyte;
00679                 count--;
00680                 if ((header.color_mode == CM_CMYK) && (component < 4))
00681                     cbyte = 255 - cbyte;
00682                 if ((header.color_mode == CM_GRAYSCALE) && (component != 3))
00683                 {
00684                     ptr[0] = cbyte;
00685                     ptr[1] = cbyte;
00686                     ptr[2] = cbyte;
00687                 }
00688                 else if ((header.color_mode == CM_DUOTONE) && (component != 3))
00689                 {
00690                     ptr -= component;
00691                     putDuotone(ptr, cbyte);
00692                     ptr += component;
00693                 }
00694                 else if ((header.color_mode == CM_INDEXED) && (component != 3))
00695                 {
00696                     int ccol = colorTable[cbyte];
00697                     ptr[0] = qRed(ccol);
00698                     ptr[1] = qGreen(ccol);
00699                     ptr[2] = qBlue(ccol);
00700                 }
00701                 else
00702                     ptr[component] = cbyte;
00703                 if (count == 0)
00704                     break;
00705                 ptr += tmpImg.channels();
00706             }
00707             if (count == 0)
00708                 break;
00709         }
00710     }
00711     else
00712     {
00713         s.device()->seek( s.device()->pos() + tmpImg.height() * 2 );
00714         uint pixel_count = tmpImg.width();
00715         uchar *ptr;
00716         uchar *ptr2;
00717         uint count, len;
00718         uchar c;
00719         for (int hh = 0; hh < tmpImg.height(); hh++)
00720         {
00721             count = 0;
00722             ptr = tmpImg.scanLine(hh);
00723             ptr2 = ptr+tmpImg.width() * tmpImg.channels();
00724             ptr += component;
00725             while( count < pixel_count )
00726             {
00727                 if(s.atEnd())
00728                     return false;
00729                 s >> c;
00730                 len = c;
00731                 if( len < 128 )
00732                 {
00733                     // Copy next len+1 bytes literally.
00734                     len++;
00735                     count += len;
00736                     while( len != 0 )
00737                     {
00738                         s >> cbyte;
00739                         if (ptr < ptr2)
00740                         {
00741                             if ((header.color_mode == CM_CMYK) && (component < 4))
00742                                 cbyte = 255 - cbyte;
00743                             if ((header.color_mode == CM_GRAYSCALE) && (component != 3))
00744                             {
00745                                 ptr -= component;
00746                                 ptr[0] = cbyte;
00747                                 ptr[1] = cbyte;
00748                                 ptr[2] = cbyte;
00749                                 ptr += component;
00750                             }
00751                             else if ((header.color_mode == CM_DUOTONE) && (component != 3))
00752                             {
00753                                 ptr -= component;
00754                                 putDuotone(ptr, cbyte);
00755                                 ptr += component;
00756                             }
00757                             else if ((header.color_mode == CM_INDEXED) && (component != 3))
00758                             {
00759                                 ptr -= component;
00760                                 int ccol = colorTable[cbyte];
00761                                 ptr[0] = qRed(ccol);
00762                                 ptr[1] = qGreen(ccol);
00763                                 ptr[2] = qBlue(ccol);
00764                                 ptr += component;
00765                             }
00766                             else
00767                             {
00768                                 *ptr = cbyte;
00769                             }
00770                         }
00771                         ptr += tmpImg.channels();
00772                         len--;
00773                     }
00774                 }
00775                 else if( len > 128 )
00776                 {
00777                     // Next -len+1 bytes in the dest are replicated from next source byte.
00778                     // (Interpret len as a negative 8-bit int.)
00779                     len ^= 0xFF;
00780                     len += 2;
00781                     count += len;
00782                     uchar val;
00783                     s >> val;
00784                     if ((header.color_mode == CM_CMYK) && (component < 4))
00785                         val = 255 - val;
00786                     while( len != 0 )
00787                     {
00788                         if (ptr < ptr2)
00789                         {
00790                             if ((header.color_mode == CM_GRAYSCALE) && (component != 3))
00791                             {
00792                                 ptr -= component;
00793                                 ptr[0] = val;
00794                                 ptr[1] = val;
00795                                 ptr[2] = val;
00796                                 ptr += component;
00797                             }
00798                             else if ((header.color_mode == CM_DUOTONE) && (component != 3))
00799                             {
00800                                 ptr -= component;
00801                                 putDuotone(ptr, val);
00802                                 ptr += component;
00803                             }
00804                             else if ((header.color_mode == CM_INDEXED) && (component != 3))
00805                             {
00806                                 ptr -= component;
00807                                 int ccol = colorTable[val];
00808                                 ptr[0] = qRed(ccol);
00809                                 ptr[1] = qGreen(ccol);
00810                                 ptr[2] = qBlue(ccol);
00811                                 ptr += component;
00812                             }
00813                             else
00814                                 *ptr = val;
00815                         }
00816                         ptr += tmpImg.channels();
00817                         len--;
00818                     }
00819                 }
00820                 else if( len == 128 )
00821                 {
00822                     // No-op.
00823                 }
00824             }
00825         }
00826     }
00827     s.device()->seek( base+layerInfo[layer].channelLen[channel] );
00828     return true;
00829 }
00830 
00831 bool ScImgDataLoader_PSD::loadLayerChannels( QDataStream & s, const PSDHeader & header, QList<PSDLayer> &layerInfo, uint layer, bool* firstLayer)
00832 {
00833     // Find out if the data is compressed.
00834     // Known values:
00835     //   0: no compression
00836     //   1: RLE compressed
00837     uint base = s.device()->pos();
00838     uint base2 = base;
00839     uint channel_num = layerInfo[layer].channelLen.count();
00840     bool hasMask = false;
00841     bool hasAlpha = false;
00842     RawImage r2_image;
00843     RawImage mask;
00844     bool createOk = false;
00845     if (header.color_mode == CM_CMYK)
00846     {
00847         createOk = r2_image.create(layerInfo[layer].width, layerInfo[layer].height, qMax(channel_num, (uint)5));
00848         r2_image.fill(0);
00849     }
00850     else
00851     {
00852         createOk = r2_image.create(layerInfo[layer].width, layerInfo[layer].height, qMax(channel_num, (uint)4));
00853         r2_image.fill(0);
00854     }
00855     if( !createOk )
00856     {
00857         for(uint channel = 0; channel < channel_num; channel++)
00858         {
00859             base2 += layerInfo[layer].channelLen[channel];
00860         }
00861         s.device()->seek( base2 );
00862         return false;
00863     }
00864     channel_num = qMin(channel_num, (uint)39);
00865     uint components[40];
00866     for(uint channel = 0; channel < channel_num; channel++)
00867     {
00868         switch(layerInfo[layer].channelType[channel])
00869         {
00870         case 0:
00871             components[channel] = 0;
00872             break;
00873         case 1:
00874             components[channel] = 1;
00875             break;
00876         case 2:
00877             components[channel] = 2;
00878             break;
00879         case 3:
00880             components[channel] = 3;
00881             break;
00882         case -1:
00883             if (header.color_mode == CM_CMYK)
00884             {
00885                 if (channel_num == 6)
00886                     components[channel] = channel_num-2;
00887                 else
00888                     components[channel] = channel_num-1;
00889             }
00890             else
00891             {
00892                 if (channel_num == 5)
00893                     components[channel] = channel_num-2;
00894                 else
00895                 {
00896                     if (header.color_mode == CM_GRAYSCALE)
00897                         components[channel] = 3;
00898                     else
00899                         components[channel] = channel_num-1;
00900                 }
00901             }
00902             hasAlpha = true;
00903             break;
00904         case -2:
00905             components[channel] = channel_num-1;
00906             break;
00907         }
00908     }
00909     if (!hasAlpha)
00910         r2_image.fill(255);
00911     for(uint channel = 0; channel < channel_num; channel++)
00912     {
00913         if (layerInfo[layer].channelType[channel] == -2)
00914         {
00915             if (!mask.create( layerInfo[layer].maskWidth, layerInfo[layer].maskHeight, 1 ))
00916                 break;
00917             mask.fill(0);
00918             if (!loadChannel(s, header, layerInfo, layer, channel, 0, mask))
00919                 break;
00920             hasMask = true;
00921         }
00922         if (!loadChannel(s, header, layerInfo, layer, channel, components[channel], r2_image))
00923             break;
00924     }
00925     for(uint channel = 0; channel < channel_num; channel++)
00926     {
00927         base2 += layerInfo[layer].channelLen[channel];
00928     }
00929     if (header.color_mode == CM_LABCOLOR)
00930     {
00931         cmsHPROFILE hsRGB = cmsCreate_sRGBProfile();
00932         cmsHPROFILE hLab  = cmsCreateLabProfile(NULL);
00933         DWORD inputProfFormat = (COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1));
00934         cmsHTRANSFORM xform = cmsCreateTransform(hLab, inputProfFormat, hsRGB, TYPE_RGBA_8, INTENT_PERCEPTUAL, 0);
00935         for (int i = 0; i < r2_image.height(); i++)
00936         {
00937             LPBYTE ptr = r2_image.scanLine(i);
00938             cmsDoTransform(xform, ptr, ptr, r2_image.width());
00939         }
00940         cmsDeleteTransform (xform);
00941         cmsCloseProfile(hsRGB);
00942         cmsCloseProfile(hLab);
00943     }
00944     s.device()->seek( base2 );
00945     QImage tmpImg2;
00946     if (header.color_mode == CM_CMYK)
00947         tmpImg2 = r2_image.convertToQImage(true);
00948     else
00949         tmpImg2 = r2_image.convertToQImage(false);
00950     QImage imt;
00951     double sx = tmpImg2.width() / 40.0;
00952     double sy = tmpImg2.height() / 40.0;
00953     imt = sy < sx ?  tmpImg2.scaled(qRound(tmpImg2.width() / sx), qRound(tmpImg2.height() / sx), Qt::IgnoreAspectRatio, Qt::SmoothTransformation) :
00954           tmpImg2.scaled(qRound(tmpImg2.width() / sy), qRound(tmpImg2.height() / sy), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
00955     layerInfo[layer].thumb = imt.copy();
00956     if (hasMask)
00957     {
00958         QImage imt2;
00959         QImage tmpImg;
00960         tmpImg = mask.convertToQImage(true);
00961         double sx = tmpImg.width() / 40.0;
00962         double sy = tmpImg.height() / 40.0;
00963         imt2 = sy < sx ?  tmpImg.scaled(qRound(tmpImg.width() / sx), qRound(tmpImg.height() / sx), Qt::IgnoreAspectRatio, Qt::SmoothTransformation) :
00964           tmpImg.scaled(qRound(tmpImg.width() / sy), qRound(tmpImg.height() / sy), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
00965         imt2.invertPixels();
00966         layerInfo[layer].thumb_mask = imt2.copy();
00967     }
00968     else
00969         layerInfo[layer].thumb_mask = QImage();
00970     if ((m_imageInfoRecord.isRequest) && (m_imageInfoRecord.RequestProps.contains(layer)))
00971         m_imageInfoRecord.RequestProps[layer].useMask = m_imageInfoRecord.RequestProps[layer].useMask;
00972     else
00973         m_imageInfoRecord.RequestProps[layer].useMask = true;
00974     bool visible = !(layerInfo[layer].flags & 2);
00975     if ((m_imageInfoRecord.isRequest) && (m_imageInfoRecord.RequestProps.contains(layer)))
00976         visible = m_imageInfoRecord.RequestProps[layer].visible;
00977     if (visible)
00978     {
00979         unsigned int startSrcY, startSrcX, startDstY, startDstX;
00980         if (layerInfo[layer].ypos < 0)
00981         {
00982             startSrcY = abs(layerInfo[layer].ypos);
00983             startDstY = 0;
00984         }
00985         else
00986         {
00987             startSrcY = 0;
00988             startDstY = layerInfo[layer].ypos;
00989         }
00990         if (layerInfo[layer].xpos < 0)
00991         {
00992             startSrcX = abs(layerInfo[layer].xpos);
00993             startDstX = 0;
00994         }
00995         else
00996         {
00997             startSrcX = 0;
00998             startDstX = layerInfo[layer].xpos;
00999         }
01000         unsigned int startSrcYm, startSrcXm, startDstYm, startDstXm;
01001         if (layerInfo[layer].maskYpos < 0)
01002         {
01003             startSrcYm = abs(layerInfo[layer].maskYpos);
01004             startDstYm = 0;
01005         }
01006         else
01007         {
01008             startSrcYm = 0;
01009             startDstYm = layerInfo[layer].maskYpos;
01010         }
01011         if (layerInfo[layer].maskXpos < 0)
01012         {
01013             startSrcXm = abs(layerInfo[layer].maskXpos);
01014             startDstXm = 0;
01015         }
01016         else
01017         {
01018             startSrcXm = 0;
01019             startDstXm = layerInfo[layer].maskXpos;
01020         }
01021         QString layBlend2 = layerInfo[layer].blend;
01022         if ((m_imageInfoRecord.isRequest) && (m_imageInfoRecord.RequestProps.contains(layer)))
01023             layBlend2 = m_imageInfoRecord.RequestProps[layer].blend;
01024         if (layBlend2 == "diss")
01025         {
01026             hasAlpha = true;
01027             int layOpa = layerInfo[layer].opacity;
01028             if ((m_imageInfoRecord.isRequest) && (m_imageInfoRecord.RequestProps.contains(layer)))
01029                 layOpa = m_imageInfoRecord.RequestProps[layer].opacity;
01030             for (int l = 0; l < r2_image.height(); l++)
01031             {
01032                 srand(random_table[ l  % 4096]);
01033                 for (int k = 0; k < r2_image.width(); k++)
01034                 {
01035                     int rand_val = rand() & 0xff;
01036                     if (rand_val > layOpa)
01037                         r2_image.setAlpha(k, l, 0);
01038                 }
01039             }
01040         }
01041         if (*firstLayer)
01042         {
01043             unsigned char *s;
01044             unsigned char *d;
01045             for( int yi=static_cast<int>(startSrcY); yi < qMin(r2_image.height(),  r_image.height()); ++yi )
01046             {
01047                 s = r2_image.scanLine( yi );
01048                 d = r_image.scanLine( qMin(static_cast<int>(startDstY),  r_image.height()-1) );
01049                 d += qMin(static_cast<int>(startDstX), r_image.width()-1) * r_image.channels();
01050                 s += qMin(static_cast<int>(startSrcX), r2_image.width()-1) * r2_image.channels();
01051                 for(int xi=static_cast<int>(startSrcX); xi < qMin(r2_image.width(),  r_image.width()); ++xi )
01052                 {
01053                     d[0] = s[0];
01054                     d[1] = s[1];
01055                     d[2] = s[2];
01056                     if (header.color_mode != CM_CMYK)
01057                     {
01058                         if (hasAlpha)
01059                             d[3] = s[3];
01060                         else
01061                             d[3] = 255;
01062                     }
01063                     else
01064                     {
01065                         d[3] = s[3];
01066                         if (hasAlpha)
01067                             d[4] = s[4];
01068                         else
01069                             d[4] = 255;
01070                     }
01071                     s += r2_image.channels();
01072                     d += r_image.channels();
01073                 }
01074                 startDstY++;
01075             }
01076         }
01077         else
01078         {
01079             unsigned char *s;
01080             unsigned char *d;
01081             unsigned char *sm = 0;
01082             unsigned char r, g, b, src_r, src_g, src_b, src_a, src_alpha, dst_alpha;
01083             unsigned char a = 0;
01084             uchar new_r, new_g, new_b;
01085             unsigned int maxDestX;
01086             for (int i = static_cast<int>(startSrcY); i < layerInfo[layer].height; i++)
01087             {
01088                 d = r_image.scanLine(qMin(static_cast<int>(startDstY),  r_image.height()-1));
01089                 s = r2_image.scanLine(qMin(i, r2_image.height()-1));
01090                 d += qMin(static_cast<int>(startDstX),  r_image.width()-1) * r_image.channels();
01091                 s += qMin(static_cast<int>(startSrcX), r2_image.width()-1) * r2_image.channels();
01092                 sm = 0;
01093                 if (hasMask)
01094                 {
01095                     sm = mask.scanLine(qMin(i, mask.height()-1));
01096                     sm += qMin(static_cast<int>(startSrcXm), mask.width()-1) * mask.channels();
01097                 }
01098                 startDstY++;
01099                 maxDestX = r_image.width() - startDstX + startSrcX - 1;
01100                 for (unsigned int j = startSrcX; j < qMin(maxDestX, static_cast<unsigned int>(layerInfo[layer].width)); j++)
01101                 {
01102                     src_r = s[0];
01103                     src_g = s[1];
01104                     src_b = s[2];
01105                     src_a = s[3];
01106                     if (hasAlpha)
01107                     {
01108                         if (hasMask)
01109                         {
01110                             if (m_imageInfoRecord.RequestProps[layer].useMask)
01111                                 src_alpha = sm[0];
01112                             else
01113                                 src_alpha = s[channel_num - 2];
01114                         }
01115                         else
01116                         {
01117                             if (header.color_mode == CM_GRAYSCALE)
01118                                 src_alpha = s[3];
01119                             else
01120                                 src_alpha = s[channel_num - 1];
01121                         }
01122                     }
01123                     else
01124                         src_alpha = 255;
01125                     if ((hasMask) && (m_imageInfoRecord.RequestProps[layer].useMask))
01126