diff --git a/plugins/color/lcms2engine/colorspaces/lab_f32/LabF32ColorSpace.cpp b/plugins/color/lcms2engine/colorspaces/lab_f32/LabF32ColorSpace.cpp index 521046594d..6ba6392f04 100644 --- a/plugins/color/lcms2engine/colorspaces/lab_f32/LabF32ColorSpace.cpp +++ b/plugins/color/lcms2engine/colorspaces/lab_f32/LabF32ColorSpace.cpp @@ -1,173 +1,196 @@ /* * 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; + 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); + 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_f32/LabF32ColorSpace.h b/plugins/color/lcms2engine/colorspaces/lab_f32/LabF32ColorSpace.h index af3327a0da..b85c8d44bf 100644 --- a/plugins/color/lcms2engine/colorspaces/lab_f32/LabF32ColorSpace.h +++ b/plugins/color/lcms2engine/colorspaces/lab_f32/LabF32ColorSpace.h @@ -1,123 +1,124 @@ /* * 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. */ #ifndef LabF32ColorSpace_H_ #define LabF32ColorSpace_H_ #include "LcmsColorSpace.h" #include "KoColorModelStandardIds.h" // XXX: implement normalizedChannelValues? struct KoLabF32Traits; class LabF32ColorSpace : public LcmsColorSpace { public: LabF32ColorSpace(const QString &name, KoColorProfile *p); bool willDegrade(ColorSpaceIndependence independence) const override; static QString colorSpaceId() { return QString("LABAF32"); } KoID colorModelId() const override { return LABAColorModelID; } KoID colorDepthId() const override { return Float32BitsColorDepthID; } virtual KoColorSpace *clone() const; void colorToXML(const quint8 *pixel, QDomDocument &doc, QDomElement &colorElt) const override; void colorFromXML(quint8* pixel, const QDomElement& elt) 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; + quint8 scaleToU8(const quint8 * srcPixel, qint32 channelIndex) const override; void convertChannelToVisualRepresentation(const quint8 *src, quint8 *dst, quint32 nPixels, const QBitArray selectedChannels, bool singleChannelAsColor) const override; bool hasHighDynamicRange() const override { return true; } }; class LabF32ColorSpaceFactory : public LcmsColorSpaceFactory { public: LabF32ColorSpaceFactory() : LcmsColorSpaceFactory(TYPE_LabA_FLT, cmsSigLabData) { } bool userVisible() const override { return true; } QString id() const override { return LabF32ColorSpace::colorSpaceId(); } QString name() const override { return QString("%1 (%2)").arg(LABAColorModelID.name()).arg(Float32BitsColorDepthID.name()); } KoID colorModelId() const override { return LABAColorModelID; } KoID colorDepthId() const override { return Float32BitsColorDepthID; } int referenceDepth() const override { return 32; } KoColorSpace *createColorSpace(const KoColorProfile *p) const override { return new LabF32ColorSpace(name(), p->clone()); } QString defaultProfile() const override { return "Lab identity built-in"; } bool isHdr() const override { return true; } }; #endif