diff --git a/libs/pigment/colorspaces/KoLabColorSpace.cpp b/libs/pigment/colorspaces/KoLabColorSpace.cpp index 0ab9bb804a..9f6cae126d 100644 --- a/libs/pigment/colorspaces/KoLabColorSpace.cpp +++ b/libs/pigment/colorspaces/KoLabColorSpace.cpp @@ -1,251 +1,263 @@ /* * Copyright (c) 2004-2009 Boudewijn Rempt * Copyright (c) 2006 Cyrille Berger * * 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 "KoLabColorSpace.h" #include #include #include #include #include #include #include "KoChannelInfo.h" #include "KoID.h" #include "KoIntegerMaths.h" #include "KoColorConversions.h" #include "../compositeops/KoCompositeOps.h" KoLabColorSpace::KoLabColorSpace() : KoSimpleColorSpace(colorSpaceId(), i18n("L*a*b* (16-bit integer/channel, unmanaged)"), LABAColorModelID, Integer16BitsColorDepthID) { addChannel(new KoChannelInfo(i18n("Lightness"), CHANNEL_L * sizeof(quint16), CHANNEL_L, KoChannelInfo::COLOR, KoChannelInfo::UINT16, sizeof(quint16), QColor(100, 100, 100))); addChannel(new KoChannelInfo(i18n("a*"), CHANNEL_A * sizeof(quint16), CHANNEL_A, KoChannelInfo::COLOR, KoChannelInfo::UINT16, sizeof(quint16), QColor(150, 150, 150))); addChannel(new KoChannelInfo(i18n("b*"), CHANNEL_B * sizeof(quint16), CHANNEL_B, KoChannelInfo::COLOR, KoChannelInfo::UINT16, sizeof(quint16), QColor(200, 200, 200))); addChannel(new KoChannelInfo(i18n("Alpha"), CHANNEL_ALPHA * sizeof(quint16), CHANNEL_ALPHA, KoChannelInfo::ALPHA, KoChannelInfo::UINT16, sizeof(quint16))); // ADD, ALPHA_DARKEN, BURN, DIVIDE, DODGE, ERASE, MULTIPLY, OVER, OVERLAY, SCREEN, SUBTRACT addStandardCompositeOps(this); } KoLabColorSpace::~KoLabColorSpace() { } QString KoLabColorSpace::colorSpaceId() { return QString("LABA"); } KoColorSpace* KoLabColorSpace::clone() const { return new KoLabColorSpace(); } void KoLabColorSpace::fromQColor(const QColor& c, quint8 *dst, const KoColorProfile * /*profile*/) const { // Convert between RGB and CIE-Lab color spaces // Uses ITU-R recommendation BT.709 with D65 as reference white. // algorithm contributed by "Mark A. Ruzon" int R, G, B, A; c.getRgb(&R, &G, &B, &A); double X, Y, Z, fX, fY, fZ; X = 0.412453 * R + 0.357580 * G + 0.180423 * B; Y = 0.212671 * R + 0.715160 * G + 0.072169 * B; Z = 0.019334 * R + 0.119193 * G + 0.950227 * B; X /= (255 * 0.950456); Y /= 255; Z /= (255 * 1.088754); quint8 L, a, b; if (Y > 0.008856) { fY = pow(Y, 1.0 / 3.0); L = static_cast(116.0 * fY - 16.0 + 0.5); } else { fY = 7.787 * Y + 16.0 / 116.0; L = static_cast(903.3 * Y + 0.5); } if (X > 0.008856) fX = pow(X, 1.0 / 3.0); else fX = 7.787 * X + 16.0 / 116.0; if (Z > 0.008856) fZ = pow(Z, 1.0 / 3.0); else fZ = 7.787 * Z + 16.0 / 116.0; a = static_cast(500.0 * (fX - fY) + 0.5); b = static_cast(200.0 * (fY - fZ) + 0.5); dst[CHANNEL_L] = UINT8_TO_UINT16(L); dst[CHANNEL_A] = UINT8_TO_UINT16(a); dst[CHANNEL_B] = UINT8_TO_UINT16(b); dst[CHANNEL_ALPHA] = UINT8_TO_UINT16(A); } void KoLabColorSpace::toQColor(const quint8 * src, QColor *c, const KoColorProfile * /*profile*/) const { // Convert between RGB and CIE-Lab color spaces // Uses ITU-R recommendation BT.709 with D65 as reference white. // algorithm contributed by "Mark A. Ruzon" quint8 L, a, b, A; L = UINT16_TO_UINT8(src[CHANNEL_L]); a = UINT16_TO_UINT8(src[CHANNEL_A]); b = UINT16_TO_UINT8(src[CHANNEL_B]); A = UINT16_TO_UINT8(src[CHANNEL_ALPHA]); double X, Y, Z, fX, fY, fZ; int RR, GG, BB; fY = pow((L + 16.0) / 116.0, 3.0); if (fY < 0.008856) fY = L / 903.3; Y = fY; if (fY > 0.008856) fY = pow(fY, 1.0 / 3.0); else fY = 7.787 * fY + 16.0 / 116.0; fX = a / 500.0 + fY; if (fX > 0.206893) X = pow(fX, 3.0); else X = (fX - 16.0 / 116.0) / 7.787; fZ = fY - b / 200.0; if (fZ > 0.206893) Z = pow(fZ, 3.0); else Z = (fZ - 16.0 / 116.0) / 7.787; X *= 0.950456 * 255; Y *= 255; Z *= 1.088754 * 255; RR = static_cast(3.240479 * X - 1.537150 * Y - 0.498535 * Z + 0.5); GG = static_cast(-0.969256 * X + 1.875992 * Y + 0.041556 * Z + 0.5); BB = static_cast(0.055648 * X - 0.204043 * Y + 1.057311 * Z + 0.5); quint8 R = RR < 0 ? 0 : RR > 255 ? 255 : RR; quint8 G = GG < 0 ? 0 : GG > 255 ? 255 : GG; quint8 B = BB < 0 ? 0 : BB > 255 ? 255 : BB; c->setRgba(qRgba(R, G, B, A)); } void KoLabColorSpace::toHSY(const QVector &channelValues, qreal *hue, qreal *sat, qreal *luma) const { LabToLCH(channelValues[0],channelValues[1],channelValues[2], luma, sat, hue); } QVector KoLabColorSpace::fromHSY(qreal *hue, qreal *sat, qreal *luma) const { QVector channelValues(4); LCHToLab(*luma, *sat, *hue, &channelValues[0],&channelValues[1],&channelValues[2]); channelValues[3]=1.0; return channelValues; } void KoLabColorSpace::toYUV(const QVector &channelValues, qreal *y, qreal *u, qreal *v) const { *y =channelValues[0]; *v=channelValues[1]; *u=channelValues[2]; } QVector KoLabColorSpace::fromYUV(qreal *y, qreal *u, qreal *v) const { QVector channelValues(4); channelValues[0]=*y; channelValues[1]=*v; channelValues[2]=*u; channelValues[3]=1.0; return channelValues; } -void KoLabColorSpace::convertChannelToVisualRepresentation(const quint8 *src, quint8 *dst, quint32 nPixels, const QBitArray selectedChannels, bool singleChannelAsColor) const +quint8 KoLabColorSpace::scaleToU8(const quint8 *srcPixel, qint32 channelIndex) const { - if (selectedChannels.count(true) == 1 && !singleChannelAsColor) { - int selectedChannelPos = 0; - - for (int i = 0; i < selectedChannels.size(); ++i) { - KoChannelInfo *channel = this->channels().at(i); - if (selectedChannels.testBit(i) && channel->channelType() == KoChannelInfo::COLOR) { - selectedChannelPos = i; - } + typename ColorSpaceTraits::channels_type c = ColorSpaceTraits::nativeArray(srcPixel)[channelIndex]; + qreal b = 0; + switch (channelIndex) { + case ColorSpaceTraits::L_pos: + b = ((qreal)c) / ColorSpaceTraits::math_trait::unitValueL; + break; + case ColorSpaceTraits::a_pos: + case ColorSpaceTraits::b_pos: + if (c <= ColorSpaceTraits::math_trait::halfValueAB) { + b = ((qreal)c - ColorSpaceTraits::math_trait::zeroValueAB) / (2.0 * (ColorSpaceTraits::math_trait::halfValueAB - ColorSpaceTraits::math_trait::zeroValueAB)); + } else { + b = 0.5 + ((qreal)c - ColorSpaceTraits::math_trait::halfValueAB) / (2.0 * (ColorSpaceTraits::math_trait::unitValueAB - ColorSpaceTraits::math_trait::halfValueAB)); } + break; + default: + b = ((qreal)c) / ColorSpaceTraits::math_trait::unitValue; + break; + } + + return KoColorSpaceMaths::scaleToA(b); +} for (uint pixelIndex = 0; pixelIndex < nPixels; ++pixelIndex) { for (uint channelIndex = 0; channelIndex < this->channelCount(); ++channelIndex) { KoChannelInfo *channel = this->channels().at(channelIndex); qint32 channelSize = channel->size(); if (channel->channelType() == KoChannelInfo::COLOR) { if (channelIndex == ColorSpaceTraits::L_pos) { memcpy(dst + (pixelIndex * ColorSpaceTraits::pixelSize) + (channelIndex * channelSize), src + (pixelIndex * ColorSpaceTraits::pixelSize) + selectedChannelPos, channelSize); } else { reinterpret_cast(dst + (pixelIndex * ColorSpaceTraits::pixelSize) + (channelIndex * channelSize))[0] = ColorSpaceTraits::math_trait::halfValueAB; } } else if (channel->channelType() == KoChannelInfo::ALPHA) { memcpy(dst + (pixelIndex * ColorSpaceTraits::pixelSize) + (channelIndex * channelSize), src + (pixelIndex * ColorSpaceTraits::pixelSize) + (channelIndex * channelSize), channelSize); } } } } else { for (uint pixelIndex = 0; pixelIndex < nPixels; ++pixelIndex) { for (uint channelIndex = 0; channelIndex < this->channelCount(); ++channelIndex) { KoChannelInfo *channel = this->channels().at(channelIndex); qint32 channelSize = channel->size(); if (selectedChannels.testBit(channelIndex)) { memcpy(dst + (pixelIndex * ColorSpaceTraits::pixelSize) + (channelIndex * channelSize), src + (pixelIndex * ColorSpaceTraits::pixelSize) + (channelIndex * channelSize), channelSize); } else { ColorSpaceTraits::channels_type v; switch (channelIndex) { case ColorSpaceTraits::L_pos: v = ColorSpaceTraits::math_trait::halfValueL; break; case ColorSpaceTraits::a_pos: case ColorSpaceTraits::b_pos: v = ColorSpaceTraits::math_trait::halfValueAB; break; default: v = ColorSpaceTraits::math_trait::zeroValue; break; } reinterpret_cast(dst + (pixelIndex * ColorSpaceTraits::pixelSize) + (channelIndex * channelSize))[0] = v; } } } } } diff --git a/libs/pigment/colorspaces/KoLabColorSpace.h b/libs/pigment/colorspaces/KoLabColorSpace.h index e6e384a5ee..896eb24143 100644 --- a/libs/pigment/colorspaces/KoLabColorSpace.h +++ b/libs/pigment/colorspaces/KoLabColorSpace.h @@ -1,88 +1,88 @@ /* * Copyright (c) 2004 Boudewijn Rempt * Copyright (c) 2006 Cyrille Berger * * 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 KOLABCOLORSPACE_H #define KOLABCOLORSPACE_H #include #include "KoSimpleColorSpace.h" #include "KoSimpleColorSpaceFactory.h" #include "KoColorModelStandardIds.h" struct KoLabU16Traits; /** * Basic and simple implementation of the LAB colorspace */ class KoLabColorSpace : public KoSimpleColorSpace { public: KoLabColorSpace(); ~KoLabColorSpace() override; static QString colorSpaceId(); virtual KoColorSpace* clone() const; void fromQColor(const QColor& color, quint8 *dst, const KoColorProfile * profile = 0) const override; void toQColor(const quint8 *src, QColor *c, const KoColorProfile * profile = 0) 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; - void convertChannelToVisualRepresentation(const quint8 *src, quint8 *dst, quint32 nPixels, const QBitArray selectedChannels, bool singleChannelAsColor) const override; + quint8 scaleToU8(const quint8 * srcPixel, qint32 channelIndex) const override; private: static const quint32 CHANNEL_L = 0; static const quint32 CHANNEL_A = 1; static const quint32 CHANNEL_B = 2; static const quint32 CHANNEL_ALPHA = 3; static const quint32 MAX_CHANNEL_L = 0xff00; static const quint32 MAX_CHANNEL_AB = 0xffff; static const quint32 CHANNEL_AB_ZERO_OFFSET = 0x8000; }; class KoLabColorSpaceFactory : public KoSimpleColorSpaceFactory { public: KoLabColorSpaceFactory() : KoSimpleColorSpaceFactory("LABA", i18n("L*a*b* (16-bit integer/channel, unmanaged)"), true, LABAColorModelID, Integer16BitsColorDepthID) { } KoColorSpace *createColorSpace(const KoColorProfile *) const override { return new KoLabColorSpace(); } }; #endif diff --git a/plugins/color/lcms2engine/colorspaces/lab_f32/LabF32ColorSpace.cpp b/plugins/color/lcms2engine/colorspaces/lab_f32/LabF32ColorSpace.cpp index 6ba6392f04..59edd3b54b 100644 --- a/plugins/color/lcms2engine/colorspaces/lab_f32/LabF32ColorSpace.cpp +++ b/plugins/color/lcms2engine/colorspaces/lab_f32/LabF32ColorSpace.cpp @@ -1,196 +1,197 @@ /* * Copyright (c) 2006 Cyrille Berger * Copyright (c) 2020 L. E. Segovia * * 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 * Library 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. */ #include "LabF32ColorSpace.h" #include #include #include "../compositeops/KoCompositeOps.h" #include #include LabF32ColorSpace::LabF32ColorSpace(const QString &name, KoColorProfile *p) : LcmsColorSpace(colorSpaceId(), name, TYPE_LabA_FLT, cmsSigLabData, p) { const IccColorProfile *icc_p = dynamic_cast(p); Q_ASSERT(icc_p); QVector uiRanges(icc_p->getFloatUIMinMax()); Q_ASSERT(uiRanges.size() == 3); addChannel(new KoChannelInfo(i18n("Lightness"), 0 * sizeof(float), 0, KoChannelInfo::COLOR, KoChannelInfo::FLOAT32, sizeof(float), QColor(100, 100, 100), uiRanges[0])); addChannel(new KoChannelInfo(i18n("a*"), 1 * sizeof(float), 1, KoChannelInfo::COLOR, KoChannelInfo::FLOAT32, sizeof(float), QColor(150, 150, 150), uiRanges[1])); addChannel(new KoChannelInfo(i18n("b*"), 2 * sizeof(float), 2, KoChannelInfo::COLOR, KoChannelInfo::FLOAT32, sizeof(float), QColor(200, 200, 200), uiRanges[2])); addChannel(new KoChannelInfo(i18n("Alpha"), 3 * sizeof(float), 3, KoChannelInfo::ALPHA, KoChannelInfo::FLOAT32, sizeof(float))); init(); addStandardCompositeOps(this); dbgPlugins << "La*b* (float) channel bounds for: " << icc_p->name(); dbgPlugins << "L: " << uiRanges[0].minVal << uiRanges[0].maxVal; dbgPlugins << "a: " << uiRanges[1].minVal << uiRanges[1].maxVal; dbgPlugins << "b: " << uiRanges[2].minVal << uiRanges[2].maxVal; } bool LabF32ColorSpace::willDegrade(ColorSpaceIndependence independence) const { if (independence == TO_RGBA16) { return true; } else { return false; } } KoColorSpace *LabF32ColorSpace::clone() const { return new LabF32ColorSpace(name(), profile()->clone()); } void LabF32ColorSpace::colorToXML(const quint8 *pixel, QDomDocument &doc, QDomElement &colorElt) const { const KoLabF32Traits::Pixel *p = reinterpret_cast(pixel); QDomElement labElt = doc.createElement("Lab"); // XML expects 0-1, we need 0-100, -128-+127 // Get the bounds from the channels and adjust the calculations labElt.setAttribute("L", KisDomUtils::toString(KoColorSpaceMaths< KoLabF32Traits::channels_type, qreal>::scaleToA(1.f / this->channels()[0]->getUIUnitValue() * (p->L - this->channels()[0]->getUIMin())))); labElt.setAttribute("a", KisDomUtils::toString(KoColorSpaceMaths< KoLabF32Traits::channels_type, qreal>::scaleToA(1.f / this->channels()[1]->getUIUnitValue() * (p->a - this->channels()[1]->getUIMin())))); labElt.setAttribute("b", KisDomUtils::toString(KoColorSpaceMaths< KoLabF32Traits::channels_type, qreal>::scaleToA(1.f / this->channels()[2]->getUIUnitValue() * (p->b - this->channels()[2]->getUIMin())))); labElt.setAttribute("space", profile()->name()); colorElt.appendChild(labElt); } void LabF32ColorSpace::colorFromXML(quint8 *pixel, const QDomElement &elt) const { KoLabF32Traits::Pixel *p = reinterpret_cast(pixel); p->L = this->channels()[0]->getUIMin() + KoColorSpaceMaths< qreal, KoLabF32Traits::channels_type >::scaleToA(KisDomUtils::toDouble(elt.attribute("L"))) * this->channels()[0]->getUIUnitValue(); p->a = this->channels()[1]->getUIMin() + KoColorSpaceMaths< qreal, KoLabF32Traits::channels_type >::scaleToA(KisDomUtils::toDouble(elt.attribute("a"))) * this->channels()[1]->getUIUnitValue(); p->b = this->channels()[2]->getUIMin() + KoColorSpaceMaths< qreal, KoLabF32Traits::channels_type >::scaleToA(KisDomUtils::toDouble(elt.attribute("b"))) * this->channels()[2]->getUIUnitValue(); p->alpha = 1.0; } void LabF32ColorSpace::toHSY(const QVector &channelValues, qreal *hue, qreal *sat, qreal *luma) const { LabToLCH(channelValues[0],channelValues[1],channelValues[2], luma, sat, hue); } QVector LabF32ColorSpace::fromHSY(qreal *hue, qreal *sat, qreal *luma) const { QVector channelValues(4); LCHToLab(*luma, *sat, *hue, &channelValues[0],&channelValues[1],&channelValues[2]); channelValues[3]=1.0; return channelValues; } void LabF32ColorSpace::toYUV(const QVector &channelValues, qreal *y, qreal *u, qreal *v) const { *y =channelValues[0]; *u=channelValues[1]; *v=channelValues[2]; } QVector LabF32ColorSpace::fromYUV(qreal *y, qreal *u, qreal *v) const { QVector channelValues(4); channelValues[0]=*y; channelValues[1]=*u; channelValues[2]=*v; channelValues[3]=1.0; return channelValues; } quint8 LabF32ColorSpace::scaleToU8(const quint8 * srcPixel, qint32 channelIndex) const { typename ColorSpaceTraits::channels_type c = ColorSpaceTraits::nativeArray(srcPixel)[channelIndex]; qreal b = 0; switch (channelIndex) { case ColorSpaceTraits::L_pos: - b = c / ColorSpaceTraits::math_trait::unitValueL; + b = ((qreal)c) / ColorSpaceTraits::math_trait::unitValueL; + break; case ColorSpaceTraits::a_pos: case ColorSpaceTraits::b_pos: if (c <= ColorSpaceTraits::math_trait::halfValueAB) { b = ((qreal)c - ColorSpaceTraits::math_trait::zeroValueAB) / (2.0 * (ColorSpaceTraits::math_trait::halfValueAB - ColorSpaceTraits::math_trait::zeroValueAB)); } else { b = 0.5 + ((qreal)c - ColorSpaceTraits::math_trait::halfValueAB) / (2.0 * (ColorSpaceTraits::math_trait::unitValueAB - ColorSpaceTraits::math_trait::halfValueAB)); } break; default: - b = (c / ColorSpaceTraits::math_trait::unitValue); + b = ((qreal)c) / ColorSpaceTraits::math_trait::unitValue; break; } return KoColorSpaceMaths::scaleToA(b); } void LabF32ColorSpace::convertChannelToVisualRepresentation(const quint8 *src, quint8 *dst, quint32 nPixels, const QBitArray selectedChannels, bool singleChannelAsColor) const { if (selectedChannels.count(true) == 1 && !singleChannelAsColor) { int selectedChannelPos = 0; for (int i = 0; i < selectedChannels.size(); ++i) { KoChannelInfo *channel = this->channels().at(i); if (selectedChannels.testBit(i) && channel->channelType() == KoChannelInfo::COLOR) { selectedChannelPos = i; } } for (uint pixelIndex = 0; pixelIndex < nPixels; ++pixelIndex) { for (uint channelIndex = 0; channelIndex < this->channelCount(); ++channelIndex) { KoChannelInfo *channel = this->channels().at(channelIndex); qint32 channelSize = channel->size(); if (channel->channelType() == KoChannelInfo::COLOR) { if (channelIndex == ColorSpaceTraits::L_pos) { memcpy(dst + (pixelIndex * ColorSpaceTraits::pixelSize) + (channelIndex * channelSize), src + (pixelIndex * ColorSpaceTraits::pixelSize) + selectedChannelPos, channelSize); } else { reinterpret_cast(dst + (pixelIndex * ColorSpaceTraits::pixelSize) + (channelIndex * channelSize))[0] = ColorSpaceTraits::math_trait::halfValueAB; } } else if (channel->channelType() == KoChannelInfo::ALPHA) { memcpy(dst + (pixelIndex * ColorSpaceTraits::pixelSize) + (channelIndex * channelSize), src + (pixelIndex * ColorSpaceTraits::pixelSize) + (channelIndex * channelSize), channelSize); } } } } else { for (uint pixelIndex = 0; pixelIndex < nPixels; ++pixelIndex) { for (uint channelIndex = 0; channelIndex < this->channelCount(); ++channelIndex) { KoChannelInfo *channel = this->channels().at(channelIndex); qint32 channelSize = channel->size(); if (selectedChannels.testBit(channelIndex)) { memcpy(dst + (pixelIndex * ColorSpaceTraits::pixelSize) + (channelIndex * channelSize), src + (pixelIndex * ColorSpaceTraits::pixelSize) + (channelIndex * channelSize), channelSize); } else { ColorSpaceTraits::channels_type v; switch (channelIndex) { case ColorSpaceTraits::L_pos: v = ColorSpaceTraits::math_trait::halfValueL; break; case ColorSpaceTraits::a_pos: case ColorSpaceTraits::b_pos: v = ColorSpaceTraits::math_trait::halfValueAB; break; default: v = ColorSpaceTraits::math_trait::zeroValue; break; } reinterpret_cast(dst + (pixelIndex * ColorSpaceTraits::pixelSize) + (channelIndex * channelSize))[0] = v; } } } } } diff --git a/plugins/color/lcms2engine/colorspaces/lab_u16/LabColorSpace.cpp b/plugins/color/lcms2engine/colorspaces/lab_u16/LabColorSpace.cpp index 85b2c02591..203277e666 100644 --- a/plugins/color/lcms2engine/colorspaces/lab_u16/LabColorSpace.cpp +++ b/plugins/color/lcms2engine/colorspaces/lab_u16/LabColorSpace.cpp @@ -1,222 +1,223 @@ /* * Copyright (c) 2006 Cyrille Berger * * 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 * Library 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. */ #include "LabColorSpace.h" #include #include #include "../compositeops/KoCompositeOps.h" #include #include LabU16ColorSpace::LabU16ColorSpace(const QString &name, KoColorProfile *p) : LcmsColorSpace(colorSpaceId(), name, TYPE_LABA_16, cmsSigLabData, p) { addChannel(new KoChannelInfo(i18n("Lightness"), 0 * sizeof(quint16), 0, KoChannelInfo::COLOR, KoChannelInfo::UINT16, sizeof(quint16), QColor(100, 100, 100))); addChannel(new KoChannelInfo(i18n("a*"), 1 * sizeof(quint16), 1, KoChannelInfo::COLOR, KoChannelInfo::UINT16, sizeof(quint16), QColor(150, 150, 150))); addChannel(new KoChannelInfo(i18n("b*"), 2 * sizeof(quint16), 2, KoChannelInfo::COLOR, KoChannelInfo::UINT16, sizeof(quint16), QColor(200, 200, 200))); addChannel(new KoChannelInfo(i18n("Alpha"), 3 * sizeof(quint16), 3, KoChannelInfo::ALPHA, KoChannelInfo::UINT16, sizeof(quint16))); init(); addStandardCompositeOps(this); } bool LabU16ColorSpace::willDegrade(ColorSpaceIndependence independence) const { if (independence == TO_RGBA8) { return true; } else { return false; } } KoColorSpace *LabU16ColorSpace::clone() const { return new LabU16ColorSpace(name(), profile()->clone()); } void LabU16ColorSpace::colorToXML(const quint8 *pixel, QDomDocument &doc, QDomElement &colorElt) const { const KoLabU16Traits::Pixel *p = reinterpret_cast(pixel); QDomElement labElt = doc.createElement("Lab"); qreal a, b; if (p->a <= KoLabColorSpaceMathsTraits::halfValueAB) { a = (p->a - KoLabColorSpaceMathsTraits::zeroValueAB) / (2.0 * (KoLabColorSpaceMathsTraits::halfValueAB - KoLabColorSpaceMathsTraits::zeroValueAB)); } else { a = 0.5 + (p->a - KoLabColorSpaceMathsTraits::halfValueAB) / (2.0 * (KoLabColorSpaceMathsTraits::unitValueAB - KoLabColorSpaceMathsTraits::halfValueAB)); } if (p->b <= KoLabColorSpaceMathsTraits::halfValueAB) { b = (p->b - KoLabColorSpaceMathsTraits::zeroValueAB) / (2.0 * (KoLabColorSpaceMathsTraits::halfValueAB - KoLabColorSpaceMathsTraits::zeroValueAB)); } else { b = 0.5 + (p->b - KoLabColorSpaceMathsTraits::halfValueAB) / (2.0 * (KoLabColorSpaceMathsTraits::unitValueAB - KoLabColorSpaceMathsTraits::halfValueAB)); } labElt.setAttribute("L", KisDomUtils::toString(KoColorSpaceMaths::scaleToA(p->L))); labElt.setAttribute("a", KisDomUtils::toString(a)); labElt.setAttribute("b", KisDomUtils::toString(b)); labElt.setAttribute("space", profile()->name()); colorElt.appendChild(labElt); } void LabU16ColorSpace::colorFromXML(quint8 *pixel, const QDomElement &elt) const { KoLabU16Traits::Pixel *p = reinterpret_cast(pixel); double a = KisDomUtils::toDouble(elt.attribute("a")); double b = KisDomUtils::toDouble(elt.attribute("b")); p->L = KoColorSpaceMaths::scaleToA(KisDomUtils::toDouble(elt.attribute("L"))); if (a <= 0.5) { p->a = KoLabColorSpaceMathsTraits::zeroValueAB + 2.0 * a * (KoLabColorSpaceMathsTraits::halfValueAB - KoLabColorSpaceMathsTraits::zeroValueAB); } else { p->a = (KoLabColorSpaceMathsTraits::halfValueAB + 2.0 * (a - 0.5) * (KoLabColorSpaceMathsTraits::unitValueAB - KoLabColorSpaceMathsTraits::halfValueAB)); } if (b <= 0.5) { p->b = KoLabColorSpaceMathsTraits::zeroValueAB + 2.0 * b * (KoLabColorSpaceMathsTraits::halfValueAB - KoLabColorSpaceMathsTraits::zeroValueAB); } else { p->b = (KoLabColorSpaceMathsTraits::halfValueAB + 2.0 * (b - 0.5) * (KoLabColorSpaceMathsTraits::unitValueAB - KoLabColorSpaceMathsTraits::halfValueAB)); } p->alpha = KoColorSpaceMathsTraits::max; } void LabU16ColorSpace::toHSY(const QVector &channelValues, qreal *hue, qreal *sat, qreal *luma) const { LabToLCH(channelValues[0],channelValues[1],channelValues[2], luma, sat, hue); } QVector LabU16ColorSpace::fromHSY(qreal *hue, qreal *sat, qreal *luma) const { QVector channelValues(4); LCHToLab(*luma, *sat, *hue, &channelValues[0],&channelValues[1],&channelValues[2]); channelValues[3]=1.0; return channelValues; } void LabU16ColorSpace::toYUV(const QVector &channelValues, qreal *y, qreal *u, qreal *v) const { *y =channelValues[0]; *u=channelValues[1]; *v=channelValues[2]; } QVector LabU16ColorSpace::fromYUV(qreal *y, qreal *u, qreal *v) const { QVector channelValues(4); channelValues[0]=*y; channelValues[1]=*u; channelValues[2]=*v; channelValues[3]=1.0; return channelValues; } quint8 LabU16ColorSpace::scaleToU8(const quint8 *srcPixel, qint32 channelIndex) const { typename ColorSpaceTraits::channels_type c = ColorSpaceTraits::nativeArray(srcPixel)[channelIndex]; qreal b = 0; switch (channelIndex) { case ColorSpaceTraits::L_pos: - b = c / ColorSpaceTraits::math_trait::unitValueL; + b = ((qreal)c) / ColorSpaceTraits::math_trait::unitValueL; + break; case ColorSpaceTraits::a_pos: case ColorSpaceTraits::b_pos: if (c <= ColorSpaceTraits::math_trait::halfValueAB) { b = ((qreal)c - ColorSpaceTraits::math_trait::zeroValueAB) / (2.0 * (ColorSpaceTraits::math_trait::halfValueAB - ColorSpaceTraits::math_trait::zeroValueAB)); } else { b = 0.5 + ((qreal)c - ColorSpaceTraits::math_trait::halfValueAB) / (2.0 * (ColorSpaceTraits::math_trait::unitValueAB - ColorSpaceTraits::math_trait::halfValueAB)); } break; default: - b = (c / ColorSpaceTraits::math_trait::unitValue); + b = ((qreal)c) / ColorSpaceTraits::math_trait::unitValue; break; } return KoColorSpaceMaths::scaleToA(b); } void LabU16ColorSpace::convertChannelToVisualRepresentation(const quint8 *src, quint8 *dst, quint32 nPixels, const QBitArray selectedChannels, bool singleChannelAsColor) const { if (selectedChannels.count(true) == 1 && !singleChannelAsColor) { int selectedChannelPos = 0; for (int i = 0; i < selectedChannels.size(); ++i) { KoChannelInfo *channel = this->channels().at(i); if (selectedChannels.testBit(i) && channel->channelType() == KoChannelInfo::COLOR) { selectedChannelPos = i; } } for (uint pixelIndex = 0; pixelIndex < nPixels; ++pixelIndex) { for (uint channelIndex = 0; channelIndex < this->channelCount(); ++channelIndex) { KoChannelInfo *channel = this->channels().at(channelIndex); qint32 channelSize = channel->size(); if (channel->channelType() == KoChannelInfo::COLOR) { if (channelIndex == ColorSpaceTraits::L_pos) { memcpy(dst + (pixelIndex * ColorSpaceTraits::pixelSize) + (channelIndex * channelSize), src + (pixelIndex * ColorSpaceTraits::pixelSize) + selectedChannelPos, channelSize); } else { reinterpret_cast(dst + (pixelIndex * ColorSpaceTraits::pixelSize) + (channelIndex * channelSize))[0] = ColorSpaceTraits::math_trait::halfValueAB; } } else if (channel->channelType() == KoChannelInfo::ALPHA) { memcpy(dst + (pixelIndex * ColorSpaceTraits::pixelSize) + (channelIndex * channelSize), src + (pixelIndex * ColorSpaceTraits::pixelSize) + (channelIndex * channelSize), channelSize); } } } } else { for (uint pixelIndex = 0; pixelIndex < nPixels; ++pixelIndex) { for (uint channelIndex = 0; channelIndex < this->channelCount(); ++channelIndex) { KoChannelInfo *channel = this->channels().at(channelIndex); qint32 channelSize = channel->size(); if (selectedChannels.testBit(channelIndex)) { memcpy(dst + (pixelIndex * ColorSpaceTraits::pixelSize) + (channelIndex * channelSize), src + (pixelIndex * ColorSpaceTraits::pixelSize) + (channelIndex * channelSize), channelSize); } else { ColorSpaceTraits::channels_type v; switch (channelIndex) { case ColorSpaceTraits::L_pos: v = ColorSpaceTraits::math_trait::halfValueL; break; case ColorSpaceTraits::a_pos: case ColorSpaceTraits::b_pos: v = ColorSpaceTraits::math_trait::halfValueAB; break; default: v = ColorSpaceTraits::math_trait::zeroValue; break; } reinterpret_cast(dst + (pixelIndex * ColorSpaceTraits::pixelSize) + (channelIndex * channelSize))[0] = v; } } } } } diff --git a/plugins/color/lcms2engine/colorspaces/lab_u8/LabU8ColorSpace.cpp b/plugins/color/lcms2engine/colorspaces/lab_u8/LabU8ColorSpace.cpp index 634ee0564d..a6533c1859 100644 --- a/plugins/color/lcms2engine/colorspaces/lab_u8/LabU8ColorSpace.cpp +++ b/plugins/color/lcms2engine/colorspaces/lab_u8/LabU8ColorSpace.cpp @@ -1,217 +1,218 @@ /* * Copyright (c) 2006 Cyrille Berger * * 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 * Library 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. */ #include "LabU8ColorSpace.h" #include #include #include "../compositeops/KoCompositeOps.h" #include #include LabU8ColorSpace::LabU8ColorSpace(const QString &name, KoColorProfile *p) : LcmsColorSpace(colorSpaceId(), name, TYPE_LABA_8, cmsSigLabData, p) { addChannel(new KoChannelInfo(i18n("Lightness"), 0 * sizeof(quint8), 0, KoChannelInfo::COLOR, KoChannelInfo::UINT8, sizeof(quint8), QColor(100, 100, 100))); addChannel(new KoChannelInfo(i18n("a*"), 1 * sizeof(quint8), 1, KoChannelInfo::COLOR, KoChannelInfo::UINT8, sizeof(quint8), QColor(150, 150, 150))); addChannel(new KoChannelInfo(i18n("b*"), 2 * sizeof(quint8), 2, KoChannelInfo::COLOR, KoChannelInfo::UINT8, sizeof(quint8), QColor(200, 200, 200))); addChannel(new KoChannelInfo(i18n("Alpha"), 3 * sizeof(quint8), 3, KoChannelInfo::ALPHA, KoChannelInfo::UINT8, sizeof(quint8))); init(); addStandardCompositeOps(this); } bool LabU8ColorSpace::willDegrade(ColorSpaceIndependence /*independence*/) const { return false; } KoColorSpace *LabU8ColorSpace::clone() const { return new LabU8ColorSpace(name(), profile()->clone()); } void LabU8ColorSpace::colorToXML(const quint8 *pixel, QDomDocument &doc, QDomElement &colorElt) const { const KoLabU8Traits::Pixel *p = reinterpret_cast(pixel); QDomElement labElt = doc.createElement("Lab"); double a, b; if (p->a <= KoLabColorSpaceMathsTraits::halfValueAB) { a = (p->a - KoLabColorSpaceMathsTraits::zeroValueAB) / (2.0 * (KoLabColorSpaceMathsTraits::halfValueAB - KoLabColorSpaceMathsTraits::zeroValueAB)); } else { a = 0.5 + (p->a - KoLabColorSpaceMathsTraits::halfValueAB) / (2.0 * (KoLabColorSpaceMathsTraits::unitValueAB - KoLabColorSpaceMathsTraits::halfValueAB)); } if (p->b <= KoLabColorSpaceMathsTraits::halfValueAB) { b = (p->b - KoLabColorSpaceMathsTraits::zeroValueAB) / (2.0 * (KoLabColorSpaceMathsTraits::halfValueAB - KoLabColorSpaceMathsTraits::zeroValueAB)); } else { b = 0.5 + (p->b - KoLabColorSpaceMathsTraits::halfValueAB) / (2.0 * (KoLabColorSpaceMathsTraits::unitValueAB - KoLabColorSpaceMathsTraits::halfValueAB)); } labElt.setAttribute("L", KisDomUtils::toString(KoColorSpaceMaths::scaleToA(p->L))); labElt.setAttribute("a", KisDomUtils::toString(a)); labElt.setAttribute("b", KisDomUtils::toString(b)); labElt.setAttribute("space", profile()->name()); colorElt.appendChild(labElt); } void LabU8ColorSpace::colorFromXML(quint8 *pixel, const QDomElement &elt) const { KoLabU8Traits::Pixel *p = reinterpret_cast(pixel); double a = KisDomUtils::toDouble(elt.attribute("a")); double b = KisDomUtils::toDouble(elt.attribute("b")); p->L = KoColorSpaceMaths::scaleToA(KisDomUtils::toDouble(elt.attribute("L"))); if (a <= 0.5) { p->a = KoLabColorSpaceMathsTraits::zeroValueAB + 2.0 * a * (KoLabColorSpaceMathsTraits::halfValueAB - KoLabColorSpaceMathsTraits::zeroValueAB); } else { p->a = (KoLabColorSpaceMathsTraits::halfValueAB + 2.0 * (a - 0.5) * (KoLabColorSpaceMathsTraits::unitValueAB - KoLabColorSpaceMathsTraits::halfValueAB)); } if (b <= 0.5) { p->b = KoLabColorSpaceMathsTraits::zeroValueAB + 2.0 * b * (KoLabColorSpaceMathsTraits::halfValueAB - KoLabColorSpaceMathsTraits::zeroValueAB); } else { p->b = (KoLabColorSpaceMathsTraits::halfValueAB + 2.0 * (b - 0.5) * (KoLabColorSpaceMathsTraits::unitValueAB - KoLabColorSpaceMathsTraits::halfValueAB)); } p->alpha = KoColorSpaceMathsTraits::max; } void LabU8ColorSpace::toHSY(const QVector &channelValues, qreal *hue, qreal *sat, qreal *luma) const { LabToLCH(channelValues[0],channelValues[1],channelValues[2], luma, sat, hue); } QVector LabU8ColorSpace::fromHSY(qreal *hue, qreal *sat, qreal *luma) const { QVector channelValues(4); LCHToLab(*luma, *sat, *hue, &channelValues[0],&channelValues[1],&channelValues[2]); channelValues[3]=1.0; return channelValues; } void LabU8ColorSpace::toYUV(const QVector &channelValues, qreal *y, qreal *u, qreal *v) const { *y =channelValues[0]; *u=channelValues[1]; *v=channelValues[2]; } QVector LabU8ColorSpace::fromYUV(qreal *y, qreal *u, qreal *v) const { QVector channelValues(4); channelValues[0]=*y; channelValues[1]=*u; channelValues[2]=*v; channelValues[3]=1.0; return channelValues; } quint8 LabU8ColorSpace::scaleToU8(const quint8 *srcPixel, qint32 channelIndex) const { typename ColorSpaceTraits::channels_type c = ColorSpaceTraits::nativeArray(srcPixel)[channelIndex]; qreal b = 0; switch (channelIndex) { case ColorSpaceTraits::L_pos: - b = c / ColorSpaceTraits::math_trait::unitValueL; + b = ((qreal)c) / ColorSpaceTraits::math_trait::unitValueL; + break; case ColorSpaceTraits::a_pos: case ColorSpaceTraits::b_pos: if (c <= ColorSpaceTraits::math_trait::halfValueAB) { b = ((qreal)c - ColorSpaceTraits::math_trait::zeroValueAB) / (2.0 * (ColorSpaceTraits::math_trait::halfValueAB - ColorSpaceTraits::math_trait::zeroValueAB)); } else { b = 0.5 + ((qreal)c - ColorSpaceTraits::math_trait::halfValueAB) / (2.0 * (ColorSpaceTraits::math_trait::unitValueAB - ColorSpaceTraits::math_trait::halfValueAB)); } break; default: - b = (c / ColorSpaceTraits::math_trait::unitValue); + b = ((qreal)c) / ColorSpaceTraits::math_trait::unitValue; break; } return KoColorSpaceMaths::scaleToA(b); } void LabU8ColorSpace::convertChannelToVisualRepresentation(const quint8 *src, quint8 *dst, quint32 nPixels, const QBitArray selectedChannels, bool singleChannelAsColor) const { if (selectedChannels.count(true) == 1 && !singleChannelAsColor) { int selectedChannelPos = 0; for (int i = 0; i < selectedChannels.size(); ++i) { KoChannelInfo *channel = this->channels().at(i); if (selectedChannels.testBit(i) && channel->channelType() == KoChannelInfo::COLOR) { selectedChannelPos = i; } } for (uint pixelIndex = 0; pixelIndex < nPixels; ++pixelIndex) { for (uint channelIndex = 0; channelIndex < this->channelCount(); ++channelIndex) { KoChannelInfo *channel = this->channels().at(channelIndex); qint32 channelSize = channel->size(); if (channel->channelType() == KoChannelInfo::COLOR) { if (channelIndex == ColorSpaceTraits::L_pos) { memcpy(dst + (pixelIndex * ColorSpaceTraits::pixelSize) + (channelIndex * channelSize), src + (pixelIndex * ColorSpaceTraits::pixelSize) + selectedChannelPos, channelSize); } else { reinterpret_cast(dst + (pixelIndex * ColorSpaceTraits::pixelSize) + (channelIndex * channelSize))[0] = ColorSpaceTraits::math_trait::halfValueAB; } } else if (channel->channelType() == KoChannelInfo::ALPHA) { memcpy(dst + (pixelIndex * ColorSpaceTraits::pixelSize) + (channelIndex * channelSize), src + (pixelIndex * ColorSpaceTraits::pixelSize) + (channelIndex * channelSize), channelSize); } } } } else { for (uint pixelIndex = 0; pixelIndex < nPixels; ++pixelIndex) { for (uint channelIndex = 0; channelIndex < this->channelCount(); ++channelIndex) { KoChannelInfo *channel = this->channels().at(channelIndex); qint32 channelSize = channel->size(); if (selectedChannels.testBit(channelIndex)) { memcpy(dst + (pixelIndex * ColorSpaceTraits::pixelSize) + (channelIndex * channelSize), src + (pixelIndex * ColorSpaceTraits::pixelSize) + (channelIndex * channelSize), channelSize); } else { ColorSpaceTraits::channels_type v; switch (channelIndex) { case ColorSpaceTraits::L_pos: v = ColorSpaceTraits::math_trait::halfValueL; break; case ColorSpaceTraits::a_pos: case ColorSpaceTraits::b_pos: v = ColorSpaceTraits::math_trait::halfValueAB; break; default: v = ColorSpaceTraits::math_trait::zeroValue; break; } reinterpret_cast(dst + (pixelIndex * ColorSpaceTraits::pixelSize) + (channelIndex * channelSize))[0] = v; } } } } }