diff --git a/libs/pigment/KoColorSpaceAbstract.h b/libs/pigment/KoColorSpaceAbstract.h index 2047902a98..95f69bafa2 100644 --- a/libs/pigment/KoColorSpaceAbstract.h +++ b/libs/pigment/KoColorSpaceAbstract.h @@ -1,209 +1,208 @@ /* * Copyright (c) 2006 Cyrille Berger * Copyright (c) 2007 Emanuele Tamponi * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KOCOLORSPACEABSTRACT_H #define KOCOLORSPACEABSTRACT_H #include #include #include #include #include #include #include "KoFallBackColorTransformation.h" #include "KoLabDarkenColorTransformation.h" #include "KoMixColorsOpImpl.h" #include "KoConvolutionOpImpl.h" #include "KoInvertColorTransformation.h" - /** * This in an implementation of KoColorSpace which can be used as a base for colorspaces with as many * different channels of the same type. * * The template parameters must be a class which inherits KoColorSpaceTrait (or a class with the same signature). * * SOMETYPE is the type of the channel for instance (quint8, quint32...), * SOMENBOFCHANNELS is the number of channels including the alpha channel * SOMEALPHAPOS is the position of the alpha channel in the pixel (can be equal to -1 if no alpha channel). */ template class KoColorSpaceAbstract : public KoColorSpace { public: KoColorSpaceAbstract(const QString &id, const QString &name) : KoColorSpace(id, name, new KoMixColorsOpImpl< _CSTrait>(), new KoConvolutionOpImpl< _CSTrait>()) { } quint32 colorChannelCount() const override { if (_CSTrait::alpha_pos == -1) return _CSTrait::channels_nb; else return _CSTrait::channels_nb - 1; } quint32 channelCount() const override { return _CSTrait::channels_nb; } quint32 pixelSize() const override { return _CSTrait::pixelSize; } QString channelValueText(const quint8 *pixel, quint32 channelIndex) const override { return _CSTrait::channelValueText(pixel, channelIndex); } QString normalisedChannelValueText(const quint8 *pixel, quint32 channelIndex) const override { return _CSTrait::normalisedChannelValueText(pixel, channelIndex); } void normalisedChannelsValue(const quint8 *pixel, QVector &channels) const override { return _CSTrait::normalisedChannelsValue(pixel, channels); } void fromNormalisedChannelsValue(quint8 *pixel, const QVector &values) const override { return _CSTrait::fromNormalisedChannelsValue(pixel, values); } quint8 scaleToU8(const quint8 * srcPixel, qint32 channelIndex) const override { typename _CSTrait::channels_type c = _CSTrait::nativeArray(srcPixel)[channelIndex]; return KoColorSpaceMaths::scaleToA(c); } void singleChannelPixel(quint8 *dstPixel, const quint8 *srcPixel, quint32 channelIndex) const override { _CSTrait::singleChannelPixel(dstPixel, srcPixel, channelIndex); } quint8 opacityU8(const quint8 * U8_pixel) const override { return _CSTrait::opacityU8(U8_pixel); } qreal opacityF(const quint8 * U8_pixel) const override { return _CSTrait::opacityF(U8_pixel); } void setOpacity(quint8 * pixels, quint8 alpha, qint32 nPixels) const override { _CSTrait::setOpacity(pixels, alpha, nPixels); } void setOpacity(quint8 * pixels, qreal alpha, qint32 nPixels) const override { _CSTrait::setOpacity(pixels, alpha, nPixels); } void multiplyAlpha(quint8 * pixels, quint8 alpha, qint32 nPixels) const override { _CSTrait::multiplyAlpha(pixels, alpha, nPixels); } void applyAlphaU8Mask(quint8 * pixels, const quint8 * alpha, qint32 nPixels) const override { _CSTrait::applyAlphaU8Mask(pixels, alpha, nPixels); } void applyInverseAlphaU8Mask(quint8 * pixels, const quint8 * alpha, qint32 nPixels) const override { _CSTrait::applyInverseAlphaU8Mask(pixels, alpha, nPixels); } void applyAlphaNormedFloatMask(quint8 * pixels, const float * alpha, qint32 nPixels) const override { _CSTrait::applyAlphaNormedFloatMask(pixels, alpha, nPixels); } void applyInverseNormedFloatMask(quint8 * pixels, const float * alpha, qint32 nPixels) const override { _CSTrait::applyInverseAlphaNormedFloatMask(pixels, alpha, nPixels); } quint8 intensity8(const quint8 * src) const override { QColor c; const_cast *>(this)->toQColor(src, &c); return static_cast(c.red() * 0.30 + c.green() * 0.59 + c.blue() * 0.11); } KoColorTransformation* createInvertTransformation() const override { - return new KoInvertColorTransformation(this); + return KoInvertColorTransformation::getTransformator(this); } KoColorTransformation *createDarkenAdjustment(qint32 shade, bool compensate, qreal compensation) const override { return new KoFallBackColorTransformation(this, KoColorSpaceRegistry::instance()->lab16(""), new KoLabDarkenColorTransformation(shade, compensate, compensation, KoColorSpaceRegistry::instance()->lab16(""))); } bool convertPixelsTo(const quint8 *src, quint8 *dst, const KoColorSpace *dstColorSpace, quint32 numPixels, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const override { // check whether we have the same profile and color model, but only a different bit // depth; in that case we don't convert as such, but scale bool scaleOnly = false; // Note: getting the id() is really, really expensive, so only do that if // we are sure there is a difference between the colorspaces if (!(*this == *dstColorSpace)) { scaleOnly = dstColorSpace->colorModelId().id() == colorModelId().id() && dstColorSpace->colorDepthId().id() != colorDepthId().id() && dstColorSpace->profile()->name() == profile()->name(); } if (scaleOnly && dynamic_cast(dstColorSpace)) { typedef typename _CSTrait::channels_type channels_type; switch(dstColorSpace->channels()[0]->channelValueType()) { case KoChannelInfo::UINT8: scalePixels<_CSTrait::pixelSize, 1, channels_type, quint8>(src, dst, numPixels); return true; // case KoChannelInfo::INT8: // scalePixels<_CSTrait::pixelSize, 1, channels_type, qint8>(src, dst, numPixels); // return true; case KoChannelInfo::UINT16: scalePixels<_CSTrait::pixelSize, 2, channels_type, quint16>(src, dst, numPixels); return true; case KoChannelInfo::INT16: scalePixels<_CSTrait::pixelSize, 2, channels_type, qint16>(src, dst, numPixels); return true; case KoChannelInfo::UINT32: scalePixels<_CSTrait::pixelSize, 4, channels_type, quint32>(src, dst, numPixels); return true; default: break; } } return KoColorSpace::convertPixelsTo(src, dst, dstColorSpace, numPixels, renderingIntent, conversionFlags); } private: template void scalePixels(const quint8* src, quint8* dst, quint32 numPixels) const { qint32 dstPixelSize = dstChannelSize * _CSTrait::channels_nb; for(quint32 i=0; i(src + i * srcPixelSize); TDstChannel* dstPixel = reinterpret_cast(dst + i * dstPixelSize); for(quint32 c=0; c<_CSTrait::channels_nb; ++c) dstPixel[c] = Arithmetic::scale(srcPixel[c]); } } }; #endif // KOCOLORSPACEABSTRACT_H diff --git a/libs/pigment/KoInvertColorTransformation.h b/libs/pigment/KoInvertColorTransformation.h index dec0fa83f0..b198060a8d 100644 --- a/libs/pigment/KoInvertColorTransformation.h +++ b/libs/pigment/KoInvertColorTransformation.h @@ -1,55 +1,188 @@ /* + * Copyright (c) 2018 Iván Santa María * Copyright (c) 2006 Cyrille Berger * Copyright (c) 2007 Emanuele Tamponi * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KO_INVERT_COLOR_TRANSFORMATION_H #define KO_INVERT_COLOR_TRANSFORMATION_H #include "KoColorTransformation.h" -class KoInvertColorTransformation : public KoColorTransformation -{ +#include "KoColorSpace.h" +#include "KoColorSpaceMaths.h" + +#include "KoColorModelStandardIds.h" + + +class KoInvertColorTransformationT : public KoColorTransformation { public: - KoInvertColorTransformation(const KoColorSpace* cs) : m_colorSpace(cs), m_psize(cs->pixelSize()) { + KoInvertColorTransformationT(const KoColorSpace* cs) + : m_colorSpace(cs) + , m_psize(cs->pixelSize()) + , m_chanCount(cs->channelCount()) + { + // Only invert COLOR channels + QList channels = cs->channels(); + for(quint8 i = 0; i < m_chanCount; i++){ + if(channels.at(i)->channelType() == KoChannelInfo::COLOR) + m_channels.append(i); + } } - void transform(const quint8 *src, quint8 *dst, qint32 nPixels) const override { + template + void transformI(const quint8 *src, quint8 *dst, qint32 nPixels) const { + T *m_rgba = (T*)(src); + T *m_dst = (T*)(dst); + + while (nPixels--) { + for(quint8 i : m_channels){ + m_dst[i] = KoColorSpaceMaths::invert(m_rgba[i]); + } + m_rgba += m_chanCount; + m_dst += m_chanCount; + } + + } + + void transformGen(const quint8 *src, quint8 *dst, qint32 nPixels) const { quint16 m_rgba[4]; while (nPixels--) { m_colorSpace->toRgbA16(src, reinterpret_cast(m_rgba), 1); m_rgba[0] = KoColorSpaceMathsTraits::max - m_rgba[0]; m_rgba[1] = KoColorSpaceMathsTraits::max - m_rgba[1]; m_rgba[2] = KoColorSpaceMathsTraits::max - m_rgba[2]; m_colorSpace->fromRgbA16(reinterpret_cast(m_rgba), dst, 1); src += m_psize; dst += m_psize; } - } -private: + // Once CMYK and LAB 32 float are normalized, this inverts will invert properly +// template +// void transformC(const quint8 *src, quint8 *dst, qint32 nPixels) const { +// QVector normChan(m_chanCount); + +// float *m_rgba; +// float *m_dst = (float*)(dst); +// while (nPixels--) { +// m_colorSpace->normalisedChannelsValue(src, normChan); +// for(quint8 i : m_channels){ +// normChan[i] = KoColorSpaceMaths::invert(normChan[i]); +// } +// m_colorSpace->fromNormalisedChannelsValue(dst,normChan); +// //m_rgba += m_psize; +// src += m_psize; +// dst += m_psize; +// } +// } +protected: + QList m_channels; +private: const KoColorSpace* m_colorSpace; quint32 m_psize; + quint32 m_chanCount; +}; + +class KoU8InvertColorTransformer : public KoInvertColorTransformationT { +public: + KoU8InvertColorTransformer(const KoColorSpace* cs) + : KoInvertColorTransformationT(cs) + { + }; + + void transform(const quint8 *src, quint8 *dst, qint32 nPixels) const override { + transformI(src,dst,nPixels); + } +}; + +class KoU16InvertColorTransformer : public KoInvertColorTransformationT { +public: + KoU16InvertColorTransformer(const KoColorSpace* cs) + : KoInvertColorTransformationT(cs) + { + }; + + void transform(const quint8 *src, quint8 *dst, qint32 nPixels) const override { + transformI(src,dst,nPixels); + } }; +class KoF16InvertColorTransformer : public KoInvertColorTransformationT { +public: + KoF16InvertColorTransformer(const KoColorSpace* cs) + : KoInvertColorTransformationT(cs) + { + }; + + void transform(const quint8 *src, quint8 *dst, qint32 nPixels) const override { + transformI(src,dst,nPixels); + } +}; + +class KoF32InvertColorTransformer : public KoInvertColorTransformationT { +public: + KoF32InvertColorTransformer(const KoColorSpace* cs) + : KoInvertColorTransformationT(cs) + { + }; + + void transform(const quint8 *src, quint8 *dst, qint32 nPixels) const override { + transformI(src,dst,nPixels); + } +}; + +class KoF32GenInvertColorTransformer : public KoInvertColorTransformationT { +public: + KoF32GenInvertColorTransformer(const KoColorSpace* cs) + : KoInvertColorTransformationT(cs) + { + }; + + void transform(const quint8 *src, quint8 *dst, qint32 nPixels) const override { + transformGen(src,dst,nPixels); + } +}; + + +class KoInvertColorTransformation +{ +public: + static KoColorTransformation* getTransformator(const KoColorSpace *cs) + { + KoID id = cs->colorDepthId(); + KoID modelId = cs->colorModelId(); + if (id == Integer8BitsColorDepthID) { + return new KoU8InvertColorTransformer(cs); + } else if (id == Integer16BitsColorDepthID) { + return new KoU16InvertColorTransformer(cs); + } else if (id == Float16BitsColorDepthID) { + return new KoF16InvertColorTransformer(cs); + } else { + if(modelId == LABAColorModelID || modelId == CMYKAColorModelID){ + return new KoF32GenInvertColorTransformer(cs); + } + return new KoF32InvertColorTransformer(cs); + } + } +}; #endif diff --git a/plugins/color/lcms2engine/colorspaces/rgb_u8/RgbU8ColorSpace.cpp b/plugins/color/lcms2engine/colorspaces/rgb_u8/RgbU8ColorSpace.cpp index 76baf63491..f2c4b37e09 100644 --- a/plugins/color/lcms2engine/colorspaces/rgb_u8/RgbU8ColorSpace.cpp +++ b/plugins/color/lcms2engine/colorspaces/rgb_u8/RgbU8ColorSpace.cpp @@ -1,144 +1,112 @@ /* * Copyright (c) 2002 Patrick Julien * Copyright (c) 2004 Boudewijn Rempt * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 "RgbU8ColorSpace.h" #include #include #include #include #include #include #include #include "compositeops/KoCompositeOps.h" #include "compositeops/RgbCompositeOps.h" #include #define downscale(quantum) (quantum) //((unsigned char) ((quantum)/257UL)) #define upscale(value) (value) // ((quint8) (257UL*(value))) -class KoRgbU8InvertColorTransformation : public KoColorTransformation -{ - -public: - - KoRgbU8InvertColorTransformation(const KoColorSpace *cs) : m_psize(cs->pixelSize()) - { - } - - void transform(const quint8 *src, quint8 *dst, qint32 nPixels) const override - { - while (nPixels--) { - dst[0] = KoColorSpaceMathsTraits::max - src[0]; - dst[1] = KoColorSpaceMathsTraits::max - src[1]; - dst[2] = KoColorSpaceMathsTraits::max - src[2]; - dst[3] = src[3]; - - src += m_psize; - dst += m_psize; - } - - } - -private: - quint32 m_psize; -}; - RgbU8ColorSpace::RgbU8ColorSpace(const QString &name, KoColorProfile *p) : LcmsColorSpace(colorSpaceId(), name, TYPE_BGRA_8, cmsSigRgbData, p) { addChannel(new KoChannelInfo(i18n("Blue"), 0, 2, KoChannelInfo::COLOR, KoChannelInfo::UINT8, 1, QColor(0, 0, 255))); addChannel(new KoChannelInfo(i18n("Green"), 1, 1, KoChannelInfo::COLOR, KoChannelInfo::UINT8, 1, QColor(0, 255, 0))); addChannel(new KoChannelInfo(i18n("Red"), 2, 0, KoChannelInfo::COLOR, KoChannelInfo::UINT8, 1, QColor(255, 0, 0))); addChannel(new KoChannelInfo(i18n("Alpha"), 3, 3, KoChannelInfo::ALPHA, KoChannelInfo::UINT8)); init(); addStandardCompositeOps(this); addCompositeOp(new RgbCompositeOpIn(this)); addCompositeOp(new RgbCompositeOpOut(this)); addCompositeOp(new RgbCompositeOpBumpmap(this)); } -KoColorTransformation *RgbU8ColorSpace::createInvertTransformation() const -{ - return new KoRgbU8InvertColorTransformation(this); -} - KoColorSpace *RgbU8ColorSpace::clone() const { return new RgbU8ColorSpace(name(), profile()->clone()); } void RgbU8ColorSpace::colorToXML(const quint8 *pixel, QDomDocument &doc, QDomElement &colorElt) const { const KoBgrU8Traits::Pixel *p = reinterpret_cast(pixel); QDomElement labElt = doc.createElement("RGB"); labElt.setAttribute("r", KisDomUtils::toString(KoColorSpaceMaths< KoBgrU8Traits::channels_type, qreal>::scaleToA(p->red))); labElt.setAttribute("g", KisDomUtils::toString(KoColorSpaceMaths< KoBgrU8Traits::channels_type, qreal>::scaleToA(p->green))); labElt.setAttribute("b", KisDomUtils::toString(KoColorSpaceMaths< KoBgrU8Traits::channels_type, qreal>::scaleToA(p->blue))); labElt.setAttribute("space", profile()->name()); colorElt.appendChild(labElt); } void RgbU8ColorSpace::colorFromXML(quint8 *pixel, const QDomElement &elt) const { KoBgrU8Traits::Pixel *p = reinterpret_cast(pixel); p->red = KoColorSpaceMaths< qreal, KoBgrU8Traits::channels_type >::scaleToA(KisDomUtils::toDouble(elt.attribute("r"))); p->green = KoColorSpaceMaths< qreal, KoBgrU8Traits::channels_type >::scaleToA(KisDomUtils::toDouble(elt.attribute("g"))); p->blue = KoColorSpaceMaths< qreal, KoBgrU8Traits::channels_type >::scaleToA(KisDomUtils::toDouble(elt.attribute("b"))); p->alpha = KoColorSpaceMathsTraits::max; } quint8 RgbU8ColorSpace::intensity8(const quint8 *src) const { const KoBgrU8Traits::Pixel *p = reinterpret_cast(src); return (quint8)(p->red * 0.30 + p->green * 0.59 + p->blue * 0.11); } void RgbU8ColorSpace::toHSY(const QVector &channelValues, qreal *hue, qreal *sat, qreal *luma) const { RGBToHSY(channelValues[0],channelValues[1],channelValues[2], hue, sat, luma, lumaCoefficients()[0], lumaCoefficients()[1], lumaCoefficients()[2]); } QVector RgbU8ColorSpace::fromHSY(qreal *hue, qreal *sat, qreal *luma) const { QVector channelValues(4); HSYToRGB(*hue, *sat, *luma, &channelValues[0],&channelValues[1],&channelValues[2], lumaCoefficients()[0], lumaCoefficients()[1], lumaCoefficients()[2]); channelValues[3]=1.0; return channelValues; } void RgbU8ColorSpace::toYUV(const QVector &channelValues, qreal *y, qreal *u, qreal *v) const { RGBToYUV(channelValues[0],channelValues[1],channelValues[2], y, u, v, lumaCoefficients()[0], lumaCoefficients()[1], lumaCoefficients()[2]); } QVector RgbU8ColorSpace::fromYUV(qreal *y, qreal *u, qreal *v) const { QVector channelValues(4); YUVToRGB(*y, *u, *v, &channelValues[0],&channelValues[1],&channelValues[2], lumaCoefficients()[0], lumaCoefficients()[1], lumaCoefficients()[2]); channelValues[3]=1.0; return channelValues; } diff --git a/plugins/color/lcms2engine/colorspaces/rgb_u8/RgbU8ColorSpace.h b/plugins/color/lcms2engine/colorspaces/rgb_u8/RgbU8ColorSpace.h index 21cefeb8fc..b9256a2276 100644 --- a/plugins/color/lcms2engine/colorspaces/rgb_u8/RgbU8ColorSpace.h +++ b/plugins/color/lcms2engine/colorspaces/rgb_u8/RgbU8ColorSpace.h @@ -1,118 +1,116 @@ /* * Copyright (c) 2002 Patrick Julien * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 KO_STRATEGY_COLORSPACE_RGB_H_ #define KO_STRATEGY_COLORSPACE_RGB_H_ #include #include #include "KoColorModelStandardIds.h" struct KoBgrU8Traits; class RgbU8ColorSpace : public LcmsColorSpace { public: RgbU8ColorSpace(const QString &name, KoColorProfile *p); bool willDegrade(ColorSpaceIndependence) const override { return false; } - KoColorTransformation *createInvertTransformation() const override; - KoID colorModelId() const override { return RGBAColorModelID; } KoID colorDepthId() const override { return Integer8BitsColorDepthID; } virtual KoColorSpace *clone() const; void colorToXML(const quint8 *pixel, QDomDocument &doc, QDomElement &colorElt) const override; void colorFromXML(quint8 *pixel, const QDomElement &elt) const override; quint8 intensity8(const quint8 * src) const override; void toHSY(const QVector &channelValues, qreal *hue, qreal *sat, qreal *luma) const override; QVector fromHSY(qreal *hue, qreal *sat, qreal *luma) const override; void toYUV(const QVector &channelValues, qreal *y, qreal *u, qreal *v) const override; QVector fromYUV(qreal *y, qreal *u, qreal *v) const override; static QString colorSpaceId() { return QString("RGBA"); } }; class RgbU8ColorSpaceFactory : public LcmsColorSpaceFactory { public: RgbU8ColorSpaceFactory() : LcmsColorSpaceFactory(TYPE_BGRA_8, cmsSigRgbData) {} bool userVisible() const override { return true; } QString id() const override { return RgbU8ColorSpace::colorSpaceId(); } QString name() const override { return QString("%1 (%2)").arg(RGBAColorModelID.name()).arg(Integer8BitsColorDepthID.name()); } KoID colorModelId() const override { return RGBAColorModelID; } KoID colorDepthId() const override { return Integer8BitsColorDepthID; } int referenceDepth() const override { return 8; } KoColorSpace *createColorSpace(const KoColorProfile *p) const override { return new RgbU8ColorSpace(name(), p->clone()); } QString defaultProfile() const override { return "sRGB-elle-V2-srgbtrc.icc"; } }; #endif // KO_STRATEGY_COLORSPACE_RGB_H_