summaryrefslogtreecommitdiffstats
path: root/chalk/chalkcolor/kis_abstract_colorspace.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'chalk/chalkcolor/kis_abstract_colorspace.cpp')
-rw-r--r--chalk/chalkcolor/kis_abstract_colorspace.cpp762
1 files changed, 762 insertions, 0 deletions
diff --git a/chalk/chalkcolor/kis_abstract_colorspace.cpp b/chalk/chalkcolor/kis_abstract_colorspace.cpp
new file mode 100644
index 000000000..7f5155348
--- /dev/null
+++ b/chalk/chalkcolor/kis_abstract_colorspace.cpp
@@ -0,0 +1,762 @@
+/*
+ * Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
+ * Copyright (c) 2004 Cyrille Berger <cberger@cberger.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include <tqimage.h>
+
+#include <kdebug.h>
+#include <tdeconfig.h>
+
+#include "kis_abstract_colorspace.h"
+#include "kis_global.h"
+#include "kis_profile.h"
+#include "kis_id.h"
+#include "kis_integer_maths.h"
+#include "kis_color_conversions.h"
+#include "kis_colorspace_factory_registry.h"
+#include "kis_channelinfo.h"
+
+class KisColorAdjustmentImpl : public KisColorAdjustment
+{
+ public:
+
+ KisColorAdjustmentImpl() : KisColorAdjustment()
+ {
+ csProfile = 0;
+ transform = 0;
+ profiles[0] = 0;
+ profiles[1] = 0;
+ profiles[2] = 0;
+ };
+
+ ~KisColorAdjustmentImpl() {
+
+ if (transform)
+ cmsDeleteTransform(transform);
+ if (profiles[0] && profiles[0] != csProfile)
+ cmsCloseProfile(profiles[0]);
+ if(profiles[1] && profiles[1] != csProfile)
+ cmsCloseProfile(profiles[1]);
+ if(profiles[2] && profiles[2] != csProfile)
+ cmsCloseProfile(profiles[2]);
+ }
+
+ cmsHPROFILE csProfile;
+ cmsHPROFILE profiles[3];
+ cmsHTRANSFORM transform;
+};
+
+KisAbstractColorSpace::KisAbstractColorSpace(const KisID& id,
+ DWORD cmType,
+ icColorSpaceSignature colorSpaceSignature,
+ KisColorSpaceFactoryRegistry * parent,
+ KisProfile *p)
+ : m_parent( parent )
+ , m_profile( p )
+ , m_id( id )
+ , m_cmType( cmType )
+ , m_colorSpaceSignature( colorSpaceSignature )
+{
+ m_alphaPos = -1;
+ m_alphaSize = -1;
+ m_qcolordata = 0;
+ m_lastUsedDstColorSpace = 0;
+ m_lastUsedTransform = 0;
+ m_lastRGBProfile = 0;
+ m_lastToRGB = 0;
+ m_lastFromRGB = 0;
+ m_defaultFromRGB = 0;
+ m_defaultToRGB = 0;
+ m_defaultFromLab = 0;
+ m_defaultToLab = 0;
+}
+
+void KisAbstractColorSpace::init()
+{
+ // Default pixel buffer for TQColor conversion
+ m_qcolordata = new TQ_UINT8[3];
+ TQ_CHECK_PTR(m_qcolordata);
+
+ if (m_profile == 0) return;
+
+ // For conversions from default rgb
+ m_lastFromRGB = cmsCreate_sRGBProfile();
+
+ m_defaultFromRGB = cmsCreateTransform(m_lastFromRGB, TYPE_BGR_8,
+ m_profile->profile(), m_cmType,
+ INTENT_PERCEPTUAL, 0);
+
+ m_defaultToRGB = cmsCreateTransform(m_profile->profile(), m_cmType,
+ m_lastFromRGB, TYPE_BGR_8,
+ INTENT_PERCEPTUAL, 0);
+
+ cmsHPROFILE hLab = cmsCreateLabProfile(NULL);
+
+ m_defaultFromLab = cmsCreateTransform(hLab, TYPE_Lab_16, m_profile->profile(), m_cmType,
+ INTENT_PERCEPTUAL, 0);
+
+ m_defaultToLab = cmsCreateTransform(m_profile->profile(), m_cmType, hLab, TYPE_Lab_16,
+ INTENT_PERCEPTUAL, 0);
+}
+
+KisAbstractColorSpace::~KisAbstractColorSpace()
+{
+}
+
+
+
+void KisAbstractColorSpace::fromTQColor(const TQColor& color, TQ_UINT8 *dst, KisProfile * profile)
+{
+ m_qcolordata[2] = color.red();
+ m_qcolordata[1] = color.green();
+ m_qcolordata[0] = color.blue();
+
+
+ if (profile == 0) {
+ // Default sRGB
+ if (!m_defaultFromRGB) return;
+
+ cmsDoTransform(m_defaultFromRGB, m_qcolordata, dst, 1);
+ }
+ else {
+ if (m_lastFromRGB == 0 || (m_lastFromRGB != 0 && m_lastRGBProfile != profile->profile())) {
+ m_lastFromRGB = cmsCreateTransform(profile->profile(), TYPE_BGR_8,
+ m_profile->profile(), m_cmType,
+ INTENT_PERCEPTUAL, 0);
+ m_lastRGBProfile = profile->profile();
+
+ }
+ cmsDoTransform(m_lastFromRGB, m_qcolordata, dst, 1);
+ }
+
+ setAlpha(dst, OPACITY_OPAQUE, 1);
+}
+
+void KisAbstractColorSpace::fromTQColor(const TQColor& color, TQ_UINT8 opacity, TQ_UINT8 *dst, KisProfile * profile)
+{
+ fromTQColor(color, dst, profile);
+ setAlpha(dst, opacity, 1);
+}
+
+void KisAbstractColorSpace::toTQColor(const TQ_UINT8 *src, TQColor *c, KisProfile * profile)
+{
+ if (profile == 0) {
+ // Default sRGB transform
+ if (!m_defaultToRGB) return;
+ cmsDoTransform(m_defaultToRGB, const_cast <TQ_UINT8 *>(src), m_qcolordata, 1);
+ }
+ else {
+ if (m_lastToRGB == 0 || (m_lastToRGB != 0 && m_lastRGBProfile != profile->profile())) {
+ m_lastToRGB = cmsCreateTransform(m_profile->profile(), m_cmType,
+ profile->profile(), TYPE_BGR_8,
+ INTENT_PERCEPTUAL, 0);
+ m_lastRGBProfile = profile->profile();
+ }
+ cmsDoTransform(m_lastToRGB, const_cast <TQ_UINT8 *>(src), m_qcolordata, 1);
+ }
+ c->setRgb(m_qcolordata[2], m_qcolordata[1], m_qcolordata[0]);
+}
+
+void KisAbstractColorSpace::toTQColor(const TQ_UINT8 *src, TQColor *c, TQ_UINT8 *opacity, KisProfile * profile)
+{
+ toTQColor(src, c, profile);
+ *opacity = getAlpha(src);
+}
+
+void KisAbstractColorSpace::toLabA16(const TQ_UINT8 * src, TQ_UINT8 * dst, const TQ_UINT32 nPixels) const
+{
+ if ( m_defaultToLab == 0 ) return;
+
+ cmsDoTransform( m_defaultToLab, const_cast<TQ_UINT8 *>( src ), dst, nPixels );
+}
+
+void KisAbstractColorSpace::fromLabA16(const TQ_UINT8 * src, TQ_UINT8 * dst, const TQ_UINT32 nPixels) const
+{
+ if ( m_defaultFromLab == 0 ) return;
+
+ cmsDoTransform( m_defaultFromLab, const_cast<TQ_UINT8 *>( src ), dst, nPixels );
+}
+
+
+void KisAbstractColorSpace::getSingleChannelPixel(TQ_UINT8 *dstPixel, const TQ_UINT8 *srcPixel, TQ_UINT32 channelIndex)
+{
+ if (channelIndex < m_channels.count()) {
+
+ fromTQColor(TQt::black, OPACITY_TRANSPARENT, dstPixel);
+
+ const KisChannelInfo *channelInfo = m_channels[channelIndex];
+ memcpy(dstPixel + channelInfo->pos(), srcPixel + channelInfo->pos(), channelInfo->size());
+ }
+}
+
+bool KisAbstractColorSpace::convertPixelsTo(const TQ_UINT8 * src,
+ TQ_UINT8 * dst,
+ KisColorSpace * dstColorSpace,
+ TQ_UINT32 numPixels,
+ TQ_INT32 renderingIntent)
+{
+ if (dstColorSpace->colorSpaceType() == colorSpaceType()
+ && dstColorSpace->getProfile() == getProfile())
+ {
+ if (src!= dst)
+ memcpy (dst, src, numPixels * pixelSize());
+
+ return true;
+ }
+
+ cmsHTRANSFORM tf = 0;
+
+ TQ_INT32 srcPixelSize = pixelSize();
+ TQ_INT32 dstPixelSize = dstColorSpace->pixelSize();
+
+ if (m_lastUsedTransform != 0 && m_lastUsedDstColorSpace != 0) {
+ if (dstColorSpace->colorSpaceType() == m_lastUsedDstColorSpace->colorSpaceType() &&
+ dstColorSpace->getProfile() == m_lastUsedDstColorSpace->getProfile()) {
+ tf = m_lastUsedTransform;
+ }
+ }
+
+ if (!tf && m_profile && dstColorSpace->getProfile()) {
+
+ if (!m_transforms.contains(dstColorSpace)) {
+ tf = createTransform(dstColorSpace,
+ m_profile,
+ dstColorSpace->getProfile(),
+ renderingIntent);
+ if (tf) {
+ // XXX: Should we clear the transform cache if it gets too big?
+ m_transforms[dstColorSpace] = tf;
+ }
+ }
+ else {
+ tf = m_transforms[dstColorSpace];
+ }
+
+ if ( tf ) {
+ m_lastUsedTransform = tf;
+ m_lastUsedDstColorSpace = dstColorSpace;
+ }
+ }
+
+ if (tf) {
+
+ cmsDoTransform(tf, const_cast<TQ_UINT8 *>(src), dst, numPixels);
+
+ // Lcms does nothing to the destination alpha channel so we must convert that manually.
+ while (numPixels > 0) {
+ TQ_UINT8 alpha = getAlpha(src);
+ dstColorSpace->setAlpha(dst, alpha, 1);
+
+ src += srcPixelSize;
+ dst += dstPixelSize;
+ numPixels--;
+ }
+
+ return true;
+ }
+
+ // Last resort fallback. This will be removed when this class is renamed KisLCMSColorSpace after 1.5.
+ while (numPixels > 0) {
+ TQColor color;
+ TQ_UINT8 opacity;
+
+ toTQColor(src, &color, &opacity);
+ dstColorSpace->fromTQColor(color, opacity, dst);
+
+ src += srcPixelSize;
+ dst += dstPixelSize;
+ numPixels--;
+ }
+
+ return true;
+}
+
+
+KisColorAdjustment *KisAbstractColorSpace::createBrightnessContrastAdjustment(TQ_UINT16 *transferValues)
+{
+ if (!m_profile) return 0;
+
+ LPGAMMATABLE transferFunctions[3];
+ transferFunctions[0] = cmsBuildGamma(256, 1.0);
+ transferFunctions[1] = cmsBuildGamma(256, 1.0);
+ transferFunctions[2] = cmsBuildGamma(256, 1.0);
+
+ for(int i =0; i < 256; i++)
+ transferFunctions[0]->GammaTable[i] = transferValues[i];
+
+ KisColorAdjustmentImpl *adj = new KisColorAdjustmentImpl;
+ adj->profiles[1] = cmsCreateLinearizationDeviceLink(icSigLabData, transferFunctions);
+ cmsSetDeviceClass(adj->profiles[1], icSigAbstractClass);
+
+ adj->profiles[0] = m_profile->profile();
+ adj->profiles[2] = m_profile->profile();
+ adj->transform = cmsCreateMultiprofileTransform(adj->profiles, 3, m_cmType, m_cmType, INTENT_PERCEPTUAL, 0);
+ adj->csProfile = m_profile->profile();
+ return adj;
+}
+
+typedef struct {
+ double Saturation;
+
+} BCHSWADJUSTS, *LPBCHSWADJUSTS;
+
+
+static int desaturateSampler(WORD In[], WORD Out[], LPVOID /*Cargo*/)
+{
+ cmsCIELab LabIn, LabOut;
+ cmsCIELCh LChIn, LChOut;
+ //LPBCHSWADJUSTS bchsw = (LPBCHSWADJUSTS) Cargo;
+
+ cmsLabEncoded2Float(&LabIn, In);
+
+ cmsLab2LCh(&LChIn, &LabIn);
+
+ // Do some adjusts on LCh
+ LChOut.L = LChIn.L;
+ LChOut.C = 0;//LChIn.C + bchsw->Saturation;
+ LChOut.h = LChIn.h;
+
+ cmsLCh2Lab(&LabOut, &LChOut);
+
+ // Back to encoded
+ cmsFloat2LabEncoded(Out, &LabOut);
+
+ return TRUE;
+}
+
+KisColorAdjustment *KisAbstractColorSpace::createDesaturateAdjustment()
+{
+ if (!m_profile) return 0;
+
+ KisColorAdjustmentImpl *adj = new KisColorAdjustmentImpl;
+
+ adj->profiles[0] = m_profile->profile();
+ adj->profiles[2] = m_profile->profile();
+ adj->csProfile = m_profile->profile();
+
+ LPLUT Lut;
+ BCHSWADJUSTS bchsw;
+
+ bchsw.Saturation = -25;
+
+ adj->profiles[1] = _cmsCreateProfilePlaceholder();
+ if (!adj->profiles[1]) // can't allocate
+ return NULL;
+
+ cmsSetDeviceClass(adj->profiles[1], icSigAbstractClass);
+ cmsSetColorSpace(adj->profiles[1], icSigLabData);
+ cmsSetPCS(adj->profiles[1], icSigLabData);
+
+ cmsSetRenderingIntent(adj->profiles[1], INTENT_PERCEPTUAL);
+
+ // Creates a LUT with 3D grid only
+ Lut = cmsAllocLUT();
+
+ cmsAlloc3DGrid(Lut, 32, 3, 3);
+
+ if (!cmsSample3DGrid(Lut, desaturateSampler, static_cast<LPVOID>(&bchsw), 0)) {
+ // Shouldn't reach here
+ cmsFreeLUT(Lut);
+ cmsCloseProfile(adj->profiles[1]);
+ return NULL;
+ }
+
+ // Create tags
+
+ cmsAddTag(adj->profiles[1], icSigDeviceMfgDescTag, (LPVOID) "(chalk internal)");
+ cmsAddTag(adj->profiles[1], icSigProfileDescriptionTag, (LPVOID) "chalk saturation abstract profile");
+ cmsAddTag(adj->profiles[1], icSigDeviceModelDescTag, (LPVOID) "saturation built-in");
+
+ cmsAddTag(adj->profiles[1], icSigMediaWhitePointTag, (LPVOID) cmsD50_XYZ());
+
+ cmsAddTag(adj->profiles[1], icSigAToB0Tag, (LPVOID) Lut);
+
+ // LUT is already on virtual profile
+ cmsFreeLUT(Lut);
+
+ adj->transform = cmsCreateMultiprofileTransform(adj->profiles, 3, m_cmType, m_cmType, INTENT_PERCEPTUAL, 0);
+
+ return adj;
+}
+
+KisColorAdjustment *KisAbstractColorSpace::createPerChannelAdjustment(TQ_UINT16 **transferValues)
+{
+ if (!m_profile) return 0;
+
+ LPGAMMATABLE *transferFunctions = new LPGAMMATABLE[nColorChannels()+1];
+
+ for(uint ch=0; ch < nColorChannels(); ch++) {
+ transferFunctions[ch] = cmsBuildGamma(256, 1.0);
+ for(uint i =0; i < 256; i++) {
+ transferFunctions[ch]->GammaTable[i] = transferValues[ch][i];
+ }
+ }
+
+ KisColorAdjustmentImpl *adj = new KisColorAdjustmentImpl;
+ adj->profiles[0] = cmsCreateLinearizationDeviceLink(colorSpaceSignature(), transferFunctions);
+ adj->profiles[1] = NULL;
+ adj->profiles[2] = NULL;
+ adj->csProfile = m_profile->profile();
+ adj->transform = cmsCreateTransform(adj->profiles[0], m_cmType, NULL, m_cmType, INTENT_PERCEPTUAL, 0);
+
+ delete [] transferFunctions;
+
+ return adj;
+}
+
+
+void KisAbstractColorSpace::applyAdjustment(const TQ_UINT8 *src, TQ_UINT8 *dst, KisColorAdjustment *adjustment, TQ_INT32 nPixels)
+{
+ KisColorAdjustmentImpl * adj = dynamic_cast<KisColorAdjustmentImpl*>(adjustment);
+ if (adj)
+ cmsDoTransform(adj->transform, const_cast<TQ_UINT8 *>(src), dst, nPixels);
+}
+
+
+void KisAbstractColorSpace::invertColor(TQ_UINT8 * src, TQ_INT32 nPixels)
+{
+ TQColor c;
+ TQ_UINT8 opacity;
+ TQ_UINT32 psize = pixelSize();
+
+ while (nPixels--)
+ {
+ toTQColor(src, &c, &opacity);
+ c.setRgb(TQ_UINT8_MAX - c.red(), TQ_UINT8_MAX - c.green(), TQ_UINT8_MAX - c.blue());
+ fromTQColor( c, opacity, src);
+
+ src += psize;
+ }
+}
+
+TQ_UINT8 KisAbstractColorSpace::difference(const TQ_UINT8* src1, const TQ_UINT8* src2)
+{
+ if (m_defaultToLab) {
+
+ TQ_UINT8 lab1[8], lab2[8];
+ cmsCIELab labF1, labF2;
+
+ if (getAlpha(src1) == OPACITY_TRANSPARENT || getAlpha(src2) == OPACITY_TRANSPARENT)
+ return (getAlpha(src1) == getAlpha(src2) ? 0 : 255);
+
+ cmsDoTransform( m_defaultToLab, const_cast<TQ_UINT8*>( src1 ), lab1, 1);
+ cmsDoTransform( m_defaultToLab, const_cast<TQ_UINT8*>( src2 ), lab2, 1);
+ cmsLabEncoded2Float(&labF1, (WORD *)lab1);
+ cmsLabEncoded2Float(&labF2, (WORD *)lab2);
+ double diff = cmsDeltaE(&labF1, &labF2);
+ if(diff>255)
+ return 255;
+ else
+ return TQ_INT8(diff);
+ }
+ else {
+ TQColor c1;
+ TQ_UINT8 opacity1;
+ toTQColor(src1, &c1, &opacity1);
+
+ TQColor c2;
+ TQ_UINT8 opacity2;
+ toTQColor(src2, &c2, &opacity2);
+
+ TQ_UINT8 red = abs(c1.red() - c2.red());
+ TQ_UINT8 green = abs(c1.green() - c2.green());
+ TQ_UINT8 blue = abs(c1.blue() - c2.blue());
+ return TQMAX(red, TQMAX(green, blue));
+ }
+}
+
+void KisAbstractColorSpace::mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const
+{
+ TQ_UINT32 totalRed = 0, totalGreen = 0, totalBlue = 0, newAlpha = 0;
+
+ TQColor c;
+ TQ_UINT8 opacity;
+
+ while (nColors--)
+ {
+ // Ugly hack to get around the current constness mess of the colour strategy...
+ const_cast<KisAbstractColorSpace *>(this)->toTQColor(*colors, &c, &opacity);
+
+ TQ_UINT32 alphaTimesWeight = UINT8_MULT(opacity, *weights);
+
+ totalRed += c.red() * alphaTimesWeight;
+ totalGreen += c.green() * alphaTimesWeight;
+ totalBlue += c.blue() * alphaTimesWeight;
+ newAlpha += alphaTimesWeight;
+
+ weights++;
+ colors++;
+ }
+
+ Q_ASSERT(newAlpha <= 255);
+
+ if (newAlpha > 0) {
+ totalRed = UINT8_DIVIDE(totalRed, newAlpha);
+ totalGreen = UINT8_DIVIDE(totalGreen, newAlpha);
+ totalBlue = UINT8_DIVIDE(totalBlue, newAlpha);
+ }
+
+ // Divide by 255.
+ totalRed += 0x80;
+
+ TQ_UINT32 dstRed = ((totalRed >> 8) + totalRed) >> 8;
+ Q_ASSERT(dstRed <= 255);
+
+ totalGreen += 0x80;
+ TQ_UINT32 dstGreen = ((totalGreen >> 8) + totalGreen) >> 8;
+ Q_ASSERT(dstGreen <= 255);
+
+ totalBlue += 0x80;
+ TQ_UINT32 dstBlue = ((totalBlue >> 8) + totalBlue) >> 8;
+ Q_ASSERT(dstBlue <= 255);
+
+ const_cast<KisAbstractColorSpace *>(this)->fromTQColor(TQColor(dstRed, dstGreen, dstBlue), newAlpha, dst);
+}
+
+void KisAbstractColorSpace::convolveColors(TQ_UINT8** colors, TQ_INT32 * kernelValues, KisChannelInfo::enumChannelFlags channelFlags,
+ TQ_UINT8 *dst, TQ_INT32 factor, TQ_INT32 offset, TQ_INT32 nColors) const
+{
+ TQ_INT32 totalRed = 0, totalGreen = 0, totalBlue = 0, totalAlpha = 0;
+
+ TQColor dstColor;
+ TQ_UINT8 dstOpacity;
+
+ const_cast<KisAbstractColorSpace *>(this)->toTQColor(dst, &dstColor, &dstOpacity);
+
+ while (nColors--)
+ {
+ TQ_INT32 weight = *kernelValues;
+
+ if (weight != 0) {
+ TQColor c;
+ TQ_UINT8 opacity;
+ const_cast<KisAbstractColorSpace *>(this)->toTQColor( *colors, &c, &opacity );
+ totalRed += c.red() * weight;
+ totalGreen += c.green() * weight;
+ totalBlue += c.blue() * weight;
+ totalAlpha += opacity * weight;
+ }
+ colors++;
+ kernelValues++;
+ }
+
+
+ if (channelFlags & KisChannelInfo::FLAG_COLOR) {
+ const_cast<KisAbstractColorSpace *>(this)->fromTQColor(TQColor(CLAMP((totalRed / factor) + offset, 0, TQ_UINT8_MAX),
+ CLAMP((totalGreen / factor) + offset, 0, TQ_UINT8_MAX),
+ CLAMP((totalBlue / factor) + offset, 0, TQ_UINT8_MAX)),
+ dstOpacity,
+ dst);
+ }
+ if (channelFlags & KisChannelInfo::FLAG_ALPHA) {
+ const_cast<KisAbstractColorSpace *>(this)->fromTQColor(dstColor, CLAMP((totalAlpha/ factor) + offset, 0, TQ_UINT8_MAX), dst);
+ }
+
+}
+
+void KisAbstractColorSpace::darken(const TQ_UINT8 * src, TQ_UINT8 * dst, TQ_INT32 shade, bool compensate, double compensation, TQ_INT32 nPixels) const
+{
+ if (m_defaultToLab) {
+ TQ_UINT16 * labcache = new TQ_UINT16[nPixels * 4];
+ cmsDoTransform( m_defaultToLab, const_cast<TQ_UINT8*>( src ), reinterpret_cast<TQ_UINT8*>( labcache ), nPixels );
+ for ( int i = 0; i < nPixels * 4; ++i ) {
+ if ( compensate ) {
+ labcache[i] = static_cast<TQ_UINT16>( ( labcache[i] * shade ) / ( compensation * 255 ) );
+ }
+ else {
+ labcache[i] = static_cast<TQ_UINT16>( labcache[i] * shade / 255 );
+ }
+ }
+ cmsDoTransform( m_defaultFromLab, reinterpret_cast<TQ_UINT8*>( labcache ), dst, nPixels );
+
+ // Copy alpha
+ for ( int i = 0; i < nPixels; ++i ) {
+ TQ_UINT8 alpha = getAlpha( src );
+ setAlpha( dst, alpha, 1 );
+ }
+ delete [] labcache;
+ }
+ else {
+
+ TQColor c;
+ TQ_INT32 psize = pixelSize();
+
+ for (int i = 0; i < nPixels; ++i) {
+
+ const_cast<KisAbstractColorSpace *>(this)->toTQColor(src + (i * psize), &c);
+ TQ_INT32 r, g, b;
+
+ if (compensate) {
+ r = static_cast<TQ_INT32>( TQMIN(255, (c.red() * shade) / (compensation * 255)));
+ g = static_cast<TQ_INT32>( TQMIN(255, (c.green() * shade) / (compensation * 255)));
+ b = static_cast<TQ_INT32>( TQMIN(255, (c.blue() * shade) / (compensation * 255)));
+ }
+ else {
+ r = static_cast<TQ_INT32>( TQMIN(255, (c.red() * shade / 255)));
+ g = static_cast<TQ_INT32>( TQMIN(255, (c.green() * shade / 255)));
+ b = static_cast<TQ_INT32>( TQMIN(255, (c.blue() * shade / 255)));
+ }
+ c.setRgb(r, g, b);
+
+ const_cast<KisAbstractColorSpace *>(this)->fromTQColor( c, dst + (i * psize));
+ }
+ }
+}
+
+TQ_UINT8 KisAbstractColorSpace::intensity8(const TQ_UINT8 * src) const
+{
+ TQColor c;
+ TQ_UINT8 opacity;
+ const_cast<KisAbstractColorSpace *>(this)->toTQColor(src, &c, &opacity);
+ return static_cast<TQ_UINT8>((c.red() * 0.30 + c.green() * 0.59 + c.blue() * 0.11) + 0.5);
+
+}
+
+
+KisID KisAbstractColorSpace::mathToolboxID() const
+{
+ return KisID("Basic");
+}
+
+void KisAbstractColorSpace::bitBlt(TQ_UINT8 *dst,
+ TQ_INT32 dststride,
+ KisColorSpace * srcSpace,
+ const TQ_UINT8 *src,
+ TQ_INT32 srcRowStride,
+ const TQ_UINT8 *srcAlphaMask,
+ TQ_INT32 maskRowStride,
+ TQ_UINT8 opacity,
+ TQ_INT32 rows,
+ TQ_INT32 cols,
+ const KisCompositeOp& op)
+{
+ if (rows <= 0 || cols <= 0)
+ return;
+
+ if (this != srcSpace) {
+ TQ_UINT32 len = pixelSize() * rows * cols;
+
+ // If our conversion cache is too small, extend it.
+ if (!m_conversionCache.resize( len, TQGArray::SpeedOptim )) {
+ kdWarning() << "Could not allocate enough memory for the conversion!\n";
+ // XXX: We should do a slow, pixel by pixel bitblt here...
+ abort();
+ }
+
+ for (TQ_INT32 row = 0; row < rows; row++) {
+ srcSpace->convertPixelsTo(src + row * srcRowStride,
+ m_conversionCache.data() + row * cols * pixelSize(), this,
+ cols);
+ }
+
+ // The old srcRowStride is no longer valid because we converted to the current cs
+ srcRowStride = cols * pixelSize();
+
+ bitBlt(dst,
+ dststride,
+ m_conversionCache.data(),
+ srcRowStride,
+ srcAlphaMask,
+ maskRowStride,
+ opacity,
+ rows,
+ cols,
+ op);
+
+ }
+ else {
+ bitBlt(dst,
+ dststride,
+ src,
+ srcRowStride,
+ srcAlphaMask,
+ maskRowStride,
+ opacity,
+ rows,
+ cols,
+ op);
+ }
+}
+
+TQImage KisAbstractColorSpace::convertToTQImage(const TQ_UINT8 *data, TQ_INT32 width, TQ_INT32 height,
+ KisProfile *dstProfile,
+ TQ_INT32 renderingIntent, float /*exposure*/)
+
+{
+ TQImage img = TQImage(width, height, 32, 0, TQImage::LittleEndian);
+ img.setAlphaBuffer( true );
+
+ KisColorSpace * dstCS;
+
+ if (dstProfile)
+ dstCS = m_parent->getColorSpace(KisID("RGBA",""),dstProfile->productName());
+ else
+ dstCS = m_parent->getRGB8();
+
+ if (data)
+ convertPixelsTo(const_cast<TQ_UINT8 *>(data), img.bits(), dstCS, width * height, renderingIntent);
+
+ return img;
+}
+
+
+cmsHTRANSFORM KisAbstractColorSpace::createTransform(KisColorSpace * dstColorSpace,
+ KisProfile * srcProfile,
+ KisProfile * dstProfile,
+ TQ_INT32 renderingIntent)
+{
+ TDEConfig * cfg = TDEGlobal::config();
+ bool bpCompensation = cfg->readBoolEntry("useBlackPointCompensation", false);
+
+ int flags = 0;
+
+ if (bpCompensation) {
+ flags = cmsFLAGS_BLACKPOINTCOMPENSATION;
+ }
+
+ if (dstColorSpace && dstProfile && srcProfile ) {
+ cmsHTRANSFORM tf = cmsCreateTransform(srcProfile->profile(),
+ colorSpaceType(),
+ dstProfile->profile(),
+ dstColorSpace->colorSpaceType(),
+ renderingIntent,
+ flags);
+
+ return tf;
+ }
+ return 0;
+}
+
+void KisAbstractColorSpace::compositeCopy(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 * /*maskRowStart*/, TQ_INT32 /*maskRowStride*/, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity)
+{
+ TQ_UINT8 *dst = dstRowStart;
+ const TQ_UINT8 *src = srcRowStart;
+ TQ_INT32 bytesPerPixel = pixelSize();
+
+ while (rows > 0) {
+ memcpy(dst, src, numColumns * bytesPerPixel);
+
+ if (opacity != OPACITY_OPAQUE) {
+ multiplyAlpha(dst, opacity, numColumns);
+ }
+
+ dst += dstRowStride;
+ src += srcRowStride;
+ --rows;
+ }
+}
+