diff options
Diffstat (limited to 'chalk/chalkcolor/colorspaces')
-rw-r--r-- | chalk/chalkcolor/colorspaces/Makefile.am | 20 | ||||
-rw-r--r-- | chalk/chalkcolor/colorspaces/kis_alpha_colorspace.cc | 296 | ||||
-rw-r--r-- | chalk/chalkcolor/colorspaces/kis_alpha_colorspace.h | 93 | ||||
-rw-r--r-- | chalk/chalkcolor/colorspaces/kis_lab_colorspace.cc | 571 | ||||
-rw-r--r-- | chalk/chalkcolor/colorspaces/kis_lab_colorspace.h | 153 | ||||
-rw-r--r-- | chalk/chalkcolor/colorspaces/kis_xyz_colorspace.cc | 624 | ||||
-rw-r--r-- | chalk/chalkcolor/colorspaces/kis_xyz_colorspace.h | 112 |
7 files changed, 1869 insertions, 0 deletions
diff --git a/chalk/chalkcolor/colorspaces/Makefile.am b/chalk/chalkcolor/colorspaces/Makefile.am new file mode 100644 index 00000000..90f75d29 --- /dev/null +++ b/chalk/chalkcolor/colorspaces/Makefile.am @@ -0,0 +1,20 @@ +INCLUDES = -I$(srcdir)/.. \ + -I$(srcdir)/../../sdk \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +noinst_LTLIBRARIES = libchalkcolorspaces.la + +libchalkcolorspaces_la_SOURCES = \ + kis_alpha_colorspace.cc \ + kis_lab_colorspace.cc + +noinst_HEADERS = \ + kis_alpha_colorspace.h \ + kis_lab_colorspace.h + +libchalkcolorspaces_la_LIBADD = $(OPENEXR_LIBS) + +libchalkcolorspaces_la_METASOURCES = AUTO + + diff --git a/chalk/chalkcolor/colorspaces/kis_alpha_colorspace.cc b/chalk/chalkcolor/colorspaces/kis_alpha_colorspace.cc new file mode 100644 index 00000000..4b54556f --- /dev/null +++ b/chalk/chalkcolor/colorspaces/kis_alpha_colorspace.cc @@ -0,0 +1,296 @@ +/* + * Copyright (c) 2004 Boudewijn Rempt <boud@valdyas.org> + * + * 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 <limits.h> +#include <stdlib.h> + +#include <tqimage.h> + +#include <kdebug.h> +#include <klocale.h> + +#include <config.h> + +#include LCMS_HEADER + +#include "kis_alpha_colorspace.h" +#include "kis_u8_base_colorspace.h" +#include "kis_channelinfo.h" +#include "kis_id.h" +#include "kis_integer_maths.h" + +namespace { + const TQ_UINT8 PIXEL_MASK = 0; +} + +KisAlphaColorSpace::KisAlphaColorSpace(KisColorSpaceFactoryRegistry * tqparent, + KisProfile *p) : + KisU8BaseColorSpace(KisID("ALPHA", i18n("Alpha tqmask")), TYPE_GRAY_8, icSigGrayData, tqparent, p) +{ + m_channels.push_back(new KisChannelInfo(i18n("Alpha"), i18n("A"), 0, KisChannelInfo::ALPHA, KisChannelInfo::UINT8)); + m_alphaPos = 0; +} + +KisAlphaColorSpace::~KisAlphaColorSpace() +{ +} + +void KisAlphaColorSpace::fromTQColor(const TQColor& /*c*/, TQ_UINT8 *dst, KisProfile * /*profile*/) +{ + dst[PIXEL_MASK] = OPACITY_OPAQUE; +} + +void KisAlphaColorSpace::fromTQColor(const TQColor& /*c*/, TQ_UINT8 opacity, TQ_UINT8 *dst, KisProfile * /*profile*/) +{ + dst[PIXEL_MASK] = opacity; +} + +void KisAlphaColorSpace::getAlpha(const TQ_UINT8 *pixel, TQ_UINT8 *alpha) const +{ + *alpha = *pixel; +} + +void KisAlphaColorSpace::toTQColor(const TQ_UINT8 */*src*/, TQColor *c, KisProfile * /*profile*/) +{ + c->setRgb(255, 255, 255); +} + +void KisAlphaColorSpace::toTQColor(const TQ_UINT8 *src, TQColor *c, TQ_UINT8 *opacity, KisProfile * /*profile*/) +{ + c->setRgb(255, 255, 255); + *opacity = src[PIXEL_MASK]; +} + +TQ_UINT8 KisAlphaColorSpace::difference(const TQ_UINT8 *src1, const TQ_UINT8 *src2) +{ + // Arithmetic operands smaller than int are converted to int automatically + return TQABS(src2[PIXEL_MASK] - src1[PIXEL_MASK]); +} + +void KisAlphaColorSpace::mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const +{ + if (nColors > 0) { + TQ_UINT32 total = 0; + + while(nColors) + { + nColors--; + total += *colors[nColors] * weights[nColors]; + } + *dst = total / 255; + } +} + +TQValueVector<KisChannelInfo *> KisAlphaColorSpace::channels() const +{ + return m_channels; +} + +bool KisAlphaColorSpace::convertPixelsTo(const TQ_UINT8 *src, + TQ_UINT8 *dst, KisAbstractColorSpace * dstColorSpace, + TQ_UINT32 numPixels, + TQ_INT32 /*renderingIntent*/) +{ + // No lcms trickery here, we are only a opacity channel + TQ_INT32 size = dstColorSpace->pixelSize(); + + TQ_UINT32 j = 0; + TQ_UINT32 i = 0; + + while ( i < numPixels ) { + + dstColorSpace->fromTQColor(TQt::red, OPACITY_OPAQUE - *(src + i), (dst + j)); + + i += 1; + j += size; + + } + return true; + +} + + +//XXX bitblt of ColorSpaceAlpha does not take tqmask into consideration as this is probably not +// used ever +void KisAlphaColorSpace::bitBlt(TQ_UINT8 *dst, + TQ_INT32 dststride, + const TQ_UINT8 *src, + TQ_INT32 srcRowStride, + const TQ_UINT8 *srcAlphaMask, + TQ_INT32 tqmaskRowStride, + TQ_UINT8 opacity, + TQ_INT32 rows, + TQ_INT32 cols, + const KisCompositeOp& op) +{ + + TQ_UINT8 *d; + const TQ_UINT8 *s; + TQ_INT32 i; + TQ_INT32 linesize; + + if (rows <= 0 || cols <= 0) + return; + switch (op.op()) { + case COMPOSITE_COPY: + compositeCopy(dst, dststride, src, srcRowStride, srcAlphaMask, tqmaskRowStride, rows, cols, opacity); + return; + case COMPOSITE_CLEAR: + linesize = sizeof(TQ_UINT8) * cols; + d = dst; + while (rows-- > 0) { + memset(d, OPACITY_TRANSPARENT, linesize); + d += dststride; + } + return; + case COMPOSITE_ERASE: + while (rows-- > 0) { + d = dst; + s = src; + + for (i = cols; i > 0; i--, d ++, s ++) { + if (d[PIXEL_MASK] < s[PIXEL_MASK]) { + continue; + } + else { + d[PIXEL_MASK] = s[PIXEL_MASK]; + } + + } + + dst += dststride; + src += srcRowStride; + } + return; + case COMPOSITE_SUBTRACT: + while (rows-- > 0) { + d = dst; + s = src; + + for (i = cols; i > 0; i--, d++, s++) { + if (d[PIXEL_MASK] <= s[PIXEL_MASK]) { + d[PIXEL_MASK] = MIN_SELECTED; + } else { + d[PIXEL_MASK] -= s[PIXEL_MASK]; + } + } + + dst += dststride; + src += srcRowStride; + } + return; + case COMPOSITE_ALPHA_DARKEN: + while (rows-- > 0) { + d = dst; + s = src; + for (i = cols; i > 0; i--, d++, s++) { + if (s[PIXEL_MASK] == OPACITY_TRANSPARENT) + continue; + int srcAlpha = (s[PIXEL_MASK] * opacity + UINT8_MAX / 2) / UINT8_MAX; + if (srcAlpha > d[PIXEL_MASK]) + d[PIXEL_MASK] = srcAlpha; + } + dst += dststride; + src += srcRowStride; + } + return; + case COMPOSITE_OVER: + default: + if (opacity == OPACITY_TRANSPARENT) + return; + if (opacity != OPACITY_OPAQUE) { + while (rows-- > 0) { + d = dst; + s = src; + for (i = cols; i > 0; i--, d++, s++) { + if (s[PIXEL_MASK] == OPACITY_TRANSPARENT) + continue; + int srcAlpha = (s[PIXEL_MASK] * opacity + UINT8_MAX / 2) / UINT8_MAX; + d[PIXEL_MASK] = (d[PIXEL_MASK] * (UINT8_MAX - srcAlpha) + srcAlpha * UINT8_MAX + UINT8_MAX / 2) / UINT8_MAX; + } + dst += dststride; + src += srcRowStride; + } + } + else { + while (rows-- > 0) { + d = dst; + s = src; + for (i = cols; i > 0; i--, d++, s++) { + if (s[PIXEL_MASK] == OPACITY_TRANSPARENT) + continue; + if (d[PIXEL_MASK] == OPACITY_TRANSPARENT || s[PIXEL_MASK] == OPACITY_OPAQUE) { + memcpy(d, s, 1); + continue; + } + int srcAlpha = s[PIXEL_MASK]; + d[PIXEL_MASK] = (d[PIXEL_MASK] * (UINT8_MAX - srcAlpha) + srcAlpha * UINT8_MAX + UINT8_MAX / 2) / UINT8_MAX; + } + dst += dststride; + src += srcRowStride; + } + } + + } +} + +KisCompositeOpList KisAlphaColorSpace::userVisiblecompositeOps() const +{ + KisCompositeOpList list; + + list.append(KisCompositeOp(COMPOSITE_OVER)); + + return list; +} + +TQString KisAlphaColorSpace::channelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const +{ + Q_ASSERT(channelIndex < nChannels()); + TQ_UINT32 channelPosition = m_channels[channelIndex]->pos(); + + return TQString().setNum(pixel[channelPosition]); +} + +TQString KisAlphaColorSpace::normalisedChannelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const +{ + Q_ASSERT(channelIndex < nChannels()); + TQ_UINT32 channelPosition = m_channels[channelIndex]->pos(); + + return TQString().setNum(static_cast<float>(pixel[channelPosition]) / UINT8_MAX); +} + + +void KisAlphaColorSpace::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 totalAlpha = 0; + + while (nColors--) + { + TQ_INT32 weight = *kernelValues; + + if (weight != 0) { + totalAlpha += (*colors)[PIXEL_MASK] * weight; + } + colors++; + kernelValues++; + } + + if (channelFlags & KisChannelInfo::FLAG_ALPHA) { + dst[PIXEL_MASK] = CLAMP((totalAlpha/ factor) + offset, 0, TQ_UINT8_MAX); + } +} diff --git a/chalk/chalkcolor/colorspaces/kis_alpha_colorspace.h b/chalk/chalkcolor/colorspaces/kis_alpha_colorspace.h new file mode 100644 index 00000000..dd4f3916 --- /dev/null +++ b/chalk/chalkcolor/colorspaces/kis_alpha_colorspace.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2004 Boudewijn Rempt <boud@valdyas.org> + * + * 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. + */ +#ifndef KIS_COLORSPACE_ALPHA_H_ +#define KIS_COLORSPACE_ALPHA_H_ + +#include <tqcolor.h> + +#include "kis_global.h" +#include "kis_u8_base_colorspace.h" + +/** + * The alpha tqmask is a special color strategy that treats all pixels as + * alpha value with a colour common to the tqmask. The default color is white. + */ +class KisAlphaColorSpace : public KisU8BaseColorSpace { +public: + KisAlphaColorSpace(KisColorSpaceFactoryRegistry * tqparent, + KisProfile *p); + virtual ~KisAlphaColorSpace(); + +public: + virtual bool willDegrade(ColorSpaceIndependence) + { + return false; + }; + + virtual void fromTQColor(const TQColor& c, TQ_UINT8 *dst, KisProfile * profile = 0); + virtual void fromTQColor(const TQColor& c, TQ_UINT8 opacity, TQ_UINT8 *dst, KisProfile * profile = 0); + + virtual void getAlpha(const TQ_UINT8 *pixel, TQ_UINT8 *alpha) const; + + virtual void toTQColor(const TQ_UINT8 *src, TQColor *c, KisProfile * profile = 0); + virtual void toTQColor(const TQ_UINT8 *src, TQColor *c, TQ_UINT8 *opacity, KisProfile * profile = 0); + + virtual TQ_UINT8 difference(const TQ_UINT8 *src1, const TQ_UINT8 *src2); + virtual void mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const; + + virtual TQValueVector<KisChannelInfo *> channels() const; + virtual TQ_UINT32 nChannels() const { return 1; }; + virtual TQ_UINT32 nColorChannels() const { return 0; }; + virtual TQ_UINT32 pixelSize() const { return 1; }; + + virtual TQString channelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const; + virtual TQString normalisedChannelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const; + + virtual void convolveColors(TQ_UINT8** colors, TQ_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, TQ_UINT8 *dst, TQ_INT32 factor, TQ_INT32 offset, TQ_INT32 nColors) const; + +protected: + + /** + * Convert a byte array of srcLen pixels *src to the specified color space + * and put the converted bytes into the prepared byte array *dst. + * + * Returns false if the conversion failed, true if it succeeded + */ + virtual bool convertPixelsTo(const TQ_UINT8 *src, + TQ_UINT8 *dst, KisAbstractColorSpace * dstColorSpace, + TQ_UINT32 numPixels, + TQ_INT32 renderingIntent = INTENT_PERCEPTUAL); + + + + virtual void bitBlt(TQ_UINT8 *dst, + TQ_INT32 dststride, + const TQ_UINT8 *src, + TQ_INT32 srcRowStride, + const TQ_UINT8 *srcAlphaMask, + TQ_INT32 tqmaskRowStride, + TQ_UINT8 opacity, + TQ_INT32 rows, + TQ_INT32 cols, + const KisCompositeOp& op); + + KisCompositeOpList userVisiblecompositeOps() const; + +}; + +#endif // KIS_COLORSPACE_ALPHA_H_ diff --git a/chalk/chalkcolor/colorspaces/kis_lab_colorspace.cc b/chalk/chalkcolor/colorspaces/kis_lab_colorspace.cc new file mode 100644 index 00000000..829b4f27 --- /dev/null +++ b/chalk/chalkcolor/colorspaces/kis_lab_colorspace.cc @@ -0,0 +1,571 @@ + /* + * Copyright (c) 2002 Patrick Julien <freak@codepimps.org> + * Copyright (c) 2004 Boudewijn Rempt <boud@valdyas.org> + * Copyright (c) 2005 Adrian Page <adrian@pagenet.plus.com> + * Copyright (c) 2005 Casper Boemann <cbr@boemann.dk> + * + * 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 <config.h> +#include <limits.h> +#include <stdlib.h> +#include LCMS_HEADER + +#include <tqimage.h> + +#include <kdebug.h> +#include <klocale.h> + +#include "kis_lab_colorspace.h" +#include "kis_color_conversions.h" +#include "kis_integer_maths.h" + +KisLabColorSpace::KisLabColorSpace(KisColorSpaceFactoryRegistry * tqparent, KisProfile *p) + : KisU16BaseColorSpace(KisID("LABA", i18n("L*a*b* (16-bit integer/channel)")), + COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1), + icSigLabData, tqparent, p) + +{ + m_channels.push_back(new KisChannelInfo(i18n("Lightness"), i18n("L"), CHANNEL_L * sizeof(TQ_UINT16), KisChannelInfo::COLOR, KisChannelInfo::UINT16, sizeof(TQ_UINT16), TQColor(100,100,100))); + m_channels.push_back(new KisChannelInfo(i18n("a*"), i18n("a"), CHANNEL_A * sizeof(TQ_UINT16), KisChannelInfo::COLOR, KisChannelInfo::UINT16, sizeof(TQ_UINT16), TQColor(150,150,150))); + m_channels.push_back(new KisChannelInfo(i18n("b*"), i18n("b"), CHANNEL_B * sizeof(TQ_UINT16), KisChannelInfo::COLOR, KisChannelInfo::UINT16, sizeof(TQ_UINT16), TQColor(200,200,200))); + m_channels.push_back(new KisChannelInfo(i18n("Alpha"), i18n("A"), CHANNEL_ALPHA * sizeof(TQ_UINT16), KisChannelInfo::ALPHA, KisChannelInfo::UINT16, sizeof(TQ_UINT16))); + + m_alphaPos = CHANNEL_ALPHA * sizeof(TQ_UINT16); + + init(); +} + +KisLabColorSpace::~KisLabColorSpace() +{ +} + +TQ_UINT8 * KisLabColorSpace::toLabA16(const TQ_UINT8 * data, const TQ_UINT32 nPixels) const +{ + TQ_UINT8 * pixels = new TQ_UINT8[nPixels * pixelSize()]; + memcpy( pixels, data, nPixels * pixelSize() ); + return pixels; +} + +TQ_UINT8 * KisLabColorSpace::fromLabA16(const TQ_UINT8 * labData, const TQ_UINT32 nPixels) const +{ + TQ_UINT8 * pixels = new TQ_UINT8[nPixels * pixelSize()]; + memcpy( pixels, labData, nPixels * pixelSize() ); + return pixels; +} + +TQ_UINT8 KisLabColorSpace::difference(const TQ_UINT8 *src1, const TQ_UINT8 *src2) +{ + cmsCIELab labF1, labF2; + + if (getAlpha(src1) == OPACITY_TRANSPARENT || getAlpha(src2) == OPACITY_TRANSPARENT) + return (getAlpha(src1) == getAlpha(src2) ? 0 : 255); + + cmsLabEncoded2Float(&labF1, (WORD *)src1); + cmsLabEncoded2Float(&labF2, (WORD *)src2); + double diff = cmsDeltaE(&labF1, &labF2); + if(diff>255) + return 255; + else + return TQ_INT8(diff); +} + +void KisLabColorSpace::mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const +{ + TQ_UINT32 totalLightness = 0, totalAlpha = 0; + TQ_UINT32 totala = 0, totalb = 0; + + while (nColors--) + { + const Pixel *color = reinterpret_cast<const Pixel *>( *colors ); + TQ_UINT32 alphaTimesWeight = UINT8_MULT(color->alpha, *weights); + + totalLightness += color->lightness * alphaTimesWeight; + totala += color->a * alphaTimesWeight; + totalb += color->b * alphaTimesWeight; + totalAlpha += alphaTimesWeight; + + weights++; + colors++; + } + + if (totalAlpha > UINT16_MAX) { + totalAlpha = UINT16_MAX; + } + + ((Pixel *)dst)->alpha = totalAlpha; + + if (totalAlpha > 0) { + totalLightness /= totalAlpha; + totala /= totalAlpha; + totalb /= totalAlpha; + } // else the values are already 0 too + + if (totalLightness > MAX_CHANNEL_L) { + totalLightness = MAX_CHANNEL_L; + } + + ((Pixel *)dst)->lightness = totalLightness; + + if (totala > MAX_CHANNEL_AB) { + totala = MAX_CHANNEL_AB; + } + + ((Pixel *)dst)->a = totala; + + if (totalb > MAX_CHANNEL_AB) { + totalb = MAX_CHANNEL_AB; + } + + ((Pixel *)dst)->b = totalb; +} + +void KisLabColorSpace::invertColor(TQ_UINT8 * src, TQ_INT32 nPixels) +{ + TQ_UINT32 psize = pixelSize(); + + while (nPixels--) + { + Pixel * s = reinterpret_cast<Pixel *>( src ); + + s->lightness = MAX_CHANNEL_L - s->lightness; + s->a = MAX_CHANNEL_AB - s->a; + s->b = MAX_CHANNEL_AB - s->b; + + src += psize; + } +} + +void KisLabColorSpace::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 totalL = 0, totalA = 0, totalB = 0, totalAlpha = 0; + + while ( nColors -- ) + { + const Pixel * pixel = reinterpret_cast<const Pixel *>( *colors ); + TQ_INT32 weight = *kernelValues; + if ( weight != 0 ) { + totalL += pixel->lightness * weight; + totalA += pixel->a * weight; + totalB += pixel->b * weight; + totalAlpha += pixel->alpha * weight; + } + colors++; + kernelValues++; + } + + + Pixel * p = reinterpret_cast< Pixel *>( dst ); + + if (channelFlags & KisChannelInfo::FLAG_COLOR) { + p->lightness = CLAMP( ( totalL / factor) + offset, 0, TQ_UINT16_MAX); + p->a = CLAMP( ( totalA / factor) + offset, 0, TQ_UINT16_MAX); + p->b = CLAMP( ( totalB / factor) + offset, 0, TQ_UINT16_MAX); + } + if (channelFlags & KisChannelInfo::FLAG_ALPHA) { + p->alpha = CLAMP((totalAlpha/ factor) + offset, 0, TQ_UINT16_MAX); + } + +} + +void KisLabColorSpace::darken(const TQ_UINT8 * src, TQ_UINT8 * dst, TQ_INT32 shade, bool compensate, double compensation, TQ_INT32 nPixels) const +{ + // XXX: Is the 255 right for u16 colorspaces? + TQ_UINT32 pSize = pixelSize(); + while ( nPixels-- ) { + const Pixel * s = reinterpret_cast<const Pixel*>( src ); + Pixel * d = reinterpret_cast<Pixel*>( dst ); + + if ( compensate ) { + d->lightness = static_cast<TQ_UINT16>( ( s->lightness * shade ) / ( compensation * 255 ) ); + } + else { + d->lightness = static_cast<TQ_UINT16>( s->lightness * shade / 255 ); + } + d->a = s->a; + d->b = s->b; + d->alpha = s->alpha; + + src += pSize; + dst += pSize; + } +} + + +TQValueVector<KisChannelInfo *> KisLabColorSpace::channels() const +{ + return m_channels; +} + +TQ_UINT32 KisLabColorSpace::nChannels() const +{ + return NUM_CHANNELS; +} + +TQ_UINT32 KisLabColorSpace::nColorChannels() const +{ + return NUM_COLOR_CHANNELS; +} + +TQ_UINT32 KisLabColorSpace::pixelSize() const +{ + return sizeof(Pixel); +} + +void KisLabColorSpace::getSingleChannelPixel(TQ_UINT8 *dst, const TQ_UINT8 *src, TQ_UINT32 channelIndex) +{ + if (channelIndex < NUM_CHANNELS) { + + const Pixel *srcPixel = reinterpret_cast<const Pixel *>(src); + Pixel *dstPixel = reinterpret_cast<Pixel *>(dst); + + switch (channelIndex) { + case CHANNEL_L: + dstPixel->lightness = srcPixel->lightness; + dstPixel->a = CHANNEL_AB_ZERO_OFFSET; + dstPixel->b = CHANNEL_AB_ZERO_OFFSET; + dstPixel->alpha = U16_OPACITY_TRANSPARENT; + break; + case CHANNEL_A: + dstPixel->lightness = MAX_CHANNEL_L / 2; + dstPixel->a = srcPixel->a; + dstPixel->b = CHANNEL_AB_ZERO_OFFSET; + dstPixel->alpha = U16_OPACITY_TRANSPARENT; + break; + case CHANNEL_B: + dstPixel->lightness = MAX_CHANNEL_L / 2; + dstPixel->a = CHANNEL_AB_ZERO_OFFSET; + dstPixel->b = srcPixel->b; + dstPixel->alpha = U16_OPACITY_TRANSPARENT; + break; + case CHANNEL_ALPHA: + dstPixel->lightness = MAX_CHANNEL_L / 2; + dstPixel->a = CHANNEL_AB_ZERO_OFFSET; + dstPixel->b = CHANNEL_AB_ZERO_OFFSET; + dstPixel->alpha = srcPixel->alpha; + break; + } + } +} + +void KisLabColorSpace::compositeOver(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + while (rows > 0) { + const Pixel *src = reinterpret_cast<const Pixel *>(srcRowStart); + Pixel *dst = reinterpret_cast<Pixel *>(dstRowStart); + const TQ_UINT8 *tqmask = tqmaskRowStart; + TQ_INT32 columns = numColumns; + + while (columns > 0) { + + TQ_UINT16 srcAlpha = src->alpha; + + // apply the alphatqmask + if (tqmask != 0) { + if (*tqmask != OPACITY_OPAQUE) { + srcAlpha = UINT16_MULT(srcAlpha, *tqmask); + } + tqmask++; + } + + if (srcAlpha != U16_OPACITY_TRANSPARENT) { + + if (opacity != U16_OPACITY_OPAQUE) { + srcAlpha = UINT16_MULT(srcAlpha, opacity); + } + + if (srcAlpha == U16_OPACITY_OPAQUE) { + memcpy(dst, src, sizeof(Pixel)); + } else { + TQ_UINT16 dstAlpha = dst->alpha; + + TQ_UINT16 srcBlend; + + if (dstAlpha == U16_OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + TQ_UINT16 newAlpha = dstAlpha + UINT16_MULT(U16_OPACITY_OPAQUE - dstAlpha, srcAlpha); + dst->alpha = newAlpha; + + if (newAlpha != 0) { + srcBlend = UINT16_DIVIDE(srcAlpha, newAlpha); + } else { + srcBlend = srcAlpha; + } + } + + if (srcBlend == U16_OPACITY_OPAQUE) { + memcpy(dst, src, sizeof(Pixel)); + } else { +/*printf("blend is %d\n", srcBlend); +printf("%d %d %d\n", src->lightness, src->a, src->b); +printf("%d %d %d\n", dst->lightness, dst->a, dst->b); +*/ + dst->lightness = UINT16_BLEND(src->lightness, dst->lightness, srcBlend); + dst->a = UINT16_BLEND(src->a, dst->a, srcBlend); + dst->b = UINT16_BLEND(src->b, dst->b, srcBlend); +//printf("%d %d %d\n", dst->lightness, dst->a, dst->b); + } + } + } + + columns--; + src++; + dst++; + } + + rows--; + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + if(tqmaskRowStart) { + tqmaskRowStart += tqmaskRowStride; + } + } +} + +void KisLabColorSpace::compositeErase(TQ_UINT8 *dst, + TQ_INT32 dstRowSize, + const TQ_UINT8 *src, + TQ_INT32 srcRowSize, + const TQ_UINT8 *srcAlphaMask, + TQ_INT32 tqmaskRowStride, + TQ_INT32 rows, + TQ_INT32 cols, + TQ_UINT16 /*opacity*/) +{ + while (rows-- > 0) + { + const Pixel *s = reinterpret_cast<const Pixel *>(src); + Pixel *d = reinterpret_cast<Pixel *>(dst); + const TQ_UINT8 *tqmask = srcAlphaMask; + + for (TQ_INT32 i = cols; i > 0; i--, s++, d++) + { + TQ_UINT16 srcAlpha = s->alpha; + + // apply the alphatqmask + if (tqmask != 0) { + TQ_UINT8 U8_tqmask = *tqmask; + + if (U8_tqmask != OPACITY_OPAQUE) { + srcAlpha = UINT16_BLEND(srcAlpha, U16_OPACITY_OPAQUE, UINT8_TO_UINT16(U8_tqmask)); + } + tqmask++; + } + d->alpha = UINT16_MULT(srcAlpha, d->alpha); + } + + dst += dstRowSize; + src += srcRowSize; + if(srcAlphaMask) { + srcAlphaMask += tqmaskRowStride; + } + } +} + +void KisLabColorSpace::bitBlt(TQ_UINT8 *dst, + TQ_INT32 dstRowStride, + const TQ_UINT8 *src, + TQ_INT32 srcRowStride, + const TQ_UINT8 *tqmask, + TQ_INT32 tqmaskRowStride, + TQ_UINT8 U8_opacity, + TQ_INT32 rows, + TQ_INT32 cols, + const KisCompositeOp& op) +{ + TQ_UINT16 opacity = UINT8_TO_UINT16(U8_opacity); + + switch (op.op()) { + case COMPOSITE_UNDEF: + // Undefined == no composition + break; + case COMPOSITE_OVER: + compositeOver(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_IN: + //compositeIn(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_OUT: + //compositeOut(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_ATOP: + //compositeAtop(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_XOR: + //compositeXor(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_PLUS: + //compositePlus(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_MINUS: + //compositeMinus(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_ADD: + //compositeAdd(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_SUBTRACT: + //compositeSubtract(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_DIFF: + //compositeDiff(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_MULT: + //compositeMultiply(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_DIVIDE: + //compositeDivide(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_BUMPMAP: + //compositeBumpmap(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY: + compositeCopy(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, U8_opacity); + break; + case COMPOSITE_COPY_RED: + //compositeCopyRed(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY_GREEN: + //compositeCopyGreen(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY_BLUE: + //compositeCopyBlue(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY_OPACITY: + //compositeCopyOpacity(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_CLEAR: + //compositeClear(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_DISSOLVE: + //compositeDissolve(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_DISPLACE: + //compositeDisplace(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; +#if 0 + case COMPOSITE_MODULATE: + compositeModulate(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_THRESHOLD: + compositeThreshold(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; +#endif + case COMPOSITE_NO: + // No composition. + break; + case COMPOSITE_DARKEN: + //compositeDarken(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_LIGHTEN: + //compositeLighten(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_HUE: + //compositeHue(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_SATURATION: + //compositeSaturation(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_VALUE: + //compositeValue(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_COLOR: + //compositeColor(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_COLORIZE: + //compositeColorize(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_LUMINIZE: + //compositeLuminize(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_SCREEN: + //compositeScreen(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_OVERLAY: + //compositeOverlay(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ERASE: + compositeErase(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_DODGE: + //compositeDodge(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_BURN: + //compositeBurn(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ALPHA_DARKEN: + abstractCompositeAlphaDarken<TQ_UINT16, U16Mult, Uint8ToU16, U16OpacityTest, + CHANNEL_ALPHA, NUM_COLOR_CHANNELS, NUM_CHANNELS>( + dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, + rows, cols, opacity, U16Mult(), Uint8ToU16(), U16OpacityTest()); + break; + default: + break; + } +} + +KisCompositeOpList KisLabColorSpace::userVisiblecompositeOps() const +{ + KisCompositeOpList list; + + list.append(KisCompositeOp(COMPOSITE_OVER)); + list.append(KisCompositeOp(COMPOSITE_ALPHA_DARKEN)); + + return list; +} + +TQString KisLabColorSpace::channelValueText(const TQ_UINT8 *U8_pixel, TQ_UINT32 channelIndex) const +{ + const Pixel *pix = reinterpret_cast<const Pixel *>(U8_pixel); + Q_ASSERT(channelIndex < nChannels()); + switch(channelIndex) + { + case CHANNEL_L: + return TQString().setNum(pix->lightness); + case CHANNEL_A: + return TQString().setNum(pix->a); + case CHANNEL_B: + return TQString().setNum(pix->b); + case CHANNEL_ALPHA: + return TQString().setNum(pix->alpha); + default: + return TQString("Error"); + } +} + +TQString KisLabColorSpace::normalisedChannelValueText(const TQ_UINT8 *U8_pixel, TQ_UINT32 channelIndex) const +{ + const Pixel *pix = reinterpret_cast<const Pixel *>(U8_pixel); + Q_ASSERT(channelIndex < nChannels()); + + // These convert from lcms encoded format to standard ranges. + + switch(channelIndex) + { + case CHANNEL_L: + return TQString().setNum(100.0 * static_cast<float>(pix->lightness) / MAX_CHANNEL_L); + case CHANNEL_A: + return TQString().setNum(100.0 * ((static_cast<float>(pix->a) - CHANNEL_AB_ZERO_OFFSET) / MAX_CHANNEL_AB)); + case CHANNEL_B: + return TQString().setNum(100.0 * ((static_cast<float>(pix->b) - CHANNEL_AB_ZERO_OFFSET) / MAX_CHANNEL_AB)); + case CHANNEL_ALPHA: + return TQString().setNum(100.0 * static_cast<float>(pix->alpha) / UINT16_MAX); + default: + return TQString("Error"); + } +} + diff --git a/chalk/chalkcolor/colorspaces/kis_lab_colorspace.h b/chalk/chalkcolor/colorspaces/kis_lab_colorspace.h new file mode 100644 index 00000000..eeab55cf --- /dev/null +++ b/chalk/chalkcolor/colorspaces/kis_lab_colorspace.h @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2002 Patrick Julien <freak@codepimps.org> + * Copyright (c) 2005 Adrian Page <adrian@pagenet.plus.com> + * + * 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. + */ +#ifndef KIS_STRATEGY_COLORSPACE_LAB_H_ +#define KIS_STRATEGY_COLORSPACE_LAB_H_ + +#include <tqcolor.h> + +#include <klocale.h> + +#include "kis_global.h" +#include "kis_integer_maths.h" +#include "kis_u16_base_colorspace.h" + +class KisLabColorSpace : public KisU16BaseColorSpace { +public: + KisLabColorSpace(KisColorSpaceFactoryRegistry * tqparent, KisProfile *p); + virtual ~KisLabColorSpace(); + +public: + + /** + * Return a COPY of the provided data. This method is provided to provide consistency, + * but you really don't want to be calling it. + */ + virtual TQ_UINT8 * toLabA16(const TQ_UINT8 * data, const TQ_UINT32 nPixels) const; + + /** + * Return a COPY of the provided data. This method is provided for consistency, + * but you really don't want to call it. + */ + virtual TQ_UINT8 * fromLabA16(const TQ_UINT8 * labData, const TQ_UINT32 nPixels) const; + + + + virtual bool willDegrade(ColorSpaceIndependence independence) + { + if (independence == TO_RGBA8) + return true; + else + return false; + }; + + virtual TQValueVector<KisChannelInfo *> channels() const; + virtual TQ_UINT32 nChannels() const; + virtual TQ_UINT32 nColorChannels() const; + virtual TQ_UINT32 pixelSize() const; + + virtual TQString channelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const; + virtual TQString normalisedChannelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const; + virtual void getSingleChannelPixel(TQ_UINT8 *dstPixel, const TQ_UINT8 *srcPixel, TQ_UINT32 channelIndex); + + virtual TQ_UINT8 difference(const TQ_UINT8 *src1, const TQ_UINT8 *src2); + virtual void mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const; + virtual void invertColor(TQ_UINT8 * src, TQ_INT32 nPixels); + virtual void convolveColors(TQ_UINT8** colors, TQ_INT32 * kernelValues, KisChannelInfo::enumChannelFlags channelFlags, TQ_UINT8 *dst, TQ_INT32 factor, TQ_INT32 offset, TQ_INT32 nColors) const; + + virtual void darken(const TQ_UINT8 * src, TQ_UINT8 * dst, TQ_INT32 shade, bool compensate, double compensation, TQ_INT32 nPixels) const; + + virtual KisCompositeOpList userVisiblecompositeOps() const; + +protected: + + virtual void bitBlt(TQ_UINT8 *dst, + TQ_INT32 dstRowStride, + const TQ_UINT8 *src, + TQ_INT32 srcRowStride, + const TQ_UINT8 *srcAlphaMask, + TQ_INT32 tqmaskRowStride, + TQ_UINT8 opacity, + TQ_INT32 rows, + TQ_INT32 cols, + const KisCompositeOp& op); + + void compositeOver(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); +/* + void compositeMultiply(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeDivide(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeScreen(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeOverlay(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeDodge(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeBurn(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeDarken(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeLighten(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeHue(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeSaturation(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeValue(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeColor(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); +*/ + void compositeErase(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + +private: + struct Pixel { + TQ_UINT16 lightness; + TQ_UINT16 a; + TQ_UINT16 b; + TQ_UINT16 alpha; + }; + static const TQ_UINT16 U16_OPACITY_OPAQUE = UINT16_MAX; + static const TQ_UINT16 U16_OPACITY_TRANSPARENT = UINT16_MIN; + + static const TQ_UINT32 NUM_CHANNELS = 4; + static const TQ_UINT32 NUM_COLOR_CHANNELS = 3; + + static const TQ_UINT32 CHANNEL_L = 0; + static const TQ_UINT32 CHANNEL_A = 1; + static const TQ_UINT32 CHANNEL_B = 2; + static const TQ_UINT32 CHANNEL_ALPHA = 3; + + static const TQ_UINT32 MAX_CHANNEL_L = 0xff00; + static const TQ_UINT32 MAX_CHANNEL_AB = 0xffff; + static const TQ_UINT32 CHANNEL_AB_ZERO_OFFSET = 0x8000; + + friend class KisLabColorSpaceTester; +}; + +class KisLabColorSpaceFactory : public KisColorSpaceFactory +{ +public: + /** + * Chalk definition for use in .kra files and internally: unchanging name + + * i18n'able description. + */ + virtual KisID id() const { return KisID("LABA", i18n("L*a*b* (16-bit integer/channel)")); }; + + /** + * lcms colorspace type definition. + */ + virtual TQ_UINT32 colorSpaceType() { return (COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)); }; + + virtual icColorSpaceSignature colorSpaceSignature() { return icSigLabData; }; + + virtual KisColorSpace *createColorSpace(KisColorSpaceFactoryRegistry * tqparent, KisProfile *p) { return new KisLabColorSpace(tqparent, p); }; + + virtual TQString defaultProfile() { return "Lab built-in - (lcms internal)"; }; +}; + +#endif // KIS_STRATEGY_COLORSPACE_LAB_H_ diff --git a/chalk/chalkcolor/colorspaces/kis_xyz_colorspace.cc b/chalk/chalkcolor/colorspaces/kis_xyz_colorspace.cc new file mode 100644 index 00000000..98ccead0 --- /dev/null +++ b/chalk/chalkcolor/colorspaces/kis_xyz_colorspace.cc @@ -0,0 +1,624 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt <boud@valdyas.org> + * + * 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 <limits.h> +#include <stdlib.h> + +#include <config.h> +#include LCMS_HEADER + +#include <tqimage.h> + +#include <klocale.h> +#include <kdebug.h> + +#include "kis_abstract_colorspace.h" +#include "kis_u16_base_colorspace.h" +#include "kis_xyz_colorspace.h" +#include "kis_integer_maths.h" + +#define downscale(quantum) (quantum) //((unsigned char) ((quantum)/257UL)) +#define upscale(value) (value) // ((TQ_UINT8) (257UL*(value))) + +// XXX: Maybe use TYPE_XYZ_DBL for an extra stimulating performance hit? People shouldn't depend +// on this fallback... + +KisXyzColorSpace::KisXyzColorSpace(KisColorSpaceFactoryRegistry * tqparent, + KisProfile *p) : + KisU16BaseColorSpace(KisID("XYZA", i18n("XYZ/Alpha")), (COLORSPACE_SH(PT_XYZ)|CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)), icSigCmykData, tqparent, p) +{ + m_channels.push_back(new KisChannelInfo(i18n("X"), i18n("X"), 0, KisChannelInfo::COLOR, KisChannelInfo::UINT8)); + m_channels.push_back(new KisChannelInfo(i18n("Y"), i18n("Y"), 1, KisChannelInfo::COLOR, KisChannelInfo::UINT8)); + m_channels.push_back(new KisChannelInfo(i18n("Z"), i18n("Z"), 2, KisChannelInfo::COLOR, KisChannelInfo::UINT8)); + m_channels.push_back(new KisChannelInfo(i18n("Alpha"), i18n("A"), 4, KisChannelInfo::ALPHA, KisChannelInfo::UINT8)); + + m_alphaPos = PIXEL_ALPHA * sizeof(TQ_UINT16); + + init(); +} + + +KisXyzColorSpace::~KisXyzColorSpace() +{ +} + + +TQValueVector<KisChannelInfo *> KisXyzColorSpace::channels() const +{ + return m_channels; +} + +TQ_UINT32 KisXyzColorSpace::nChannels() const +{ + return xyz::MAX_CHANNEL_XYZA; +} + +TQ_UINT32 KisXyzColorSpace::nColorChannels() const +{ + return xyz::MAX_CHANNEL_XYZ; +} + +TQ_UINT32 KisXyzColorSpace::pixelSize() const +{ + return xyz::MAX_CHANNEL_XYZA * sizeof(TQ_UINT16); +} + +KisColorAdjustment * KisXyzColorSpace::createBrightnessContrastAdjustment(TQ_UINT16 *transferValues) +{ + return 0; +} + +void KisXyzColorSpace::applyAdjustment(const TQ_UINT8 *src, TQ_UINT8 *dst, KisColorAdjustment *, TQ_INT32 nPixels) +{ +} + +void KisXyzColorSpace::invertColor(TQ_UINT8 * src, TQ_INT32 nPixels) +{ + TQ_INT32 pSize = pixelSize(); + + while (nPixels--) + { + TQ_UINT16 * p = reinterpret_cast<TQ_UINT16 *>(src); + p[PIXEL_X] = UINT16_MAX - p[PIXEL_X]; + p[PIXEL_Y] = UINT16_MAX - p[PIXEL_Y]; + p[PIXEL_Z] = UINT16_MAX - p[PIXEL_Z]; + src += pSize; + } +} + +void KisXyzColorSpace::mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const +{ +} + +void KisXyzColorSpace::convolveColors(TQ_UINT8** colors, TQ_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, TQ_UINT8 *dst, TQ_INT32 factor, TQ_INT32 offset, TQ_INT32 nPixels) const +{ +} + +void KisXyzColorSpace::darken(const TQ_UINT8 * src, TQ_UINT8 * dst, TQ_INT32 shade, bool compensate, double compensation, TQ_INT32 nPixels) const +{ +} + +TQ_UINT8 KisXyzColorSpace::intensity8(const TQ_UINT8 * src) const +{ + return 0; +} + +void KisXyzColorSpace::compositeOver(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + while (rows > 0) { + + const TQ_UINT16 *src = reinterpret_cast<const TQ_UINT16 *>(srcRowStart); + TQ_UINT16 *dst = reinterpret_cast<TQ_UINT16 *>(dstRowStart); + const TQ_UINT8 *tqmask = tqmaskRowStart; + TQ_INT32 columns = numColumns; + + while (columns > 0) { + + TQ_UINT16 srcAlpha = src[PIXEL_ALPHA]; + + // apply the alphatqmask + if (tqmask != 0) { + TQ_UINT8 U8_tqmask = *tqmask; + + if (U8_tqmask != OPACITY_OPAQUE) { + srcAlpha = UINT16_MULT(srcAlpha, UINT8_TO_UINT16(U8_tqmask)); + } + tqmask++; + } + + if (srcAlpha != U16_OPACITY_TRANSPARENT) { + + if (opacity != U16_OPACITY_OPAQUE) { + srcAlpha = UINT16_MULT(srcAlpha, opacity); + } + + if (srcAlpha == U16_OPACITY_OPAQUE) { + memcpy(dst, src, xyz::MAX_CHANNEL_XYZA * sizeof(TQ_UINT16)); + } else { + TQ_UINT16 dstAlpha = dst[PIXEL_ALPHA]; + + TQ_UINT16 srcBlend; + + if (dstAlpha == U16_OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + TQ_UINT16 newAlpha = dstAlpha + UINT16_MULT(U16_OPACITY_OPAQUE - dstAlpha, srcAlpha); + dst[PIXEL_ALPHA] = newAlpha; + + if (newAlpha != 0) { + srcBlend = UINT16_DIVIDE(srcAlpha, newAlpha); + } else { + srcBlend = srcAlpha; + } + } + + if (srcBlend == U16_OPACITY_OPAQUE) { + memcpy(dst, src, xyz::MAX_CHANNEL_XYZ * sizeof(TQ_UINT16)); + } else { + dst[PIXEL_X] = UINT16_BLEND(src[PIXEL_X], dst[PIXEL_X], srcBlend); + dst[PIXEL_Y] = UINT16_BLEND(src[PIXEL_Y], dst[PIXEL_Y], srcBlend); + dst[PIXEL_Z] = UINT16_BLEND(src[PIXEL_Z], dst[PIXEL_Z], srcBlend); + } + } + } + + columns--; + src += xyz::MAX_CHANNEL_XYZA; + dst += xyz::MAX_CHANNEL_XYZA; + } + + rows--; + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + if(tqmaskRowStart) { + tqmaskRowStart += tqmaskRowStride; + } + } +} + +#define COMMON_COMPOSITE_OP_PROLOG() \ + while (rows > 0) { \ + \ + const TQ_UINT16 *src = reinterpret_cast<const TQ_UINT16 *>(srcRowStart); \ + TQ_UINT16 *dst = reinterpret_cast<TQ_UINT16 *>(dstRowStart); \ + TQ_INT32 columns = numColumns; \ + const TQ_UINT8 *tqmask = tqmaskRowStart; \ + \ + while (columns > 0) { \ + \ + TQ_UINT16 srcAlpha = src[PIXEL_ALPHA]; \ + TQ_UINT16 dstAlpha = dst[PIXEL_ALPHA]; \ + \ + srcAlpha = TQMIN(srcAlpha, dstAlpha); \ + \ + if (tqmask != 0) { \ + TQ_UINT8 U8_tqmask = *tqmask; \ + \ + if (U8_tqmask != OPACITY_OPAQUE) { \ + srcAlpha = UINT16_MULT(srcAlpha, UINT8_TO_UINT16(U8_tqmask)); \ + } \ + tqmask++; \ + } \ + \ + if (srcAlpha != U16_OPACITY_TRANSPARENT) { \ + \ + if (opacity != U16_OPACITY_OPAQUE) { \ + srcAlpha = UINT16_MULT(srcAlpha, opacity); \ + } \ + \ + TQ_UINT16 srcBlend; \ + \ + if (dstAlpha == U16_OPACITY_OPAQUE) { \ + srcBlend = srcAlpha; \ + } else { \ + TQ_UINT16 newAlpha = dstAlpha + UINT16_MULT(U16_OPACITY_OPAQUE - dstAlpha, srcAlpha); \ + dst[PIXEL_ALPHA] = newAlpha; \ + \ + if (newAlpha != 0) { \ + srcBlend = UINT16_DIVIDE(srcAlpha, newAlpha); \ + } else { \ + srcBlend = srcAlpha; \ + } \ + } + +#define COMMON_COMPOSITE_OP_EPILOG() \ + } \ + \ + columns--; \ + src += xyz::MAX_CHANNEL_XYZA; \ + dst += xyz::MAX_CHANNEL_XYZA; \ + } \ + \ + rows--; \ + srcRowStart += srcRowStride; \ + dstRowStart += dstRowStride; \ + if(tqmaskRowStart) { \ + tqmaskRowStart += tqmaskRowStride; \ + } \ + } + +void KisXyzColorSpace::compositeMultiply(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + + for (int channel = 0; channel < xyz::MAX_CHANNEL_XYZ; channel++) { + TQ_UINT16 srcColor = src[channel]; + TQ_UINT16 dstColor = dst[channel]; + + srcColor = UINT16_MULT(srcColor, dstColor); + + dst[channel] = UINT16_BLEND(srcColor, dstColor, srcBlend); + + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisXyzColorSpace::compositeDivide(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < xyz::MAX_CHANNEL_XYZ; channel++) { + + TQ_UINT16 srcColor = src[channel]; + TQ_UINT16 dstColor = dst[channel]; + + srcColor = TQMIN((dstColor * (UINT16_MAX + 1u) + (srcColor / 2u)) / (1u + srcColor), UINT16_MAX); + + TQ_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisXyzColorSpace::compositeScreen(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < xyz::MAX_CHANNEL_XYZ; channel++) { + + TQ_UINT16 srcColor = src[channel]; + TQ_UINT16 dstColor = dst[channel]; + + srcColor = UINT16_MAX - UINT16_MULT(UINT16_MAX - dstColor, UINT16_MAX - srcColor); + + TQ_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisXyzColorSpace::compositeOverlay(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < xyz::MAX_CHANNEL_XYZ; channel++) { + + TQ_UINT16 srcColor = src[channel]; + TQ_UINT16 dstColor = dst[channel]; + + srcColor = UINT16_MULT(dstColor, dstColor + 2u * UINT16_MULT(srcColor, UINT16_MAX - dstColor)); + + TQ_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisXyzColorSpace::compositeDodge(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < xyz::MAX_CHANNEL_XYZ; channel++) { + + TQ_UINT16 srcColor = src[channel]; + TQ_UINT16 dstColor = dst[channel]; + + srcColor = TQMIN((dstColor * (UINT16_MAX + 1u)) / (UINT16_MAX + 1u - srcColor), UINT16_MAX); + + TQ_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisXyzColorSpace::compositeBurn(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < xyz::MAX_CHANNEL_XYZ; channel++) { + + TQ_UINT16 srcColor = src[channel]; + TQ_UINT16 dstColor = dst[channel]; + + srcColor = TQMIN(((UINT16_MAX - dstColor) * (UINT16_MAX + 1u)) / (srcColor + 1u), UINT16_MAX); + srcColor = CLAMP(UINT16_MAX - srcColor, 0u, UINT16_MAX); + + TQ_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisXyzColorSpace::compositeDarken(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < xyz::MAX_CHANNEL_XYZ; channel++) { + + TQ_UINT16 srcColor = src[channel]; + TQ_UINT16 dstColor = dst[channel]; + + srcColor = TQMIN(srcColor, dstColor); + + TQ_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisXyzColorSpace::compositeLighten(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < xyz::MAX_CHANNEL_XYZ; channel++) { + + TQ_UINT16 srcColor = src[channel]; + TQ_UINT16 dstColor = dst[channel]; + + srcColor = TQMAX(srcColor, dstColor); + + TQ_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + + + +void KisXyzColorSpace::compositeErase(TQ_UINT8 *dst, + TQ_INT32 dstRowSize, + const TQ_UINT8 *src, + TQ_INT32 srcRowSize, + const TQ_UINT8 *srcAlphaMask, + TQ_INT32 tqmaskRowStride, + TQ_INT32 rows, + TQ_INT32 cols, + TQ_UINT16 /*opacity*/) +{ + while (rows-- > 0) + { + const Pixel *s = reinterpret_cast<const Pixel *>(src); + Pixel *d = reinterpret_cast<Pixel *>(dst); + const TQ_UINT8 *tqmask = srcAlphaMask; + + for (TQ_INT32 i = cols; i > 0; i--, s++, d++) + { + TQ_UINT16 srcAlpha = s -> alpha; + + // apply the alphatqmask + if (tqmask != 0) { + TQ_UINT8 U8_tqmask = *tqmask; + + if (U8_tqmask != OPACITY_OPAQUE) { + srcAlpha = UINT16_BLEND(srcAlpha, U16_OPACITY_OPAQUE, UINT8_TO_UINT16(U8_tqmask)); + } + tqmask++; + } + d -> alpha = UINT16_MULT(srcAlpha, d -> alpha); + } + + dst += dstRowSize; + src += srcRowSize; + if(srcAlphaMask) { + srcAlphaMask += tqmaskRowStride; + } + } +} + +void KisXyzColorSpace::bitBlt(TQ_UINT8 *dst, + TQ_INT32 dstRowStride, + const TQ_UINT8 *src, + TQ_INT32 srcRowStride, + const TQ_UINT8 *tqmask, + TQ_INT32 tqmaskRowStride, + TQ_UINT8 U8_opacity, + TQ_INT32 rows, + TQ_INT32 cols, + const KisCompositeOp& op) +{ + TQ_UINT16 opacity = UINT8_TO_UINT16(U8_opacity); + + switch (op.op()) { + case COMPOSITE_UNDEF: + // Undefined == no composition + break; + case COMPOSITE_OVER: + compositeOver(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_IN: + //compositeIn(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + case COMPOSITE_OUT: + //compositeOut(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_ATOP: + //compositeAtop(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_XOR: + //compositeXor(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_PLUS: + //compositePlus(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_MINUS: + //compositeMinus(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_ADD: + //compositeAdd(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_SUBTRACT: + //compositeSubtract(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_DIFF: + //compositeDiff(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_MULT: + compositeMultiply(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_DIVIDE: + compositeDivide(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_BUMPMAP: + //compositeBumpmap(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY: + compositeCopy(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, U8_opacity); + break; + case COMPOSITE_COPY_RED: + //compositeCopyRed(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY_GREEN: + //compositeCopyGreen(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY_BLUE: + //compositeCopyBlue(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY_OPACITY: + //compositeCopyOpacity(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_CLEAR: + //compositeClear(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_DISSOLVE: + //compositeDissolve(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_DISPLACE: + //compositeDisplace(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; +#if 0 + case COMPOSITE_MODULATE: + compositeModulate(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_THRESHOLD: + compositeThreshold(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; +#endif + case COMPOSITE_NO: + // No composition. + break; + case COMPOSITE_DARKEN: + compositeDarken(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_LIGHTEN: + compositeLighten(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_HUE: + //compositeHue(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_SATURATION: + //compositeSaturation(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_VALUE: + //compositeValue(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_COLOR: + //compositeColor(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_COLORIZE: + //compositeColorize(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_LUMINIZE: + //compositeLuminize(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_SCREEN: + compositeScreen(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_OVERLAY: + compositeOverlay(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ERASE: + compositeErase(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_DODGE: + compositeDodge(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_BURN: + compositeBurn(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ALPHA_DARKEN: + abstractCompositeAlphaDarken<TQ_UINT16, U16Mult, Uint8ToU16, U16OpacityTest, + PIXEL_ALPHA, xyz::MAX_CHANNEL_XYZ, xyz::MAX_CHANNEL_XYZA>( + dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, + rows, cols, opacity, U16Mult(), Uint8ToU16(), U16OpacityTest()); + break; + default: + break; + } +} + +KisCompositeOpList KisXyzColorSpace::userVisiblecompositeOps() const +{ + KisCompositeOpList list; + + list.append(KisCompositeOp(COMPOSITE_OVER)); + list.append(KisCompositeOp(COMPOSITE_ALPHA_DARKEN)); + list.append(KisCompositeOp(COMPOSITE_MULT)); + list.append(KisCompositeOp(COMPOSITE_BURN)); + list.append(KisCompositeOp(COMPOSITE_DODGE)); + list.append(KisCompositeOp(COMPOSITE_DIVIDE)); + list.append(KisCompositeOp(COMPOSITE_SCREEN)); + list.append(KisCompositeOp(COMPOSITE_OVERLAY)); + list.append(KisCompositeOp(COMPOSITE_DARKEN)); + list.append(KisCompositeOp(COMPOSITE_LIGHTEN)); + + return list; +} + + diff --git a/chalk/chalkcolor/colorspaces/kis_xyz_colorspace.h b/chalk/chalkcolor/colorspaces/kis_xyz_colorspace.h new file mode 100644 index 00000000..2f7c3efd --- /dev/null +++ b/chalk/chalkcolor/colorspaces/kis_xyz_colorspace.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt (boud@valdyas.org) + * + * 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. + */ +#ifndef KIS__COLORSPACE_XYZ_H_ +#define KIS__COLORSPACE_XYZ_H_ + +#include <tqcolor.h> + +#include "kis_global.h" +#include "kis_integer_maths.h" +#include "kis_u16_base_colorspace.h" + +namespace xyz { + const TQ_INT32 MAX_CHANNEL_XYZ = 3; + const TQ_INT32 MAX_CHANNEL_XYZA = 4; +} + + + +class KisXyzColorSpace : public KisU16BaseColorSpace { + +public: + + struct Pixel { + TQ_UINT16 X; + TQ_UINT16 Y; + TQ_UINT16 Z; + TQ_UINT16 alpha; + }; + +public: + KisXyzColorSpace(KisColorSpaceFactoryRegistry * tqparent, + KisProfile *p); + virtual ~KisXyzColorSpace(); + + virtual bool willDegrade(ColorSpaceIndependence independence) + { + if (independence == TO_RGBA8) + return true; + else + return false; + }; +public: + // Pixel manipulation + virtual KisColorAdjustment *createBrightnessContrastAdjustment(TQ_UINT16 *transferValues); + virtual void applyAdjustment(const TQ_UINT8 *src, TQ_UINT8 *dst, KisColorAdjustment *, TQ_INT32 nPixels); + virtual void invertColor(TQ_UINT8 * src, TQ_INT32 nPixels); + virtual void mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const; + virtual void convolveColors(TQ_UINT8** colors, TQ_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, TQ_UINT8 *dst, TQ_INT32 factor, TQ_INT32 offset, TQ_INT32 nPixels) const; + virtual void darken(const TQ_UINT8 * src, TQ_UINT8 * dst, TQ_INT32 shade, bool compensate, double compensation, TQ_INT32 nPixels) const; + virtual TQ_UINT8 intensity8(const TQ_UINT8 * src) const; + + // Information about the colorstrategy + virtual TQValueVector<KisChannelInfo *> channels() const; + virtual TQ_UINT32 nChannels() const; + virtual TQ_UINT32 nColorChannels() const; + virtual TQ_UINT32 pixelSize() const; + + + // Composition + + virtual void bitBlt(TQ_UINT8 *dst, + TQ_INT32 dststride, + const TQ_UINT8 *src, + TQ_INT32 srcRowStride, + const TQ_UINT8 *srcAlphaMask, + TQ_INT32 tqmaskRowStride, + TQ_UINT8 opacity, + TQ_INT32 rows, + TQ_INT32 cols, + const KisCompositeOp& op); + + KisCompositeOpList userVisiblecompositeOps() const; + +protected: + void compositeOver(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeMultiply(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeDivide(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeScreen(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeOverlay(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeDodge(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeBurn(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeDarken(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeLighten(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeErase(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + +private: + + static const TQ_UINT8 PIXEL_X = 0; + static const TQ_UINT8 PIXEL_Y = 1; + static const TQ_UINT8 PIXEL_Z = 2; + static const TQ_UINT8 PIXEL_ALPHA = 3; + + TQ_UINT8 * m_qcolordata; // A small buffer for conversion from and to qcolor. + +}; + +#endif // KIS__COLORSPACE_XYZ_H_ |