krita

kis_abstract_colorspace.cc

00001 /*
00002  *  Copyright (c) 2002 Patrick Julien  <freak@codepimps.org>
00003  *  Copyright (c) 2004 Cyrille Berger <cberger@cberger.net>
00004  *
00005  *  This program is free software; you can redistribute it and/or modify
00006  *  it under the terms of the GNU General Public License as published by
00007  *  the Free Software Foundation; either version 2 of the License, or
00008  *  (at your option) any later version.
00009  *
00010  *  This program is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *  GNU General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU General Public License
00016  *  along with this program; if not, write to the Free Software
00017  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00018  */
00019 #include <qimage.h>
00020 
00021 #include <kdebug.h>
00022 #include <kconfig.h>
00023 
00024 #include "kis_abstract_colorspace.h"
00025 #include "kis_global.h"
00026 #include "kis_profile.h"
00027 #include "kis_id.h"
00028 #include "kis_integer_maths.h"
00029 #include "kis_color_conversions.h"
00030 #include "kis_colorspace_factory_registry.h"
00031 #include "kis_channelinfo.h"
00032 
00033 class KisColorAdjustmentImpl : public KisColorAdjustment
00034 {
00035     public:
00036         
00037     KisColorAdjustmentImpl() : KisColorAdjustment()
00038         {
00039             csProfile = 0;
00040             transform = 0;
00041             profiles[0] = 0;
00042             profiles[1] = 0;
00043             profiles[2] = 0;
00044         };
00045     
00046     ~KisColorAdjustmentImpl() {
00047 
00048         if (transform)
00049             cmsDeleteTransform(transform);
00050         if (profiles[0] && profiles[0] != csProfile)
00051             cmsCloseProfile(profiles[0]);
00052         if(profiles[1] && profiles[1] != csProfile)
00053             cmsCloseProfile(profiles[1]);
00054         if(profiles[2] && profiles[2] != csProfile)
00055             cmsCloseProfile(profiles[2]);
00056     }
00057 
00058     cmsHPROFILE csProfile;
00059     cmsHPROFILE profiles[3];
00060     cmsHTRANSFORM transform;
00061 };
00062 
00063 KisAbstractColorSpace::KisAbstractColorSpace(const KisID& id,
00064                                              DWORD cmType,
00065                                              icColorSpaceSignature colorSpaceSignature,
00066                                              KisColorSpaceFactoryRegistry * parent,
00067                                              KisProfile *p)
00068     : m_parent( parent )
00069     , m_profile( p )
00070     , m_id( id )
00071     , m_cmType( cmType )
00072     , m_colorSpaceSignature( colorSpaceSignature )
00073 {
00074     m_alphaPos = -1;
00075     m_alphaSize = -1;
00076     m_qcolordata = 0;
00077     m_lastUsedDstColorSpace = 0;
00078     m_lastUsedTransform = 0;
00079     m_lastRGBProfile = 0;
00080     m_lastToRGB = 0;
00081     m_lastFromRGB = 0;
00082     m_defaultFromRGB = 0;
00083     m_defaultToRGB = 0;
00084     m_defaultFromLab = 0;
00085     m_defaultToLab = 0;
00086 }
00087 
00088 void KisAbstractColorSpace::init()
00089 {
00090     // Default pixel buffer for QColor conversion
00091     m_qcolordata = new Q_UINT8[3];
00092     Q_CHECK_PTR(m_qcolordata);
00093 
00094     if (m_profile == 0) return;
00095 
00096     // For conversions from default rgb
00097     m_lastFromRGB = cmsCreate_sRGBProfile();
00098 
00099     m_defaultFromRGB = cmsCreateTransform(m_lastFromRGB, TYPE_BGR_8,
00100                                           m_profile->profile(), m_cmType,
00101                                           INTENT_PERCEPTUAL, 0);
00102 
00103     m_defaultToRGB =  cmsCreateTransform(m_profile->profile(), m_cmType,
00104                                          m_lastFromRGB, TYPE_BGR_8,
00105                                          INTENT_PERCEPTUAL, 0);
00106 
00107     cmsHPROFILE hLab  = cmsCreateLabProfile(NULL);
00108 
00109     m_defaultFromLab = cmsCreateTransform(hLab, TYPE_Lab_16, m_profile->profile(), m_cmType,
00110                                           INTENT_PERCEPTUAL, 0);
00111 
00112     m_defaultToLab = cmsCreateTransform(m_profile->profile(), m_cmType, hLab, TYPE_Lab_16,
00113                                         INTENT_PERCEPTUAL, 0);
00114 }
00115 
00116 KisAbstractColorSpace::~KisAbstractColorSpace()
00117 {
00118 }
00119 
00120 
00121 
00122 void KisAbstractColorSpace::fromQColor(const QColor& color, Q_UINT8 *dst, KisProfile * profile)
00123 {
00124     m_qcolordata[2] = color.red();
00125     m_qcolordata[1] = color.green();
00126     m_qcolordata[0] = color.blue();
00127 
00128 
00129     if (profile == 0) {
00130         // Default sRGB
00131         if (!m_defaultFromRGB) return;
00132 
00133         cmsDoTransform(m_defaultFromRGB, m_qcolordata, dst, 1);
00134     }
00135     else {
00136         if (m_lastFromRGB == 0 || (m_lastFromRGB != 0 && m_lastRGBProfile != profile->profile())) {
00137             m_lastFromRGB = cmsCreateTransform(profile->profile(), TYPE_BGR_8,
00138                            m_profile->profile(), m_cmType,
00139                            INTENT_PERCEPTUAL, 0);
00140             m_lastRGBProfile = profile->profile();
00141 
00142         }
00143         cmsDoTransform(m_lastFromRGB, m_qcolordata, dst, 1);
00144     }
00145 
00146     setAlpha(dst, OPACITY_OPAQUE, 1);
00147 }
00148 
00149 void KisAbstractColorSpace::fromQColor(const QColor& color, Q_UINT8 opacity, Q_UINT8 *dst, KisProfile * profile)
00150 {
00151     fromQColor(color, dst, profile);
00152     setAlpha(dst, opacity, 1);
00153 }
00154 
00155 void KisAbstractColorSpace::toQColor(const Q_UINT8 *src, QColor *c, KisProfile * profile)
00156 {
00157     if (profile == 0) {
00158     // Default sRGB transform
00159         if (!m_defaultToRGB) return;
00160         cmsDoTransform(m_defaultToRGB, const_cast <Q_UINT8 *>(src), m_qcolordata, 1);
00161     }
00162     else {
00163         if (m_lastToRGB == 0 || (m_lastToRGB != 0 && m_lastRGBProfile != profile->profile())) {
00164             m_lastToRGB = cmsCreateTransform(m_profile->profile(), m_cmType,
00165                                                  profile->profile(), TYPE_BGR_8,
00166                                                  INTENT_PERCEPTUAL, 0);
00167             m_lastRGBProfile = profile->profile();
00168         }
00169         cmsDoTransform(m_lastToRGB, const_cast <Q_UINT8 *>(src), m_qcolordata, 1);
00170     }
00171     c->setRgb(m_qcolordata[2], m_qcolordata[1], m_qcolordata[0]);
00172 }
00173 
00174 void KisAbstractColorSpace::toQColor(const Q_UINT8 *src, QColor *c, Q_UINT8 *opacity, KisProfile * profile)
00175 {
00176     toQColor(src, c, profile);
00177     *opacity = getAlpha(src);
00178 }
00179 
00180 void KisAbstractColorSpace::getSingleChannelPixel(Q_UINT8 *dstPixel, const Q_UINT8 *srcPixel, Q_UINT32 channelIndex)
00181 {
00182     if (channelIndex < m_channels.count()) {
00183 
00184         fromQColor(Qt::black, OPACITY_TRANSPARENT, dstPixel);
00185 
00186         const KisChannelInfo *channelInfo = m_channels[channelIndex];
00187         memcpy(dstPixel + channelInfo->pos(), srcPixel + channelInfo->pos(), channelInfo->size());
00188     }
00189 }
00190 
00191 bool KisAbstractColorSpace::convertPixelsTo(const Q_UINT8 * src,
00192                         Q_UINT8 * dst,
00193                         KisColorSpace * dstColorSpace,
00194                         Q_UINT32 numPixels,
00195                         Q_INT32 renderingIntent)
00196 {
00197     if (dstColorSpace->colorSpaceType() == colorSpaceType()
00198         && dstColorSpace->getProfile() == getProfile())
00199     {
00200         if (src!= dst)
00201             memcpy (dst, src, numPixels * pixelSize());
00202 
00203         return true;
00204     }
00205 
00206     cmsHTRANSFORM tf = 0;
00207 
00208     Q_INT32 srcPixelSize = pixelSize();
00209     Q_INT32 dstPixelSize = dstColorSpace->pixelSize();
00210 
00211     if (m_lastUsedTransform != 0 && m_lastUsedDstColorSpace != 0) {
00212         if (dstColorSpace->colorSpaceType() == m_lastUsedDstColorSpace->colorSpaceType() && 
00213             dstColorSpace->getProfile() == m_lastUsedDstColorSpace->getProfile()) {
00214             tf = m_lastUsedTransform;
00215         }
00216     }
00217 
00218     if (!tf && m_profile && dstColorSpace->getProfile()) {
00219 
00220         if (!m_transforms.contains(dstColorSpace)) {
00221             tf = createTransform(dstColorSpace,
00222                  m_profile,
00223                  dstColorSpace->getProfile(),
00224                  renderingIntent);
00225             if (tf) {
00226         // XXX: Should we clear the transform cache if it gets too big?
00227         m_transforms[dstColorSpace] = tf;
00228             }
00229         }
00230         else {
00231             tf = m_transforms[dstColorSpace];
00232         }
00233 
00234         if ( tf ) {
00235             m_lastUsedTransform = tf;
00236             m_lastUsedDstColorSpace = dstColorSpace;
00237         }
00238     }
00239 
00240     if (tf) {
00241 
00242         cmsDoTransform(tf, const_cast<Q_UINT8 *>(src), dst, numPixels);
00243 
00244         // Lcms does nothing to the destination alpha channel so we must convert that manually.
00245         while (numPixels > 0) {
00246             Q_UINT8 alpha = getAlpha(src);
00247             dstColorSpace->setAlpha(dst, alpha, 1);
00248 
00249             src += srcPixelSize;
00250             dst += dstPixelSize;
00251             numPixels--;
00252         }
00253 
00254         return true;
00255     }
00256 
00257     // Last resort fallback. This will be removed when this class is renamed KisLCMSColorSpace after 1.5.
00258     while (numPixels > 0) {
00259         QColor color;
00260         Q_UINT8 opacity;
00261 
00262         toQColor(src, &color, &opacity);
00263         dstColorSpace->fromQColor(color, opacity, dst);
00264 
00265         src += srcPixelSize;
00266         dst += dstPixelSize;
00267         numPixels--;
00268     }
00269 
00270     return true;
00271 }
00272 
00273 
00274 KisColorAdjustment *KisAbstractColorSpace::createBrightnessContrastAdjustment(Q_UINT16 *transferValues)
00275 {
00276     if (!m_profile) return 0;
00277 
00278     LPGAMMATABLE transferFunctions[3];
00279     transferFunctions[0] = cmsBuildGamma(256, 1.0);
00280     transferFunctions[1] = cmsBuildGamma(256, 1.0);
00281     transferFunctions[2] = cmsBuildGamma(256, 1.0);
00282 
00283     for(int i =0; i < 256; i++)
00284         transferFunctions[0]->GammaTable[i] = transferValues[i];
00285 
00286     KisColorAdjustmentImpl *adj = new KisColorAdjustmentImpl;
00287     adj->profiles[1] = cmsCreateLinearizationDeviceLink(icSigLabData, transferFunctions);
00288     cmsSetDeviceClass(adj->profiles[1], icSigAbstractClass);
00289 
00290     adj->profiles[0] = m_profile->profile();
00291     adj->profiles[2] = m_profile->profile();
00292     adj->transform  = cmsCreateMultiprofileTransform(adj->profiles, 3, m_cmType, m_cmType, INTENT_PERCEPTUAL, 0);
00293     adj->csProfile = m_profile->profile();
00294     return adj;
00295 }
00296 
00297 typedef struct {
00298                 double Saturation;
00299 
00300 } BCHSWADJUSTS, *LPBCHSWADJUSTS;
00301 
00302 
00303 static int desaturateSampler(register WORD In[], register WORD Out[], register LPVOID /*Cargo*/)
00304 {
00305     cmsCIELab LabIn, LabOut;
00306     cmsCIELCh LChIn, LChOut;
00307     //LPBCHSWADJUSTS bchsw = (LPBCHSWADJUSTS) Cargo;
00308 
00309     cmsLabEncoded2Float(&LabIn, In);
00310 
00311     cmsLab2LCh(&LChIn, &LabIn);
00312 
00313     // Do some adjusts on LCh
00314     LChOut.L = LChIn.L;
00315     LChOut.C = 0;//LChIn.C + bchsw->Saturation;
00316     LChOut.h = LChIn.h;
00317 
00318     cmsLCh2Lab(&LabOut, &LChOut);
00319 
00320     // Back to encoded
00321     cmsFloat2LabEncoded(Out, &LabOut);
00322 
00323     return TRUE;
00324 }
00325 
00326 KisColorAdjustment *KisAbstractColorSpace::createDesaturateAdjustment()
00327 {
00328     if (!m_profile) return 0;
00329 
00330     KisColorAdjustmentImpl *adj = new KisColorAdjustmentImpl;
00331 
00332     adj->profiles[0] = m_profile->profile();
00333     adj->profiles[2] = m_profile->profile();
00334     adj->csProfile = m_profile->profile();
00335     
00336      LPLUT Lut;
00337      BCHSWADJUSTS bchsw;
00338 
00339      bchsw.Saturation = -25;
00340 
00341      adj->profiles[1] = _cmsCreateProfilePlaceholder();
00342      if (!adj->profiles[1]) // can't allocate
00343         return NULL;
00344 
00345      cmsSetDeviceClass(adj->profiles[1], icSigAbstractClass);
00346      cmsSetColorSpace(adj->profiles[1], icSigLabData);
00347      cmsSetPCS(adj->profiles[1], icSigLabData);
00348 
00349      cmsSetRenderingIntent(adj->profiles[1], INTENT_PERCEPTUAL);
00350 
00351      // Creates a LUT with 3D grid only
00352      Lut = cmsAllocLUT();
00353 
00354      cmsAlloc3DGrid(Lut, 32, 3, 3);
00355 
00356      if (!cmsSample3DGrid(Lut, desaturateSampler, static_cast<LPVOID>(&bchsw), 0)) {
00357          // Shouldn't reach here
00358          cmsFreeLUT(Lut);
00359          cmsCloseProfile(adj->profiles[1]);
00360          return NULL;
00361      }
00362 
00363     // Create tags
00364 
00365     cmsAddTag(adj->profiles[1], icSigDeviceMfgDescTag,      (LPVOID) "(krita internal)");
00366     cmsAddTag(adj->profiles[1], icSigProfileDescriptionTag, (LPVOID) "krita saturation abstract profile");
00367     cmsAddTag(adj->profiles[1], icSigDeviceModelDescTag,    (LPVOID) "saturation built-in");
00368 
00369     cmsAddTag(adj->profiles[1], icSigMediaWhitePointTag, (LPVOID) cmsD50_XYZ());
00370 
00371     cmsAddTag(adj->profiles[1], icSigAToB0Tag, (LPVOID) Lut);
00372 
00373     // LUT is already on virtual profile
00374     cmsFreeLUT(Lut);
00375 
00376     adj->transform  = cmsCreateMultiprofileTransform(adj->profiles, 3, m_cmType, m_cmType, INTENT_PERCEPTUAL, 0);
00377 
00378     return adj;
00379 }
00380 
00381 KisColorAdjustment *KisAbstractColorSpace::createPerChannelAdjustment(Q_UINT16 **transferValues)
00382 {
00383     if (!m_profile) return 0;
00384 
00385     LPGAMMATABLE *transferFunctions = new LPGAMMATABLE[nColorChannels()+1];
00386 
00387     for(uint ch=0; ch < nColorChannels(); ch++) {
00388         transferFunctions[ch] = cmsBuildGamma(256, 1.0);
00389         for(uint i =0; i < 256; i++) {
00390             transferFunctions[ch]->GammaTable[i] = transferValues[ch][i];
00391         }
00392     }
00393 
00394     KisColorAdjustmentImpl *adj = new KisColorAdjustmentImpl;
00395     adj->profiles[0] = cmsCreateLinearizationDeviceLink(colorSpaceSignature(), transferFunctions);
00396     adj->profiles[1] = NULL;
00397     adj->profiles[2] = NULL;
00398     adj->csProfile = m_profile->profile();
00399     adj->transform  = cmsCreateTransform(adj->profiles[0], m_cmType, NULL, m_cmType, INTENT_PERCEPTUAL, 0);
00400 
00401     delete [] transferFunctions;
00402 
00403     return adj;
00404 }
00405 
00406 
00407 void KisAbstractColorSpace::applyAdjustment(const Q_UINT8 *src, Q_UINT8 *dst, KisColorAdjustment *adjustment, Q_INT32 nPixels)
00408 {
00409     KisColorAdjustmentImpl * adj = dynamic_cast<KisColorAdjustmentImpl*>(adjustment);
00410     if (adj)
00411         cmsDoTransform(adj->transform, const_cast<Q_UINT8 *>(src), dst, nPixels);
00412 }
00413 
00414 
00415 void KisAbstractColorSpace::invertColor(Q_UINT8 * src, Q_INT32 nPixels)
00416 {
00417     QColor c;
00418     Q_UINT8 opacity;
00419     Q_UINT32 psize = pixelSize();
00420 
00421     while (nPixels--)
00422     {
00423         toQColor(src, &c, &opacity);
00424         c.setRgb(Q_UINT8_MAX - c.red(), Q_UINT8_MAX - c.green(), Q_UINT8_MAX - c.blue());
00425         fromQColor( c, opacity, src);
00426 
00427         src += psize;
00428     }
00429 }
00430 
00431 Q_UINT8 KisAbstractColorSpace::difference(const Q_UINT8* src1, const Q_UINT8* src2)
00432 {
00433     if (m_defaultToLab) {
00434 
00435         Q_UINT8 lab1[8], lab2[8];
00436         cmsCIELab labF1, labF2;
00437 
00438         if (getAlpha(src1) == OPACITY_TRANSPARENT || getAlpha(src2) == OPACITY_TRANSPARENT)
00439             return (getAlpha(src1) == getAlpha(src2) ? 0 : 255);
00440 
00441         cmsDoTransform( m_defaultToLab, const_cast<Q_UINT8*>( src1 ), lab1, 1);
00442         cmsDoTransform( m_defaultToLab, const_cast<Q_UINT8*>( src2 ), lab2, 1);
00443         cmsLabEncoded2Float(&labF1, (WORD *)lab1);
00444         cmsLabEncoded2Float(&labF2, (WORD *)lab2);
00445         double diff = cmsDeltaE(&labF1, &labF2);
00446         if(diff>255)
00447             return 255;
00448         else
00449             return Q_INT8(diff);
00450     }
00451     else {
00452         QColor c1;
00453         Q_UINT8 opacity1;
00454         toQColor(src1, &c1, &opacity1);
00455 
00456         QColor c2;
00457         Q_UINT8 opacity2;
00458         toQColor(src2, &c2, &opacity2);
00459 
00460         Q_UINT8 red = abs(c1.red() - c2.red());
00461         Q_UINT8 green = abs(c1.green() - c2.green());
00462         Q_UINT8 blue = abs(c1.blue() - c2.blue());
00463         return QMAX(red, QMAX(green, blue));
00464     }
00465 }
00466 
00467 void KisAbstractColorSpace::mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const
00468 {
00469     Q_UINT32 totalRed = 0, totalGreen = 0, totalBlue = 0, newAlpha = 0;
00470 
00471     QColor c;
00472     Q_UINT8 opacity;
00473 
00474     while (nColors--)
00475     {
00476         // Ugly hack to get around the current constness mess of the colour strategy...
00477         const_cast<KisAbstractColorSpace *>(this)->toQColor(*colors, &c, &opacity);
00478 
00479         Q_UINT32 alphaTimesWeight = UINT8_MULT(opacity, *weights);
00480 
00481         totalRed += c.red() * alphaTimesWeight;
00482         totalGreen += c.green() * alphaTimesWeight;
00483         totalBlue += c.blue() * alphaTimesWeight;
00484         newAlpha += alphaTimesWeight;
00485 
00486         weights++;
00487         colors++;
00488     }
00489 
00490     Q_ASSERT(newAlpha <= 255);
00491 
00492     if (newAlpha > 0) {
00493         totalRed = UINT8_DIVIDE(totalRed, newAlpha);
00494         totalGreen = UINT8_DIVIDE(totalGreen, newAlpha);
00495         totalBlue = UINT8_DIVIDE(totalBlue, newAlpha);
00496     }
00497 
00498     // Divide by 255.
00499     totalRed += 0x80;
00500 
00501     Q_UINT32 dstRed = ((totalRed >> 8) + totalRed) >> 8;
00502     Q_ASSERT(dstRed <= 255);
00503 
00504     totalGreen += 0x80;
00505     Q_UINT32 dstGreen = ((totalGreen >> 8) + totalGreen) >> 8;
00506     Q_ASSERT(dstGreen <= 255);
00507 
00508     totalBlue += 0x80;
00509     Q_UINT32 dstBlue = ((totalBlue >> 8) + totalBlue) >> 8;
00510     Q_ASSERT(dstBlue <= 255);
00511 
00512     const_cast<KisAbstractColorSpace *>(this)->fromQColor(QColor(dstRed, dstGreen, dstBlue), newAlpha, dst);
00513 }
00514 
00515 void KisAbstractColorSpace::convolveColors(Q_UINT8** colors, Q_INT32 * kernelValues, KisChannelInfo::enumChannelFlags channelFlags,
00516                                            Q_UINT8 *dst, Q_INT32 factor, Q_INT32 offset, Q_INT32 nColors) const
00517 {
00518     Q_INT32 totalRed = 0, totalGreen = 0, totalBlue = 0, totalAlpha = 0;
00519 
00520     QColor dstColor;
00521     Q_UINT8 dstOpacity;
00522 
00523     const_cast<KisAbstractColorSpace *>(this)->toQColor(dst, &dstColor, &dstOpacity);
00524 
00525     while (nColors--)
00526     {
00527         Q_INT32 weight = *kernelValues;
00528 
00529         if (weight != 0) {
00530             QColor c;
00531             Q_UINT8 opacity;
00532             const_cast<KisAbstractColorSpace *>(this)->toQColor( *colors, &c, &opacity );
00533             totalRed += c.red() * weight;
00534             totalGreen += c.green() * weight;
00535             totalBlue += c.blue() * weight;
00536             totalAlpha += opacity * weight;
00537         }
00538         colors++;
00539         kernelValues++;
00540     }
00541 
00542 
00543     if (channelFlags & KisChannelInfo::FLAG_COLOR) {
00544         const_cast<KisAbstractColorSpace *>(this)->fromQColor(QColor(CLAMP((totalRed / factor) + offset, 0, Q_UINT8_MAX),
00545                                         CLAMP((totalGreen / factor) + offset, 0, Q_UINT8_MAX),
00546                                         CLAMP((totalBlue / factor) + offset, 0, Q_UINT8_MAX)),
00547             dstOpacity,
00548             dst);
00549     }
00550     if (channelFlags & KisChannelInfo::FLAG_ALPHA) {
00551         const_cast<KisAbstractColorSpace *>(this)->fromQColor(dstColor, CLAMP((totalAlpha/ factor) + offset, 0, Q_UINT8_MAX), dst);
00552     }
00553 
00554 }
00555 
00556 void KisAbstractColorSpace::darken(const Q_UINT8 * src, Q_UINT8 * dst, Q_INT32 shade, bool compensate, double compensation, Q_INT32 nPixels) const
00557 {
00558     if (m_defaultToLab) {
00559         Q_UINT16 * labcache = new Q_UINT16[nPixels * 4];
00560         cmsDoTransform( m_defaultToLab, const_cast<Q_UINT8*>( src ), reinterpret_cast<Q_UINT8*>( labcache ), nPixels );
00561         for ( int i = 0; i < nPixels * 4; ++i ) {
00562             if ( compensate ) {
00563                 labcache[i] = static_cast<Q_UINT16>( ( labcache[i] * shade ) / ( compensation * 255 ) );
00564             }
00565             else {
00566                 labcache[i] = static_cast<Q_UINT16>( labcache[i] * shade  / 255 );
00567             }
00568         }
00569         cmsDoTransform( m_defaultFromLab, reinterpret_cast<Q_UINT8*>( labcache ), dst, nPixels );
00570 
00571         // Copy alpha
00572         for ( int i = 0; i < nPixels; ++i ) {
00573             Q_UINT8 alpha = getAlpha( src );
00574             setAlpha( dst, alpha, 1 );
00575         }
00576         delete [] labcache;
00577     }
00578     else {
00579 
00580         QColor c;
00581         Q_INT32 psize = pixelSize();
00582 
00583         for (int i = 0; i < nPixels; ++i) {
00584 
00585             const_cast<KisAbstractColorSpace *>(this)->toQColor(src + (i * psize), &c);
00586             Q_INT32 r, g, b;
00587 
00588             if (compensate) {
00589                 r = static_cast<Q_INT32>( QMIN(255, (c.red() * shade) / (compensation * 255)));
00590                 g = static_cast<Q_INT32>( QMIN(255, (c.green() * shade) / (compensation * 255)));
00591                 b = static_cast<Q_INT32>( QMIN(255, (c.blue() * shade) / (compensation * 255)));
00592             }
00593             else {
00594                 r = static_cast<Q_INT32>( QMIN(255, (c.red() * shade / 255)));
00595                 g = static_cast<Q_INT32>( QMIN(255, (c.green() * shade / 255)));
00596                 b = static_cast<Q_INT32>( QMIN(255, (c.blue() * shade / 255)));
00597             }
00598             c.setRgb(r, g, b);
00599 
00600             const_cast<KisAbstractColorSpace *>(this)->fromQColor( c, dst  + (i * psize));
00601         }
00602     }
00603 }
00604 
00605 Q_UINT8 KisAbstractColorSpace::intensity8(const Q_UINT8 * src) const
00606 {
00607     QColor c;
00608     Q_UINT8 opacity;
00609     const_cast<KisAbstractColorSpace *>(this)->toQColor(src, &c, &opacity);
00610     return static_cast<Q_UINT8>((c.red() * 0.30 + c.green() * 0.59 + c.blue() * 0.11) + 0.5);
00611 
00612 }
00613 
00614 
00615 KisID KisAbstractColorSpace::mathToolboxID() const
00616 {
00617     return KisID("Basic");
00618 }
00619 
00620 void KisAbstractColorSpace::bitBlt(Q_UINT8 *dst,
00621                    Q_INT32 dststride,
00622                    KisColorSpace * srcSpace,
00623                    const Q_UINT8 *src,
00624                    Q_INT32 srcRowStride,
00625                    const Q_UINT8 *srcAlphaMask,
00626                    Q_INT32 maskRowStride,
00627                    Q_UINT8 opacity,
00628                    Q_INT32 rows,
00629                    Q_INT32 cols,
00630                    const KisCompositeOp& op)
00631 {
00632     if (rows <= 0 || cols <= 0)
00633         return;
00634 
00635     if (this != srcSpace) {
00636         Q_UINT32 len = pixelSize() * rows * cols;
00637 
00638         // If our conversion cache is too small, extend it.
00639         if (!m_conversionCache.resize( len, QGArray::SpeedOptim )) {
00640             kdWarning() << "Could not allocate enough memory for the conversion!\n";
00641             // XXX: We should do a slow, pixel by pixel bitblt here...
00642             abort();
00643         }
00644 
00645         for (Q_INT32 row = 0; row < rows; row++) {
00646             srcSpace->convertPixelsTo(src + row * srcRowStride,
00647                                         m_conversionCache.data() + row * cols * pixelSize(), this,
00648                                         cols);
00649         }
00650 
00651         // The old srcRowStride is no longer valid because we converted to the current cs
00652         srcRowStride = cols * pixelSize();
00653 
00654         bitBlt(dst,
00655                dststride,
00656                m_conversionCache.data(),
00657                srcRowStride,
00658                srcAlphaMask,
00659                maskRowStride,
00660                opacity,
00661                rows,
00662                cols,
00663                op);
00664 
00665     }
00666     else {
00667         bitBlt(dst,
00668                dststride,
00669                src,
00670                srcRowStride,
00671                srcAlphaMask,
00672                maskRowStride,
00673                opacity,
00674                rows,
00675                cols,
00676                op);
00677     }
00678 }
00679 
00680 QImage KisAbstractColorSpace::convertToQImage(const Q_UINT8 *data, Q_INT32 width, Q_INT32 height,
00681                                               KisProfile *dstProfile,
00682                                               Q_INT32 renderingIntent, float /*exposure*/)
00683 
00684 {
00685     QImage img = QImage(width, height, 32, 0, QImage::LittleEndian);
00686     img.setAlphaBuffer( true );
00687 
00688     KisColorSpace * dstCS;
00689 
00690     if (dstProfile)
00691         dstCS = m_parent->getColorSpace(KisID("RGBA",""),dstProfile->productName());
00692     else
00693         dstCS = m_parent->getRGB8();
00694 
00695     if (data)
00696         convertPixelsTo(const_cast<Q_UINT8 *>(data), img.bits(), dstCS, width * height, renderingIntent);
00697 
00698     return img;
00699 }
00700 
00701 
00702 cmsHTRANSFORM KisAbstractColorSpace::createTransform(KisColorSpace * dstColorSpace,
00703                              KisProfile *  srcProfile,
00704                              KisProfile *  dstProfile,
00705                              Q_INT32 renderingIntent)
00706 {
00707     KConfig * cfg = KGlobal::config();
00708     bool bpCompensation = cfg->readBoolEntry("useBlackPointCompensation", false);
00709 
00710     int flags = 0;
00711 
00712     if (bpCompensation) {
00713         flags = cmsFLAGS_BLACKPOINTCOMPENSATION;
00714     }
00715 
00716     if (dstColorSpace && dstProfile && srcProfile ) {
00717         cmsHTRANSFORM tf = cmsCreateTransform(srcProfile->profile(),
00718                               colorSpaceType(),
00719                               dstProfile->profile(),
00720                               dstColorSpace->colorSpaceType(),
00721                               renderingIntent,
00722                               flags);
00723 
00724         return tf;
00725     }
00726     return 0;
00727 }
00728 
00729 void KisAbstractColorSpace::compositeCopy(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 * /*maskRowStart*/, Q_INT32 /*maskRowStride*/, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity)
00730 {
00731     Q_UINT8 *dst = dstRowStart;
00732     const Q_UINT8 *src = srcRowStart;
00733     Q_INT32 bytesPerPixel = pixelSize();
00734 
00735     while (rows > 0) {
00736         memcpy(dst, src, numColumns * bytesPerPixel);
00737 
00738         if (opacity != OPACITY_OPAQUE) {
00739             multiplyAlpha(dst, opacity, numColumns);
00740         }
00741 
00742         dst += dstRowStride;
00743         src += srcRowStride;
00744         --rows;
00745     }
00746 }
00747 
KDE Home | KDE Accessibility Home | Description of Access Keys