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::toLabA16(const Q_UINT8 * src, Q_UINT8 * dst, const Q_UINT32 nPixels) const
00181 {
00182     if ( m_defaultToLab == 0 ) return;
00183 
00184     cmsDoTransform( m_defaultToLab, const_cast<Q_UINT8 *>( src ), dst, nPixels );
00185 }
00186 
00187 void KisAbstractColorSpace::fromLabA16(const Q_UINT8 * src, Q_UINT8 * dst, const Q_UINT32 nPixels) const
00188 {
00189     if ( m_defaultFromLab == 0 ) return;
00190 
00191     cmsDoTransform( m_defaultFromLab,  const_cast<Q_UINT8 *>( src ), dst,  nPixels );
00192 }
00193 
00194 
00195 void KisAbstractColorSpace::getSingleChannelPixel(Q_UINT8 *dstPixel, const Q_UINT8 *srcPixel, Q_UINT32 channelIndex)
00196 {
00197     if (channelIndex < m_channels.count()) {
00198 
00199         fromQColor(Qt::black, OPACITY_TRANSPARENT, dstPixel);
00200 
00201         const KisChannelInfo *channelInfo = m_channels[channelIndex];
00202         memcpy(dstPixel + channelInfo->pos(), srcPixel + channelInfo->pos(), channelInfo->size());
00203     }
00204 }
00205 
00206 bool KisAbstractColorSpace::convertPixelsTo(const Q_UINT8 * src,
00207                         Q_UINT8 * dst,
00208                         KisColorSpace * dstColorSpace,
00209                         Q_UINT32 numPixels,
00210                         Q_INT32 renderingIntent)
00211 {
00212     if (dstColorSpace->colorSpaceType() == colorSpaceType()
00213         && dstColorSpace->getProfile() == getProfile())
00214     {
00215         if (src!= dst)
00216             memcpy (dst, src, numPixels * pixelSize());
00217 
00218         return true;
00219     }
00220 
00221     cmsHTRANSFORM tf = 0;
00222 
00223     Q_INT32 srcPixelSize = pixelSize();
00224     Q_INT32 dstPixelSize = dstColorSpace->pixelSize();
00225 
00226     if (m_lastUsedTransform != 0 && m_lastUsedDstColorSpace != 0) {
00227         if (dstColorSpace->colorSpaceType() == m_lastUsedDstColorSpace->colorSpaceType() &&
00228             dstColorSpace->getProfile() == m_lastUsedDstColorSpace->getProfile()) {
00229             tf = m_lastUsedTransform;
00230         }
00231     }
00232 
00233     if (!tf && m_profile && dstColorSpace->getProfile()) {
00234 
00235         if (!m_transforms.contains(dstColorSpace)) {
00236             tf = createTransform(dstColorSpace,
00237                  m_profile,
00238                  dstColorSpace->getProfile(),
00239                  renderingIntent);
00240             if (tf) {
00241         // XXX: Should we clear the transform cache if it gets too big?
00242         m_transforms[dstColorSpace] = tf;
00243             }
00244         }
00245         else {
00246             tf = m_transforms[dstColorSpace];
00247         }
00248 
00249         if ( tf ) {
00250             m_lastUsedTransform = tf;
00251             m_lastUsedDstColorSpace = dstColorSpace;
00252         }
00253     }
00254 
00255     if (tf) {
00256 
00257         cmsDoTransform(tf, const_cast<Q_UINT8 *>(src), dst, numPixels);
00258 
00259         // Lcms does nothing to the destination alpha channel so we must convert that manually.
00260         while (numPixels > 0) {
00261             Q_UINT8 alpha = getAlpha(src);
00262             dstColorSpace->setAlpha(dst, alpha, 1);
00263 
00264             src += srcPixelSize;
00265             dst += dstPixelSize;
00266             numPixels--;
00267         }
00268 
00269         return true;
00270     }
00271 
00272     // Last resort fallback. This will be removed when this class is renamed KisLCMSColorSpace after 1.5.
00273     while (numPixels > 0) {
00274         QColor color;
00275         Q_UINT8 opacity;
00276 
00277         toQColor(src, &color, &opacity);
00278         dstColorSpace->fromQColor(color, opacity, dst);
00279 
00280         src += srcPixelSize;
00281         dst += dstPixelSize;
00282         numPixels--;
00283     }
00284 
00285     return true;
00286 }
00287 
00288 
00289 KisColorAdjustment *KisAbstractColorSpace::createBrightnessContrastAdjustment(Q_UINT16 *transferValues)
00290 {
00291     if (!m_profile) return 0;
00292 
00293     LPGAMMATABLE transferFunctions[3];
00294     transferFunctions[0] = cmsBuildGamma(256, 1.0);
00295     transferFunctions[1] = cmsBuildGamma(256, 1.0);
00296     transferFunctions[2] = cmsBuildGamma(256, 1.0);
00297 
00298     for(int i =0; i < 256; i++)
00299         transferFunctions[0]->GammaTable[i] = transferValues[i];
00300 
00301     KisColorAdjustmentImpl *adj = new KisColorAdjustmentImpl;
00302     adj->profiles[1] = cmsCreateLinearizationDeviceLink(icSigLabData, transferFunctions);
00303     cmsSetDeviceClass(adj->profiles[1], icSigAbstractClass);
00304 
00305     adj->profiles[0] = m_profile->profile();
00306     adj->profiles[2] = m_profile->profile();
00307     adj->transform  = cmsCreateMultiprofileTransform(adj->profiles, 3, m_cmType, m_cmType, INTENT_PERCEPTUAL, 0);
00308     adj->csProfile = m_profile->profile();
00309     return adj;
00310 }
00311 
00312 typedef struct {
00313                 double Saturation;
00314 
00315 } BCHSWADJUSTS, *LPBCHSWADJUSTS;
00316 
00317 
00318 static int desaturateSampler(register WORD In[], register WORD Out[], register LPVOID /*Cargo*/)
00319 {
00320     cmsCIELab LabIn, LabOut;
00321     cmsCIELCh LChIn, LChOut;
00322     //LPBCHSWADJUSTS bchsw = (LPBCHSWADJUSTS) Cargo;
00323 
00324     cmsLabEncoded2Float(&LabIn, In);
00325 
00326     cmsLab2LCh(&LChIn, &LabIn);
00327 
00328     // Do some adjusts on LCh
00329     LChOut.L = LChIn.L;
00330     LChOut.C = 0;//LChIn.C + bchsw->Saturation;
00331     LChOut.h = LChIn.h;
00332 
00333     cmsLCh2Lab(&LabOut, &LChOut);
00334 
00335     // Back to encoded
00336     cmsFloat2LabEncoded(Out, &LabOut);
00337 
00338     return TRUE;
00339 }
00340 
00341 KisColorAdjustment *KisAbstractColorSpace::createDesaturateAdjustment()
00342 {
00343     if (!m_profile) return 0;
00344 
00345     KisColorAdjustmentImpl *adj = new KisColorAdjustmentImpl;
00346 
00347     adj->profiles[0] = m_profile->profile();
00348     adj->profiles[2] = m_profile->profile();
00349     adj->csProfile = m_profile->profile();
00350 
00351      LPLUT Lut;
00352      BCHSWADJUSTS bchsw;
00353 
00354      bchsw.Saturation = -25;
00355 
00356      adj->profiles[1] = _cmsCreateProfilePlaceholder();
00357      if (!adj->profiles[1]) // can't allocate
00358         return NULL;
00359 
00360      cmsSetDeviceClass(adj->profiles[1], icSigAbstractClass);
00361      cmsSetColorSpace(adj->profiles[1], icSigLabData);
00362      cmsSetPCS(adj->profiles[1], icSigLabData);
00363 
00364      cmsSetRenderingIntent(adj->profiles[1], INTENT_PERCEPTUAL);
00365 
00366      // Creates a LUT with 3D grid only
00367      Lut = cmsAllocLUT();
00368 
00369      cmsAlloc3DGrid(Lut, 32, 3, 3);
00370 
00371      if (!cmsSample3DGrid(Lut, desaturateSampler, static_cast<LPVOID>(&bchsw), 0)) {
00372          // Shouldn't reach here
00373          cmsFreeLUT(Lut);
00374          cmsCloseProfile(adj->profiles[1]);
00375          return NULL;
00376      }
00377 
00378     // Create tags
00379 
00380     cmsAddTag(adj->profiles[1], icSigDeviceMfgDescTag,      (LPVOID) "(krita internal)");
00381     cmsAddTag(adj->profiles[1], icSigProfileDescriptionTag, (LPVOID) "krita saturation abstract profile");
00382     cmsAddTag(adj->profiles[1], icSigDeviceModelDescTag,    (LPVOID) "saturation built-in");
00383 
00384     cmsAddTag(adj->profiles[1], icSigMediaWhitePointTag, (LPVOID) cmsD50_XYZ());
00385 
00386     cmsAddTag(adj->profiles[1], icSigAToB0Tag, (LPVOID) Lut);
00387 
00388     // LUT is already on virtual profile
00389     cmsFreeLUT(Lut);
00390 
00391     adj->transform  = cmsCreateMultiprofileTransform(adj->profiles, 3, m_cmType, m_cmType, INTENT_PERCEPTUAL, 0);
00392 
00393     return adj;
00394 }
00395 
00396 KisColorAdjustment *KisAbstractColorSpace::createPerChannelAdjustment(Q_UINT16 **transferValues)
00397 {
00398     if (!m_profile) return 0;
00399 
00400     LPGAMMATABLE *transferFunctions = new LPGAMMATABLE[nColorChannels()+1];
00401 
00402     for(uint ch=0; ch < nColorChannels(); ch++) {
00403         transferFunctions[ch] = cmsBuildGamma(256, 1.0);
00404         for(uint i =0; i < 256; i++) {
00405             transferFunctions[ch]->GammaTable[i] = transferValues[ch][i];
00406         }
00407     }
00408 
00409     KisColorAdjustmentImpl *adj = new KisColorAdjustmentImpl;
00410     adj->profiles[0] = cmsCreateLinearizationDeviceLink(colorSpaceSignature(), transferFunctions);
00411     adj->profiles[1] = NULL;
00412     adj->profiles[2] = NULL;
00413     adj->csProfile = m_profile->profile();
00414     adj->transform  = cmsCreateTransform(adj->profiles[0], m_cmType, NULL, m_cmType, INTENT_PERCEPTUAL, 0);
00415 
00416     delete [] transferFunctions;
00417 
00418     return adj;
00419 }
00420 
00421 
00422 void KisAbstractColorSpace::applyAdjustment(const Q_UINT8 *src, Q_UINT8 *dst, KisColorAdjustment *adjustment, Q_INT32 nPixels)
00423 {
00424     KisColorAdjustmentImpl * adj = dynamic_cast<KisColorAdjustmentImpl*>(adjustment);
00425     if (adj)
00426         cmsDoTransform(adj->transform, const_cast<Q_UINT8 *>(src), dst, nPixels);
00427 }
00428 
00429 
00430 void KisAbstractColorSpace::invertColor(Q_UINT8 * src, Q_INT32 nPixels)
00431 {
00432     QColor c;
00433     Q_UINT8 opacity;
00434     Q_UINT32 psize = pixelSize();
00435 
00436     while (nPixels--)
00437     {
00438         toQColor(src, &c, &opacity);
00439         c.setRgb(Q_UINT8_MAX - c.red(), Q_UINT8_MAX - c.green(), Q_UINT8_MAX - c.blue());
00440         fromQColor( c, opacity, src);
00441 
00442         src += psize;
00443     }
00444 }
00445 
00446 Q_UINT8 KisAbstractColorSpace::difference(const Q_UINT8* src1, const Q_UINT8* src2)
00447 {
00448     if (m_defaultToLab) {
00449 
00450         Q_UINT8 lab1[8], lab2[8];
00451         cmsCIELab labF1, labF2;
00452 
00453         if (getAlpha(src1) == OPACITY_TRANSPARENT || getAlpha(src2) == OPACITY_TRANSPARENT)
00454             return (getAlpha(src1) == getAlpha(src2) ? 0 : 255);
00455 
00456         cmsDoTransform( m_defaultToLab, const_cast<Q_UINT8*>( src1 ), lab1, 1);
00457         cmsDoTransform( m_defaultToLab, const_cast<Q_UINT8*>( src2 ), lab2, 1);
00458         cmsLabEncoded2Float(&labF1, (WORD *)lab1);
00459         cmsLabEncoded2Float(&labF2, (WORD *)lab2);
00460         double diff = cmsDeltaE(&labF1, &labF2);
00461         if(diff>255)
00462             return 255;
00463         else
00464             return Q_INT8(diff);
00465     }
00466     else {
00467         QColor c1;
00468         Q_UINT8 opacity1;
00469         toQColor(src1, &c1, &opacity1);
00470 
00471         QColor c2;
00472         Q_UINT8 opacity2;
00473         toQColor(src2, &c2, &opacity2);
00474 
00475         Q_UINT8 red = abs(c1.red() - c2.red());
00476         Q_UINT8 green = abs(c1.green() - c2.green());
00477         Q_UINT8 blue = abs(c1.blue() - c2.blue());
00478         return QMAX(red, QMAX(green, blue));
00479     }
00480 }
00481 
00482 void KisAbstractColorSpace::mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const
00483 {
00484     Q_UINT32 totalRed = 0, totalGreen = 0, totalBlue = 0, newAlpha = 0;
00485 
00486     QColor c;
00487     Q_UINT8 opacity;
00488 
00489     while (nColors--)
00490     {
00491         // Ugly hack to get around the current constness mess of the colour strategy...
00492         const_cast<KisAbstractColorSpace *>(this)->toQColor(*colors, &c, &opacity);
00493 
00494         Q_UINT32 alphaTimesWeight = UINT8_MULT(opacity, *weights);
00495 
00496         totalRed += c.red() * alphaTimesWeight;
00497         totalGreen += c.green() * alphaTimesWeight;
00498         totalBlue += c.blue() * alphaTimesWeight;
00499         newAlpha += alphaTimesWeight;
00500 
00501         weights++;
00502         colors++;
00503     }
00504 
00505     Q_ASSERT(newAlpha <= 255);
00506 
00507     if (newAlpha > 0) {
00508         totalRed = UINT8_DIVIDE(totalRed, newAlpha);
00509         totalGreen = UINT8_DIVIDE(totalGreen, newAlpha);
00510         totalBlue = UINT8_DIVIDE(totalBlue, newAlpha);
00511     }
00512 
00513     // Divide by 255.
00514     totalRed += 0x80;
00515 
00516     Q_UINT32 dstRed = ((totalRed >> 8) + totalRed) >> 8;
00517     Q_ASSERT(dstRed <= 255);
00518 
00519     totalGreen += 0x80;
00520     Q_UINT32 dstGreen = ((totalGreen >> 8) + totalGreen) >> 8;
00521     Q_ASSERT(dstGreen <= 255);
00522 
00523     totalBlue += 0x80;
00524     Q_UINT32 dstBlue = ((totalBlue >> 8) + totalBlue) >> 8;
00525     Q_ASSERT(dstBlue <= 255);
00526 
00527     const_cast<KisAbstractColorSpace *>(this)->fromQColor(QColor(dstRed, dstGreen, dstBlue), newAlpha, dst);
00528 }
00529 
00530 void KisAbstractColorSpace::convolveColors(Q_UINT8** colors, Q_INT32 * kernelValues, KisChannelInfo::enumChannelFlags channelFlags,
00531                                            Q_UINT8 *dst, Q_INT32 factor, Q_INT32 offset, Q_INT32 nColors) const
00532 {
00533     Q_INT32 totalRed = 0, totalGreen = 0, totalBlue = 0, totalAlpha = 0;
00534 
00535     QColor dstColor;
00536     Q_UINT8 dstOpacity;
00537 
00538     const_cast<KisAbstractColorSpace *>(this)->toQColor(dst, &dstColor, &dstOpacity);
00539 
00540     while (nColors--)
00541     {
00542         Q_INT32 weight = *kernelValues;
00543 
00544         if (weight != 0) {
00545             QColor c;
00546             Q_UINT8 opacity;
00547             const_cast<KisAbstractColorSpace *>(this)->toQColor( *colors, &c, &opacity );
00548             totalRed += c.red() * weight;
00549             totalGreen += c.green() * weight;
00550             totalBlue += c.blue() * weight;
00551             totalAlpha += opacity * weight;
00552         }
00553         colors++;
00554         kernelValues++;
00555     }
00556 
00557 
00558     if (channelFlags & KisChannelInfo::FLAG_COLOR) {
00559         const_cast<KisAbstractColorSpace *>(this)->fromQColor(QColor(CLAMP((totalRed / factor) + offset, 0, Q_UINT8_MAX),
00560                                         CLAMP((totalGreen / factor) + offset, 0, Q_UINT8_MAX),
00561                                         CLAMP((totalBlue / factor) + offset, 0, Q_UINT8_MAX)),
00562             dstOpacity,
00563             dst);
00564     }
00565     if (channelFlags & KisChannelInfo::FLAG_ALPHA) {
00566         const_cast<KisAbstractColorSpace *>(this)->fromQColor(dstColor, CLAMP((totalAlpha/ factor) + offset, 0, Q_UINT8_MAX), dst);
00567     }
00568 
00569 }
00570 
00571 void KisAbstractColorSpace::darken(const Q_UINT8 * src, Q_UINT8 * dst, Q_INT32 shade, bool compensate, double compensation, Q_INT32 nPixels) const
00572 {
00573     if (m_defaultToLab) {
00574         Q_UINT16 * labcache = new Q_UINT16[nPixels * 4];
00575         cmsDoTransform( m_defaultToLab, const_cast<Q_UINT8*>( src ), reinterpret_cast<Q_UINT8*>( labcache ), nPixels );
00576         for ( int i = 0; i < nPixels * 4; ++i ) {
00577             if ( compensate ) {
00578                 labcache[i] = static_cast<Q_UINT16>( ( labcache[i] * shade ) / ( compensation * 255 ) );
00579             }
00580             else {
00581                 labcache[i] = static_cast<Q_UINT16>( labcache[i] * shade  / 255 );
00582             }
00583         }
00584         cmsDoTransform( m_defaultFromLab, reinterpret_cast<Q_UINT8*>( labcache ), dst, nPixels );
00585 
00586         // Copy alpha
00587         for ( int i = 0; i < nPixels; ++i ) {
00588             Q_UINT8 alpha = getAlpha( src );
00589             setAlpha( dst, alpha, 1 );
00590         }
00591         delete [] labcache;
00592     }
00593     else {
00594 
00595         QColor c;
00596         Q_INT32 psize = pixelSize();
00597 
00598         for (int i = 0; i < nPixels; ++i) {
00599 
00600             const_cast<KisAbstractColorSpace *>(this)->toQColor(src + (i * psize), &c);
00601             Q_INT32 r, g, b;
00602 
00603             if (compensate) {
00604                 r = static_cast<Q_INT32>( QMIN(255, (c.red() * shade) / (compensation * 255)));
00605                 g = static_cast<Q_INT32>( QMIN(255, (c.green() * shade) / (compensation * 255)));
00606                 b = static_cast<Q_INT32>( QMIN(255, (c.blue() * shade) / (compensation * 255)));
00607             }
00608             else {
00609                 r = static_cast<Q_INT32>( QMIN(255, (c.red() * shade / 255)));
00610                 g = static_cast<Q_INT32>( QMIN(255, (c.green() * shade / 255)));
00611                 b = static_cast<Q_INT32>( QMIN(255, (c.blue() * shade / 255)));
00612             }
00613             c.setRgb(r, g, b);
00614 
00615             const_cast<KisAbstractColorSpace *>(this)->fromQColor( c, dst  + (i * psize));
00616         }
00617     }
00618 }
00619 
00620 Q_UINT8 KisAbstractColorSpace::intensity8(const Q_UINT8 * src) const
00621 {
00622     QColor c;
00623     Q_UINT8 opacity;
00624     const_cast<KisAbstractColorSpace *>(this)->toQColor(src, &c, &opacity);
00625     return static_cast<Q_UINT8>((c.red() * 0.30 + c.green() * 0.59 + c.blue() * 0.11) + 0.5);
00626 
00627 }
00628 
00629 
00630 KisID KisAbstractColorSpace::mathToolboxID() const
00631 {
00632     return KisID("Basic");
00633 }
00634 
00635 void KisAbstractColorSpace::bitBlt(Q_UINT8 *dst,
00636                    Q_INT32 dststride,
00637                    KisColorSpace * srcSpace,
00638                    const Q_UINT8 *src,
00639                    Q_INT32 srcRowStride,
00640                    const Q_UINT8 *srcAlphaMask,
00641                    Q_INT32 maskRowStride,
00642                    Q_UINT8 opacity,
00643                    Q_INT32 rows,
00644                    Q_INT32 cols,
00645                    const KisCompositeOp& op)
00646 {
00647     if (rows <= 0 || cols <= 0)
00648         return;
00649 
00650     if (this != srcSpace) {
00651         Q_UINT32 len = pixelSize() * rows * cols;
00652 
00653         // If our conversion cache is too small, extend it.
00654         if (!m_conversionCache.resize( len, QGArray::SpeedOptim )) {
00655             kdWarning() << "Could not allocate enough memory for the conversion!\n";
00656             // XXX: We should do a slow, pixel by pixel bitblt here...
00657             abort();
00658         }
00659 
00660         for (Q_INT32 row = 0; row < rows; row++) {
00661             srcSpace->convertPixelsTo(src + row * srcRowStride,
00662                                         m_conversionCache.data() + row * cols * pixelSize(), this,
00663                                         cols);
00664         }
00665 
00666         // The old srcRowStride is no longer valid because we converted to the current cs
00667         srcRowStride = cols * pixelSize();
00668 
00669         bitBlt(dst,
00670                dststride,
00671                m_conversionCache.data(),
00672                srcRowStride,
00673                srcAlphaMask,
00674                maskRowStride,
00675                opacity,
00676                rows,
00677                cols,
00678                op);
00679 
00680     }
00681     else {
00682         bitBlt(dst,
00683                dststride,
00684                src,
00685                srcRowStride,
00686                srcAlphaMask,
00687                maskRowStride,
00688                opacity,
00689                rows,
00690                cols,
00691                op);
00692     }
00693 }
00694 
00695 QImage KisAbstractColorSpace::convertToQImage(const Q_UINT8 *data, Q_INT32 width, Q_INT32 height,
00696                                               KisProfile *dstProfile,
00697                                               Q_INT32 renderingIntent, float /*exposure*/)
00698 
00699 {
00700     QImage img = QImage(width, height, 32, 0, QImage::LittleEndian);
00701     img.setAlphaBuffer( true );
00702 
00703     KisColorSpace * dstCS;
00704 
00705     if (dstProfile)
00706         dstCS = m_parent->getColorSpace(KisID("RGBA",""),dstProfile->productName());
00707     else
00708         dstCS = m_parent->getRGB8();
00709 
00710     if (data)
00711         convertPixelsTo(const_cast<Q_UINT8 *>(data), img.bits(), dstCS, width * height, renderingIntent);
00712 
00713     return img;
00714 }
00715 
00716 
00717 cmsHTRANSFORM KisAbstractColorSpace::createTransform(KisColorSpace * dstColorSpace,
00718                              KisProfile *  srcProfile,
00719                              KisProfile *  dstProfile,
00720                              Q_INT32 renderingIntent)
00721 {
00722     KConfig * cfg = KGlobal::config();
00723     bool bpCompensation = cfg->readBoolEntry("useBlackPointCompensation", false);
00724 
00725     int flags = 0;
00726 
00727     if (bpCompensation) {
00728         flags = cmsFLAGS_BLACKPOINTCOMPENSATION;
00729     }
00730 
00731     if (dstColorSpace && dstProfile && srcProfile ) {
00732         cmsHTRANSFORM tf = cmsCreateTransform(srcProfile->profile(),
00733                               colorSpaceType(),
00734                               dstProfile->profile(),
00735                               dstColorSpace->colorSpaceType(),
00736                               renderingIntent,
00737                               flags);
00738 
00739         return tf;
00740     }
00741     return 0;
00742 }
00743 
00744 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)
00745 {
00746     Q_UINT8 *dst = dstRowStart;
00747     const Q_UINT8 *src = srcRowStart;
00748     Q_INT32 bytesPerPixel = pixelSize();
00749 
00750     while (rows > 0) {
00751         memcpy(dst, src, numColumns * bytesPerPixel);
00752 
00753         if (opacity != OPACITY_OPAQUE) {
00754             multiplyAlpha(dst, opacity, numColumns);
00755         }
00756 
00757         dst += dstRowStride;
00758         src += srcRowStride;
00759         --rows;
00760     }
00761 }
00762 
KDE Home | KDE Accessibility Home | Description of Access Keys