diff options
Diffstat (limited to 'chalk/chalkcolor/kis_basic_histogram_producers.cpp')
-rw-r--r-- | chalk/chalkcolor/kis_basic_histogram_producers.cpp | 484 |
1 files changed, 484 insertions, 0 deletions
diff --git a/chalk/chalkcolor/kis_basic_histogram_producers.cpp b/chalk/chalkcolor/kis_basic_histogram_producers.cpp new file mode 100644 index 000000000..a37a1fb3f --- /dev/null +++ b/chalk/chalkcolor/kis_basic_histogram_producers.cpp @@ -0,0 +1,484 @@ +/* + * Copyright (c) 2005 Bart Coppens <kde@bartcoppens.be> + * + * 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 <tqstring.h> +#include <tdelocale.h> + +#include "config.h" + +#ifdef HAVE_OPENEXR +#include <half.h> +#endif + +#include "kis_global.h" +#include "kis_basic_histogram_producers.h" +#include "kis_integer_maths.h" +#include "kis_channelinfo.h" +#include "kis_colorspace.h" +#include "kis_lab_colorspace.h" + +KisLabColorSpace* KisGenericLabHistogramProducer::m_labCs = 0; + + +KisBasicHistogramProducer::KisBasicHistogramProducer(const KisID& id, int channels, int nrOfBins, KisColorSpace *cs) + : m_channels(channels), + m_nrOfBins(nrOfBins), + m_colorSpace(cs), + m_id(id) +{ + m_bins.resize(m_channels); + for (int i = 0; i < m_channels; i++) + m_bins.at(i).resize(m_nrOfBins); + m_outLeft.resize(m_channels); + m_outRight.resize(m_channels); + m_count = 0; + m_from = 0.0; + m_width = 1.0; +} + +void KisBasicHistogramProducer::clear() { + m_count = 0; + for (int i = 0; i < m_channels; i++) { + for (int j = 0; j < m_nrOfBins; j++) { + m_bins.at(i).at(j) = 0; + } + m_outRight.at(i) = 0; + m_outLeft.at(i) = 0; + } +} + +void KisBasicHistogramProducer::makeExternalToInternal() { + // This function assumes that the pixel is has no 'gaps'. That is to say: if we start + // at byte 0, we can get to the end of the pixel by adding consecutive size()s of + // the channels + TQValueVector<KisChannelInfo *> c = channels(); + uint count = c.count(); + int currentPos = 0; + + for (uint i = 0; i < count; i++) { + for (uint j = 0; j < count; j++) { + if (c.at(j)->pos() == currentPos) { + m_external.append(j); + break; + } + } + currentPos += c.at(m_external.at(m_external.count() - 1))->size(); + } +} + +// ------------ U8 --------------------- + +KisBasicU8HistogramProducer::KisBasicU8HistogramProducer(const KisID& id, KisColorSpace *cs) + : KisBasicHistogramProducer(id, cs->nChannels(), 256, cs) +{ +} + +TQString KisBasicU8HistogramProducer::positionToString(double pos) const { + return TQString("%1").arg(static_cast<TQ_UINT8>(pos * UINT8_MAX)); +} + +void KisBasicU8HistogramProducer::addRegionToBin(TQ_UINT8 * pixels, TQ_UINT8 * selectionMask, TQ_UINT32 nPixels, KisColorSpace *cs) +{ + if (!pixels) return; + if (!cs) return; + if (nPixels == 0) return; + + TQ_INT32 pSize = cs->pixelSize(); + + if ( selectionMask ) { + while (nPixels > 0) { + if ( ! (m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT) ) { + + for (int i = 0; i < m_channels; i++) { + m_bins.at(i).at(pixels[i])++; + } + m_count++; + + } + + pixels += pSize; + selectionMask++; + nPixels--; + } + } + else { + while (nPixels > 0) { + if ( ! (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT) ) { + + for (int i = 0; i < m_channels; i++) { + m_bins.at(i).at(pixels[i])++; + } + m_count++; + + } + + pixels += pSize; + nPixels--; + } + } +} + +// ------------ U16 --------------------- + +KisBasicU16HistogramProducer::KisBasicU16HistogramProducer(const KisID& id, KisColorSpace *cs) + : KisBasicHistogramProducer(id, cs->nChannels(), 256, cs) +{ +} + +TQString KisBasicU16HistogramProducer::positionToString(double pos) const +{ + return TQString("%1").arg(static_cast<TQ_UINT8>(pos * UINT8_MAX)); +} + +double KisBasicU16HistogramProducer::maximalZoom() const +{ + return 1.0 / 255.0; +} + +void KisBasicU16HistogramProducer::addRegionToBin(TQ_UINT8 * pixels, TQ_UINT8 * selectionMask, TQ_UINT32 nPixels, KisColorSpace *cs) +{ + // The view + TQ_UINT16 from = static_cast<TQ_UINT16>(m_from * UINT16_MAX); + TQ_UINT16 width = static_cast<TQ_UINT16>(m_width * UINT16_MAX + 0.5); // We include the end + TQ_UINT16 to = from + width; + double factor = 255.0 / width; + + TQ_INT32 pSize = cs->pixelSize(); + + if ( selectionMask ) { + TQ_UINT16* pixel = reinterpret_cast<TQ_UINT16*>(pixels); + while (nPixels > 0) { + if ( ! ((m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) ) { + for (int i = 0; i < m_channels; i++) { + TQ_UINT16 value = pixel[i]; + if (value > to) + m_outRight.at(i)++; + else if (value < from) + m_outLeft.at(i)++; + else + m_bins.at(i).at(static_cast<TQ_UINT8>((value - from) * factor))++; + } + m_count++; + } + pixels += pSize; + selectionMask++; + nPixels--; + } + } + else { + while (nPixels > 0) { + TQ_UINT16* pixel = reinterpret_cast<TQ_UINT16*>(pixels); + + if ( ! (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) { + for (int i = 0; i < m_channels; i++) { + TQ_UINT16 value = pixel[i]; + if (value > to) + m_outRight.at(i)++; + else if (value < from) + m_outLeft.at(i)++; + else + m_bins.at(i).at(static_cast<TQ_UINT8>((value - from) * factor))++; + } + m_count++; + } + pixels += pSize; + nPixels--; + + } + } +} + +// ------------ Float32 --------------------- +KisBasicF32HistogramProducer::KisBasicF32HistogramProducer(const KisID& id, KisColorSpace *cs) + : KisBasicHistogramProducer(id, cs->nChannels(), 256, cs) +{ +} + +TQString KisBasicF32HistogramProducer::positionToString(double pos) const { + return TQString("%1").arg(static_cast<float>(pos)); // XXX I doubt this is correct! +} + +double KisBasicF32HistogramProducer::maximalZoom() const { + // XXX What _is_ the maximal zoom here? I don't think there is one with floats, so this seems a fine compromis for the moment + return 1.0 / 255.0; +} + +void KisBasicF32HistogramProducer::addRegionToBin(TQ_UINT8 * pixels, TQ_UINT8 * selectionMask, TQ_UINT32 nPixels, KisColorSpace *cs) { + // The view + float from = static_cast<float>(m_from); + float width = static_cast<float>(m_width); + float to = from + width; + float factor = 255.0 / width; + + TQ_INT32 pSize = cs->pixelSize(); + + if ( selectionMask ) { + while (nPixels > 0) { + + float* pixel = reinterpret_cast<float*>(pixels); + if ( !((m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) ) { + for (int i = 0; i < m_channels; i++) { + float value = pixel[i]; + if (value > to) + m_outRight.at(i)++; + else if (value < from) + m_outLeft.at(i)++; + else + m_bins.at(i).at(static_cast<TQ_UINT8>((value - from) * factor))++; + } + m_count++; + } + + pixels += pSize; + selectionMask++; + nPixels--; + + } + } + else { + while (nPixels > 0) { + + float* pixel = reinterpret_cast<float*>(pixels); + if ( !(m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) { + for (int i = 0; i < m_channels; i++) { + float value = pixel[i]; + if (value > to) + m_outRight.at(i)++; + else if (value < from) + m_outLeft.at(i)++; + else + m_bins.at(i).at(static_cast<TQ_UINT8>((value - from) * factor))++; + } + m_count++; + } + + pixels += pSize; + nPixels--; + + } + } +} + +#ifdef HAVE_OPENEXR +// ------------ Float16 Half --------------------- +KisBasicF16HalfHistogramProducer::KisBasicF16HalfHistogramProducer(const KisID& id, + KisColorSpace *cs) + : KisBasicHistogramProducer(id, cs->nChannels(), 256, cs) { +} + +TQString KisBasicF16HalfHistogramProducer::positionToString(double pos) const { + return TQString("%1").arg(static_cast<float>(pos)); // XXX I doubt this is correct! +} + +double KisBasicF16HalfHistogramProducer::maximalZoom() const { + // XXX What _is_ the maximal zoom here? I don't think there is one with floats, so this seems a fine compromis for the moment + return 1.0 / 255.0; +} + +void KisBasicF16HalfHistogramProducer::addRegionToBin(TQ_UINT8 * pixels, TQ_UINT8 * selectionMask, TQ_UINT32 nPixels, KisColorSpace *cs) { + // The view + float from = static_cast<float>(m_from); + float width = static_cast<float>(m_width); + float to = from + width; + float factor = 255.0 / width; + + TQ_INT32 pSize = cs->pixelSize(); + if ( selectionMask ) { + while (nPixels > 0) { + half* pixel = reinterpret_cast<half*>(pixels); + if ( !((m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) ) { + for (int i = 0; i < m_channels; i++) { + float value = pixel[i]; + if (value > to) + m_outRight.at(i)++; + else if (value < from) + m_outLeft.at(i)++; + else + m_bins.at(i).at(static_cast<TQ_UINT8>((value - from) * factor))++; + } + m_count++; + } + pixels += pSize; + selectionMask++; + nPixels--; + } + } + else { + while (nPixels > 0) { + half* pixel = reinterpret_cast<half*>(pixels); + if ( !(m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) { + for (int i = 0; i < m_channels; i++) { + float value = pixel[i]; + if (value > to) + m_outRight.at(i)++; + else if (value < from) + m_outLeft.at(i)++; + else + m_bins.at(i).at(static_cast<TQ_UINT8>((value - from) * factor))++; + } + m_count++; + } + pixels += pSize; + nPixels--; + } + } +} +#endif + +// ------------ Generic RGB --------------------- +KisGenericRGBHistogramProducer::KisGenericRGBHistogramProducer() + : KisBasicHistogramProducer(KisID("GENRGBHISTO", i18n("Generic RGB Histogram")), + 3, 256, 0) { + /* we set 0 as colorspece, because we are not based on a specific colorspace. This + is no problem for the superclass since we override channels() */ + m_channelsList.append(new KisChannelInfo(i18n("R"), i18n("R"), 0, KisChannelInfo::COLOR, KisChannelInfo::UINT8, 1, TQColor(255,0,0))); + m_channelsList.append(new KisChannelInfo(i18n("G"), i18n("G"), 1, KisChannelInfo::COLOR, KisChannelInfo::UINT8, 1, TQColor(0,255,0))); + m_channelsList.append(new KisChannelInfo(i18n("B"), i18n("B"), 2, KisChannelInfo::COLOR, KisChannelInfo::UINT8, 1, TQColor(0,0,255))); +} + +TQValueVector<KisChannelInfo *> KisGenericRGBHistogramProducer::channels() { + return m_channelsList; +} + +TQString KisGenericRGBHistogramProducer::positionToString(double pos) const { + return TQString("%1").arg(static_cast<TQ_UINT8>(pos * UINT8_MAX)); +} + +double KisGenericRGBHistogramProducer::maximalZoom() const { + return 1.0; +} + + +void KisGenericRGBHistogramProducer::addRegionToBin(TQ_UINT8 * pixels, TQ_UINT8 * selectionMask, TQ_UINT32 nPixels, KisColorSpace *cs) +{ + for (int i = 0; i < m_channels; i++) { + m_outRight.at(i) = 0; + m_outLeft.at(i) = 0; + } + + TQColor c; + TQ_INT32 pSize = cs->pixelSize(); + if (selectionMask) { + while (nPixels > 0) { + if ( !((m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) ) { + cs->toTQColor(pixels, &c); + m_bins.at(0).at(c.red())++; + m_bins.at(1).at(c.green())++; + m_bins.at(2).at(c.blue())++; + + m_count++; + } + pixels += pSize; + selectionMask++; + nPixels--; + } + + } + else { + while (nPixels > 0) { + + if ( !(m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) { + cs->toTQColor(pixels, &c); + m_bins.at(0).at(c.red())++; + m_bins.at(1).at(c.green())++; + m_bins.at(2).at(c.blue())++; + + m_count++; + } + pixels += pSize; + nPixels--; + } + } +} + +// ------------ Generic L*a*b* --------------------- +KisGenericLabHistogramProducer::KisGenericLabHistogramProducer() + : KisBasicHistogramProducer(KisID("GENLABHISTO", i18n("L*a*b* Histogram")), 3, 256, 0) { + /* we set 0 as colorspace, because we are not based on a specific colorspace. This + is no problem for the superclass since we override channels() */ + m_channelsList.append(new KisChannelInfo(i18n("L*"), i18n("L"), 0, KisChannelInfo::COLOR, KisChannelInfo::UINT8)); + m_channelsList.append(new KisChannelInfo(i18n("a*"), i18n("a"), 1, KisChannelInfo::COLOR, KisChannelInfo::UINT8)); + m_channelsList.append(new KisChannelInfo(i18n("b*"), i18n("b"), 2, KisChannelInfo::COLOR, KisChannelInfo::UINT8)); + + if (!m_labCs) { + KisProfile *labProfile = new KisProfile(cmsCreateLabProfile(NULL)); + m_labCs = new KisLabColorSpace(0, labProfile); + } + m_colorSpace = m_labCs; +} +KisGenericLabHistogramProducer::~KisGenericLabHistogramProducer() +{ + delete m_channelsList[0]; + delete m_channelsList[1]; + delete m_channelsList[2]; +} + +TQValueVector<KisChannelInfo *> KisGenericLabHistogramProducer::channels() { + return m_channelsList; +} + +TQString KisGenericLabHistogramProducer::positionToString(double pos) const { + return TQString("%1").arg(static_cast<TQ_UINT16>(pos * UINT16_MAX)); +} + +double KisGenericLabHistogramProducer::maximalZoom() const { + return 1.0; +} + + +void KisGenericLabHistogramProducer::addRegionToBin(TQ_UINT8 * pixels, TQ_UINT8 * selectionMask, TQ_UINT32 nPixels, KisColorSpace *cs) +{ + for (int i = 0; i < m_channels; i++) { + m_outRight.at(i) = 0; + m_outLeft.at(i) = 0; + } + + TQ_UINT8 dst[8]; + TQ_INT32 pSize = cs->pixelSize(); + + if (selectionMask) { + while (nPixels > 0) { + if ( !((m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) ) { +/* + cs->toTQColor(pixels, &c); + m_bins.at(0).at(c.red())++; +*/ + m_count++; + } + pixels += pSize; + selectionMask++; + nPixels--; + } + } + else { + while (nPixels > 0) { + if ( !(m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) { + + cs->convertPixelsTo(pixels, dst, m_colorSpace, 1); + m_bins.at(0).at(m_colorSpace->scaleToU8(dst, 0))++; + m_bins.at(1).at(m_colorSpace->scaleToU8(dst, 1))++; + m_bins.at(2).at(m_colorSpace->scaleToU8(dst, 2))++; + + m_count++; + } + pixels += pSize; + nPixels--; + } + } +} + |