diff options
Diffstat (limited to 'chalk/chalkcolor/kis_abstract_colorspace.cpp')
-rw-r--r-- | chalk/chalkcolor/kis_abstract_colorspace.cpp | 762 |
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; + } +} + |