Git commit 774e5b763f0c48e4185d9d47619c3e89f58a1a70 by Boudewijn Rempt. Committed on 07/12/2016 at 09:48. Pushed by rempt into branch 'krita/3.1'. D3525: Fix floating point Lab Even for floating point lab the unit value should be 0-100, -128-127, -128-127 M +291 -0 libs/pigment/KoLabColorSpaceTraits.h https://commits.kde.org/krita/774e5b763f0c48e4185d9d47619c3e89f58a1a70 diff --git a/libs/pigment/KoLabColorSpaceTraits.h b/libs/pigment/KoLabColor= SpaceTraits.h index 1cc4ce0a6cd..43eb0f72a7b 100644 --- a/libs/pigment/KoLabColorSpaceTraits.h +++ b/libs/pigment/KoLabColorSpaceTraits.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2006-2007 Cyrille Berger + * Copyright (c) 2016 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 @@ -84,26 +85,316 @@ struct KoLabTraits : public KoColorSpaceTrait<_channel= s_type_, 4, 3> { } }; = +//For quint* values must range from 0 to 1 - see KoColorSpaceMaths = struct KoLabU8Traits : public KoLabTraits { + + static const quint32 MAX_CHANNEL_L =3D 100; + static const quint32 MAX_CHANNEL_AB =3D 255; + static const quint32 CHANNEL_AB_ZERO_OFFSET =3D 128; + + inline static void normalisedChannelsValue(const quint8 *pixel, QVecto= r &channels) { + Q_ASSERT((int)channels.count() =3D=3D (int)parent::channels_nb); + channels_type c; + for (uint i =3D 0; i < parent::channels_nb; i++) { + c =3D nativeArray(pixel)[i]; + switch (i) { + case L_pos: + channels[i] =3D ((qreal)c) / MAX_CHANNEL_L; + break; + case a_pos: + channels[i] =3D (((qreal)c) - CHANNEL_AB_ZERO_OFFSET) / MA= X_CHANNEL_AB; + break; + case b_pos: + channels[i] =3D (((qreal)c) - CHANNEL_AB_ZERO_OFFSET) / MA= X_CHANNEL_AB; + break; + case 3: + channels[i] =3D ((qreal)c) / UINT16_MAX; + break; + default: + channels[i] =3D ((qreal)c) / KoColorSpaceMathsTraits::unitValue; + break; + } + } + } + + inline static QString normalisedChannelValueText(const quint8 *pixel, = quint32 channelIndex) { + if (channelIndex > parent::channels_nb) return QString("Error"); + channels_type c =3D nativeArray(pixel)[channelIndex]; + switch (channelIndex) { + case L_pos: + return QString().setNum(100.0 * ((qreal)c) / MAX_CHANNEL_L); + case a_pos: + return QString().setNum(100.0 * ((((qreal)c) - CHANNEL_AB_ZERO= _OFFSET) / MAX_CHANNEL_AB)); + case b_pos: + return QString().setNum(100.0 * ((((qreal)c) - CHANNEL_AB_ZERO= _OFFSET) / MAX_CHANNEL_AB)); + case 3: + return QString().setNum(100.0 * ((qreal)c) / UINT16_MAX); + default: + return QString("Error"); + } + } + + inline static void fromNormalisedChannelsValue(quint8 *pixel, const QV= ector &values) { + Q_ASSERT((int)values.count() =3D=3D (int)parent::channels_nb); + channels_type c; + for (uint i =3D 0; i < channels_nb; i++) { + float b =3D 0; + + switch (i) { + case L_pos: + b =3D qBound((float)0, + (float)MAX_CHANNEL_L * values[i], + (float)MAX_CHANNEL_L); + break; + case a_pos: + case b_pos: + b =3D qBound((float)0, + (float)MAX_CHANNEL_AB * values[i], + (float)MAX_CHANNEL_AB); + break; + default: + b =3D qBound((float)KoColorSpaceMathsTraits= ::min, + (float)KoColorSpaceMathsTraits::= unitValue * values[i], + (float)KoColorSpaceMathsTraits::= max); + break; + } + c =3D (channels_type)b; + nativeArray(pixel)[i] =3D c; + } + } }; = struct KoLabU16Traits : public KoLabTraits { + // https://github.com/mm2/Little-CMS/blob/master/src/cmspcs.c + static const quint32 MAX_CHANNEL_L =3D 0xFF00; + static const quint32 MAX_CHANNEL_AB =3D 0xFFFF; + static const quint32 CHANNEL_AB_ZERO_OFFSET =3D 0x8000; + + inline static void normalisedChannelsValue(const quint8 *pixel, QVecto= r &channels) { + Q_ASSERT((int)channels.count() =3D=3D (int)parent::channels_nb); + channels_type c; + for (uint i =3D 0; i < parent::channels_nb; i++) { + c =3D nativeArray(pixel)[i]; + switch (i) { + case L_pos: + channels[i] =3D ((qreal)c) / MAX_CHANNEL_L; + break; + case a_pos: + channels[i] =3D (((qreal)c) - CHANNEL_AB_ZERO_OFFSET) / MA= X_CHANNEL_AB; + break; + case b_pos: + channels[i] =3D (((qreal)c) - CHANNEL_AB_ZERO_OFFSET) / MA= X_CHANNEL_AB; + break; + case 3: + channels[i] =3D ((qreal)c) / UINT16_MAX; + break; + default: + channels[i] =3D ((qreal)c) / KoColorSpaceMathsTraits::unitValue; + break; + } + } + } + + inline static QString normalisedChannelValueText(const quint8 *pixel, = quint32 channelIndex) { + if (channelIndex > parent::channels_nb) return QString("Error"); + channels_type c =3D nativeArray(pixel)[channelIndex]; + switch (channelIndex) { + case L_pos: + return QString().setNum(100.0 * ((qreal)c) / MAX_CHANNEL_L); + case a_pos: + return QString().setNum(100.0 * ((((qreal)c) - CHANNEL_AB_ZERO= _OFFSET) / MAX_CHANNEL_AB)); + case b_pos: + return QString().setNum(100.0 * ((((qreal)c) - CHANNEL_AB_ZERO= _OFFSET) / MAX_CHANNEL_AB)); + case 3: + return QString().setNum(100.0 * ((qreal)c) / UINT16_MAX); + default: + return QString("Error"); + } + } + + inline static void fromNormalisedChannelsValue(quint8 *pixel, const QV= ector &values) { + Q_ASSERT((int)values.count() =3D=3D (int)parent::channels_nb); + channels_type c; + for (uint i =3D 0; i < channels_nb; i++) { + float b =3D 0; + + switch (i) { + case L_pos: + b =3D qBound((float)0, + (float)MAX_CHANNEL_L * values[i], + (float)MAX_CHANNEL_L); + break; + case a_pos: + case b_pos: + b =3D qBound((float)0, + (float)MAX_CHANNEL_AB * values[i], + (float)MAX_CHANNEL_AB); + break; + default: + b =3D qBound((float)KoColorSpaceMathsTraits= ::min, + (float)KoColorSpaceMathsTraits::= unitValue * values[i], + (float)KoColorSpaceMathsTraits::= max); + break; + } + c =3D (channels_type)b; + nativeArray(pixel)[i] =3D c; + } + } }; = +// Float values are not normalised +// XXX: is it really necessary to bind them to these ranges? + #include #ifdef HAVE_OPENEXR #include = struct KoLabF16Traits : public KoLabTraits { + static constexpr float MIN_CHANNEL_L =3D 0; + static constexpr float MAX_CHANNEL_L =3D 100; + static constexpr float MIN_CHANNEL_AB =3D -128; + static constexpr float MAX_CHANNEL_AB =3D +127; + + // Lab has some... particulars + // For instance, float et al. are NOT normalised + inline static QString normalisedChannelValueText(const quint8 *pixel, = quint32 channelIndex) { + return channelValueText(pixel, channelIndex); + } + inline static void normalisedChannelsValue(const quint8 *pixel, QVecto= r &channels) { + Q_ASSERT((int)channels.count() =3D=3D (int)parent::channels_nb); + channels_type c; + for (uint i =3D 0; i < parent::channels_nb; i++) { + c =3D parent::nativeArray(pixel)[i]; + channels[i] =3D (qreal)c; + } + } + inline static void fromNormalisedChannelsValue(quint8 *pixel, const QV= ector &values) { + Q_ASSERT((int)values.count() =3D=3D (int)parent::channels_nb); + channels_type c; + for (uint i =3D 0; i < parent::channels_nb; i++) { + float b =3D 0; + switch(i) { + case L_pos: + b =3D qBound((float)MIN_CHANNEL_L, + (float)KoColorSpaceMathsTraits::unitValue= * values[i], + (float)MAX_CHANNEL_L); + break; + case a_pos: + case b_pos: + b =3D qBound((float)MIN_CHANNEL_AB, + (float)KoColorSpaceMathsTraits::unitValue= * values[i], + (float)MAX_CHANNEL_AB); + break; + case 3: + b =3D qBound((float)KoColorSpaceMathsTraits::min, + (float)KoColorSpaceMathsTraits::unitValue= * values[i], + (float)KoColorSpaceMathsTraits::max); + default: + break; + } + c =3D (channels_type)b; + parent::nativeArray(pixel)[i] =3D c; + } + } }; = #endif = struct KoLabF32Traits : public KoLabTraits { + static constexpr float MIN_CHANNEL_L =3D 0; + static constexpr float MAX_CHANNEL_L =3D 100; + static constexpr float MIN_CHANNEL_AB =3D -128; + static constexpr float MAX_CHANNEL_AB =3D +127; + + // Lab has some... particulars + inline static QString normalisedChannelValueText(const quint8 *pixel, = quint32 channelIndex) { + return channelValueText(pixel, channelIndex); + } + inline static void normalisedChannelsValue(const quint8 *pixel, QVecto= r &channels) { + Q_ASSERT((int)channels.count() =3D=3D (int)parent::channels_nb); + channels_type c; + for (uint i =3D 0; i < parent::channels_nb; i++) { + c =3D parent::nativeArray(pixel)[i]; + channels[i] =3D (qreal)c; + } + } + inline static void fromNormalisedChannelsValue(quint8 *pixel, const QV= ector &values) { + Q_ASSERT((int)values.count() =3D=3D (int)parent::channels_nb); + channels_type c; + for (uint i =3D 0; i < parent::channels_nb; i++) { + float b =3D 0; + switch(i) { + case L_pos: + b =3D qBound((float)MIN_CHANNEL_L, + (float)KoColorSpaceMathsTraits::unitValu= e * values[i], + (float)MAX_CHANNEL_L); + break; + case a_pos: + case b_pos: + b =3D qBound((float)MIN_CHANNEL_AB, + (float)KoColorSpaceMathsTraits::unitValu= e * values[i], + (float)MAX_CHANNEL_AB); + break; + case 3: + b =3D qBound((float)KoColorSpaceMathsTraits::min, + (float)KoColorSpaceMathsTraits::unitValu= e * values[i], + (float)KoColorSpaceMathsTraits::max); + default: + break; + } + c =3D (channels_type)b; + parent::nativeArray(pixel)[i] =3D c; + } + } }; = struct KoLabF64Traits : public KoLabTraits { + static constexpr double MIN_CHANNEL_L =3D 0; + static constexpr double MAX_CHANNEL_L =3D 100; + static constexpr double MIN_CHANNEL_AB =3D -128; + static constexpr double MAX_CHANNEL_AB =3D +127; + + // Lab has some... particulars + inline static QString normalisedChannelValueText(const quint8 *pixel, = quint32 channelIndex) { + return channelValueText(pixel, channelIndex); + } + inline static void normalisedChannelsValue(const quint8 *pixel, QVecto= r &channels) { + Q_ASSERT((int)channels.count() =3D=3D (int)parent::channels_nb); + channels_type c; + for (uint i =3D 0; i < parent::channels_nb; i++) { + c =3D parent::nativeArray(pixel)[i]; + channels[i] =3D (qreal)c; + } + } + inline static void fromNormalisedChannelsValue(quint8 *pixel, const QV= ector &values) { + Q_ASSERT((int)values.count() =3D=3D (int)parent::channels_nb); + channels_type c; + for (uint i =3D 0; i < parent::channels_nb; i++) { + float b =3D 0; + switch(i) { + case L_pos: + b =3D qBound((float)MIN_CHANNEL_L, + (float)KoColorSpaceMathsTraits::unitVal= ue * values[i], + (float)MAX_CHANNEL_L); + break; + case a_pos: + case b_pos: + b =3D qBound((float)MIN_CHANNEL_AB, + (float)KoColorSpaceMathsTraits::unitVal= ue * values[i], + (float)MAX_CHANNEL_AB); + break; + case 3: + b =3D qBound((float)KoColorSpaceMathsTraits::min, + (float)KoColorSpaceMathsTraits::unitVal= ue * values[i], + (float)KoColorSpaceMathsTraits::max); + default: + break; + } + c =3D (channels_type)b; + parent::nativeArray(pixel)[i] =3D c; + } + } }; = #endif