Warning, file /office/calligra/libs/pigment/KoBasicHistogramProducers.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002  *  Copyright (c) 2005 Bart Coppens <kde@bartcoppens.be>
0003  *
0004  *  This library is free software; you can redistribute it and/or modify
0005  *  it under the terms of the GNU Lesser General Public License as published
0006  *  by the Free Software Foundation; either version 2.1 of the License, or
0007  *  (at your option) any later version.
0008  *
0009  *  This library is distributed in the hope that it will be useful,
0010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0012  *  GNU Lesser General Public License for more details.
0013  *
0014  *  You should have received a copy of the GNU Lesser General Public License
0015  *  along with this program; if not, write to the Free Software
0016  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
0017  */
0018 
0019 #include "KoBasicHistogramProducers.h"
0020 
0021 #include <QString>
0022 #include <klocalizedstring.h>
0023 
0024 #include <KoConfig.h>
0025 #ifdef HAVE_OPENEXR
0026 #include <half.h>
0027 #endif
0028 
0029 // #include "Ko_global.h"
0030 #include "KoIntegerMaths.h"
0031 #include "KoChannelInfo.h"
0032 
0033 static const KoColorSpace* m_labCs = 0;
0034 
0035 
0036 KoBasicHistogramProducer::KoBasicHistogramProducer(const KoID& id, int channelCount, int nrOfBins)
0037     : m_channels(channelCount)
0038     , m_nrOfBins(nrOfBins)
0039     , m_colorSpace(0)
0040     , m_id(id)
0041 {
0042     m_bins.resize(m_channels);
0043     for (int i = 0; i < m_channels; i++)
0044         m_bins[i].resize(m_nrOfBins);
0045     m_outLeft.resize(m_channels);
0046     m_outRight.resize(m_channels);
0047     m_count = 0;
0048     m_from = 0.0;
0049     m_width = 1.0;
0050 }
0051 
0052 KoBasicHistogramProducer::KoBasicHistogramProducer(const KoID& id, int nrOfBins, const KoColorSpace *cs)
0053     : m_nrOfBins(nrOfBins),
0054       m_colorSpace(cs),
0055       m_id(id)
0056 {
0057     Q_ASSERT(cs);
0058     m_channels = cs->channelCount();
0059 
0060     m_bins.resize(m_channels);
0061     for (int i = 0; i < m_channels; i++)
0062         m_bins[i].resize(m_nrOfBins);
0063     m_outLeft.resize(m_channels);
0064     m_outRight.resize(m_channels);
0065     m_count = 0;
0066     m_from = 0.0;
0067     m_width = 1.0;
0068 }
0069 
0070 
0071 void KoBasicHistogramProducer::clear()
0072 {
0073     m_count = 0;
0074     for (int i = 0; i < m_channels; i++) {
0075         for (int j = 0; j < m_nrOfBins; j++) {
0076             m_bins[i][j] = 0;
0077         }
0078         m_outRight[i] = 0;
0079         m_outLeft[i] = 0;
0080     }
0081 }
0082 
0083 void KoBasicHistogramProducer::makeExternalToInternal()
0084 {
0085     // This function assumes that the pixel is has no 'gaps'. That is to say: if we start
0086     // at byte 0, we can get to the end of the pixel by adding consecutive size()s of
0087     // the channels
0088     QList<KoChannelInfo *> c = channels();
0089     uint count = c.count();
0090     int currentPos = 0;
0091 
0092     for (uint i = 0; i < count; i++) {
0093         for (uint j = 0; j < count; j++) {
0094             if (c[j]->pos() == currentPos) {
0095                 m_external.append(j);
0096                 break;
0097             }
0098         }
0099         currentPos += c.at(m_external.at(m_external.count() - 1))->size();
0100     }
0101 }
0102 
0103 // ------------ U8 ---------------------
0104 
0105 KoBasicU8HistogramProducer::KoBasicU8HistogramProducer(const KoID& id, const KoColorSpace *cs)
0106     : KoBasicHistogramProducer(id, 256, cs)
0107 {
0108 }
0109 
0110 QString KoBasicU8HistogramProducer::positionToString(qreal pos) const
0111 {
0112     return QString("%1").arg(static_cast<quint8>(pos * UINT8_MAX));
0113 }
0114 
0115 void KoBasicU8HistogramProducer::addRegionToBin(const quint8 * pixels, const quint8 * selectionMask, quint32 nPixels, const KoColorSpace *cs)
0116 {
0117     qint32 pSize = cs->pixelSize();
0118 
0119     if (selectionMask) {
0120         while (nPixels > 0) {
0121             if (!(m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->opacityU8(pixels) == OPACITY_TRANSPARENT_U8)) {
0122 
0123                 for (int i = 0; i < m_channels; i++) {
0124                     m_bins[i][pixels[i]]++;
0125                 }
0126                 m_count++;
0127 
0128             }
0129 
0130             pixels += pSize;
0131             selectionMask++;
0132             nPixels--;
0133         }
0134     } else {
0135         while (nPixels > 0) {
0136             if (!(m_skipTransparent && cs->opacityU8(pixels) == OPACITY_TRANSPARENT_U8)) {
0137 
0138                 for (int i = 0; i < m_channels; i++) {
0139                     m_bins[i][pixels[i]]++;
0140                 }
0141                 m_count++;
0142 
0143             }
0144 
0145             pixels += pSize;
0146             nPixels--;
0147         }
0148     }
0149 }
0150 
0151 // ------------ U16 ---------------------
0152 
0153 KoBasicU16HistogramProducer::KoBasicU16HistogramProducer(const KoID& id, const KoColorSpace *cs)
0154     : KoBasicHistogramProducer(id, 256, cs)
0155 {
0156 }
0157 
0158 QString KoBasicU16HistogramProducer::positionToString(qreal pos) const
0159 {
0160     return QString("%1").arg(static_cast<quint8>(pos * UINT8_MAX));
0161 }
0162 
0163 qreal KoBasicU16HistogramProducer::maximalZoom() const
0164 {
0165     return 1.0 / 255.0;
0166 }
0167 
0168 void KoBasicU16HistogramProducer::addRegionToBin(const quint8 * pixels, const quint8 * selectionMask, quint32 nPixels, const KoColorSpace *cs)
0169 {
0170     // The view
0171     quint16 from = static_cast<quint16>(m_from * UINT16_MAX);
0172     quint16 width = static_cast<quint16>(m_width * UINT16_MAX + 0.5); // We include the end
0173     quint16 to = from + width;
0174     qreal factor = 255.0 / width;
0175 
0176     qint32 pSize = cs->pixelSize();
0177 
0178     if (selectionMask) {
0179         const quint16* pixel = reinterpret_cast<const quint16*>(pixels);
0180         while (nPixels > 0) {
0181             if (!((m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->opacityU8(pixels) == OPACITY_TRANSPARENT_U8))) {
0182                 for (int i = 0; i < m_channels; i++) {
0183                     quint16 value = pixel[i];
0184                     if (value > to)
0185                         m_outRight[i]++;
0186                     else if (value < from)
0187                         m_outLeft[i]++;
0188                     else
0189                         m_bins[i][static_cast<quint8>((value - from) * factor)]++;
0190                 }
0191                 m_count++;
0192             }
0193             pixels += pSize;
0194             selectionMask++;
0195             nPixels--;
0196         }
0197     } else {
0198         while (nPixels > 0) {
0199             const quint16* pixel = reinterpret_cast<const quint16*>(pixels);
0200 
0201             if (!(m_skipTransparent && cs->opacityU8(pixels) == OPACITY_TRANSPARENT_U8)) {
0202                 for (int i = 0; i < m_channels; i++) {
0203                     quint16 value = pixel[i];
0204                     if (value > to)
0205                         m_outRight[i]++;
0206                     else if (value < from)
0207                         m_outLeft[i]++;
0208                     else
0209                         m_bins[i][static_cast<quint8>((value - from) * factor)]++;
0210                 }
0211                 m_count++;
0212             }
0213             pixels += pSize;
0214             nPixels--;
0215 
0216         }
0217     }
0218 }
0219 
0220 // ------------ Float32 ---------------------
0221 KoBasicF32HistogramProducer::KoBasicF32HistogramProducer(const KoID& id, const KoColorSpace *cs)
0222     : KoBasicHistogramProducer(id, 256, cs)
0223 {
0224 }
0225 
0226 QString KoBasicF32HistogramProducer::positionToString(qreal pos) const
0227 {
0228     return QString("%1").arg(static_cast<float>(pos)); // XXX I doubt this is correct!
0229 }
0230 
0231 qreal KoBasicF32HistogramProducer::maximalZoom() const
0232 {
0233     // 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
0234     return 1.0 / 255.0;
0235 }
0236 
0237 void KoBasicF32HistogramProducer::addRegionToBin(const quint8 * pixels, const quint8 * selectionMask, quint32 nPixels, const KoColorSpace *cs)
0238 {
0239     // The view
0240     float from = static_cast<float>(m_from);
0241     float width = static_cast<float>(m_width);
0242     float to = from + width;
0243     float factor = 255.0 / width;
0244 
0245     qint32 pSize = cs->pixelSize();
0246 
0247     if (selectionMask) {
0248         while (nPixels > 0) {
0249 
0250             const float* pixel = reinterpret_cast<const float*>(pixels);
0251             if (!((m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->opacityU8(pixels) == OPACITY_TRANSPARENT_U8))) {
0252                 for (int i = 0; i < m_channels; i++) {
0253                     float value = pixel[i];
0254                     if (value > to)
0255                         m_outRight[i]++;
0256                     else if (value < from)
0257                         m_outLeft[i]++;
0258                     else
0259                         m_bins[i][static_cast<quint8>((value - from) * factor)]++;
0260                 }
0261                 m_count++;
0262             }
0263 
0264             pixels += pSize;
0265             selectionMask++;
0266             nPixels--;
0267 
0268         }
0269     } else {
0270         while (nPixels > 0) {
0271 
0272             const float* pixel = reinterpret_cast<const float*>(pixels);
0273             if (!(m_skipTransparent && cs->opacityU8(pixels) == OPACITY_TRANSPARENT_U8)) {
0274                 for (int i = 0; i < m_channels; i++) {
0275                     float value = pixel[i];
0276                     if (value > to)
0277                         m_outRight[i]++;
0278                     else if (value < from)
0279                         m_outLeft[i]++;
0280                     else
0281                         m_bins[i][static_cast<quint8>((value - from) * factor)]++;
0282                 }
0283                 m_count++;
0284             }
0285 
0286             pixels += pSize;
0287             nPixels--;
0288 
0289         }
0290     }
0291 }
0292 
0293 #ifdef HAVE_OPENEXR
0294 // ------------ Float16 Half ---------------------
0295 KoBasicF16HalfHistogramProducer::KoBasicF16HalfHistogramProducer(const KoID& id,
0296                                                                  const KoColorSpace *cs)
0297     : KoBasicHistogramProducer(id, 256, cs)
0298 {
0299 }
0300 
0301 QString KoBasicF16HalfHistogramProducer::positionToString(qreal pos) const
0302 {
0303     return QString("%1").arg(static_cast<float>(pos)); // XXX I doubt this is correct!
0304 }
0305 
0306 qreal KoBasicF16HalfHistogramProducer::maximalZoom() const
0307 {
0308     // 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
0309     return 1.0 / 255.0;
0310 }
0311 
0312 void KoBasicF16HalfHistogramProducer::addRegionToBin(const quint8 * pixels, const quint8 * selectionMask, quint32 nPixels, const KoColorSpace *cs)
0313 {
0314     // The view
0315     float from = static_cast<float>(m_from);
0316     float width = static_cast<float>(m_width);
0317     float to = from + width;
0318     float factor = 255.0 / width;
0319 
0320     qint32 pSize = cs->pixelSize();
0321     if (selectionMask) {
0322         while (nPixels > 0) {
0323             const half* pixel = reinterpret_cast<const half*>(pixels);
0324             if (!((m_skipUnselected  && *selectionMask == 0) || (m_skipTransparent && cs->opacityU8(pixels) == OPACITY_TRANSPARENT_U8))) {
0325                 for (int i = 0; i < m_channels; i++) {
0326                     float value = pixel[i];
0327                     if (value > to)
0328                         m_outRight[i]++;
0329                     else if (value < from)
0330                         m_outLeft[i]++;
0331                     else
0332                         m_bins[i][static_cast<quint8>((value - from) * factor)]++;
0333                 }
0334                 m_count++;
0335             }
0336             pixels += pSize;
0337             selectionMask++;
0338             nPixels--;
0339         }
0340     } else {
0341         while (nPixels > 0) {
0342             const half* pixel = reinterpret_cast<const half*>(pixels);
0343             if (!(m_skipTransparent && cs->opacityU8(pixels) == OPACITY_TRANSPARENT_U8)) {
0344                 for (int i = 0; i < m_channels; i++) {
0345                     float value = pixel[i];
0346                     if (value > to)
0347                         m_outRight[i]++;
0348                     else if (value < from)
0349                         m_outLeft[i]++;
0350                     else
0351                         m_bins[i][static_cast<quint8>((value - from) * factor)]++;
0352                 }
0353                 m_count++;
0354             }
0355             pixels += pSize;
0356             nPixels--;
0357         }
0358     }
0359 }
0360 #endif
0361 
0362 // ------------ Generic RGB ---------------------
0363 KoGenericRGBHistogramProducer::KoGenericRGBHistogramProducer()
0364     : KoBasicHistogramProducer(KoID("GENRGBHISTO", i18n("Generic RGB Histogram")), 3, 256)
0365 {
0366     /* we set 0 as colorspece, because we are not based on a specific colorspace. This
0367        is no problem for the superclass since we override channels() */
0368     m_channelsList.append(new KoChannelInfo(i18n("R"), 0, 0, KoChannelInfo::COLOR, KoChannelInfo::UINT8, 1, QColor(255, 0, 0)));
0369     m_channelsList.append(new KoChannelInfo(i18n("G"), 1, 1, KoChannelInfo::COLOR, KoChannelInfo::UINT8, 1, QColor(0, 255, 0)));
0370     m_channelsList.append(new KoChannelInfo(i18n("B"), 2, 2, KoChannelInfo::COLOR, KoChannelInfo::UINT8, 1, QColor(0, 0, 255)));
0371 }
0372 
0373 QList<KoChannelInfo *> KoGenericRGBHistogramProducer::channels()
0374 {
0375     return m_channelsList;
0376 }
0377 
0378 QString KoGenericRGBHistogramProducer::positionToString(qreal pos) const
0379 {
0380     return QString("%1").arg(static_cast<quint8>(pos * UINT8_MAX));
0381 }
0382 
0383 qreal KoGenericRGBHistogramProducer::maximalZoom() const
0384 {
0385     return 1.0;
0386 }
0387 
0388 
0389 void KoGenericRGBHistogramProducer::addRegionToBin(const quint8 * pixels, const quint8 * selectionMask, quint32 nPixels, const KoColorSpace *cs)
0390 {
0391     for (int i = 0; i < m_channels; i++) {
0392         m_outRight[i] = 0;
0393         m_outLeft[i] = 0;
0394     }
0395 
0396     QColor c;
0397     qint32 pSize = cs->pixelSize();
0398     if (selectionMask) {
0399         while (nPixels > 0) {
0400             if (!((m_skipUnselected  && *selectionMask == 0) || (m_skipTransparent && cs->opacityU8(pixels) == OPACITY_TRANSPARENT_U8))) {
0401                 cs->toQColor(pixels, &c);
0402                 m_bins[0][c.red()]++;
0403                 m_bins[1][c.green()]++;
0404                 m_bins[2][c.blue()]++;
0405 
0406                 m_count++;
0407             }
0408             pixels += pSize;
0409             selectionMask++;
0410             nPixels--;
0411         }
0412 
0413     } else {
0414         while (nPixels > 0) {
0415 
0416             if (!(m_skipTransparent && cs->opacityU8(pixels) == OPACITY_TRANSPARENT_U8)) {
0417                 cs->toQColor(pixels, &c);
0418                 m_bins[0][c.red()]++;
0419                 m_bins[1][c.green()]++;
0420                 m_bins[2][c.blue()]++;
0421 
0422                 m_count++;
0423             }
0424             pixels += pSize;
0425             nPixels--;
0426         }
0427     }
0428 }
0429 
0430 KoGenericRGBHistogramProducerFactory::KoGenericRGBHistogramProducerFactory()
0431     : KoHistogramProducerFactory(KoID("GENRGBHISTO", i18n("Generic RGB Histogram")))
0432 {
0433 }
0434 
0435 // ------------ Generic L*a*b* ---------------------
0436 KoGenericLabHistogramProducer::KoGenericLabHistogramProducer()
0437     : KoBasicHistogramProducer(KoID("GENLABHISTO", i18n("L*a*b* Histogram")), 3, 256)
0438 {
0439     /* we set 0 as colorspace, because we are not based on a specific colorspace. This
0440        is no problem for the superclass since we override channels() */
0441     m_channelsList.append(new KoChannelInfo(i18n("L*"), 0, 0, KoChannelInfo::COLOR, KoChannelInfo::UINT8));
0442     m_channelsList.append(new KoChannelInfo(i18n("a*"), 1, 1, KoChannelInfo::COLOR, KoChannelInfo::UINT8));
0443     m_channelsList.append(new KoChannelInfo(i18n("b*"), 2, 2, KoChannelInfo::COLOR, KoChannelInfo::UINT8));
0444 
0445     if (!m_labCs) {
0446         m_labCs = KoColorSpaceRegistry::instance()->lab16();
0447     }
0448     m_colorSpace = m_labCs;
0449 }
0450 KoGenericLabHistogramProducer::~KoGenericLabHistogramProducer()
0451 {
0452     delete m_channelsList[0];
0453     delete m_channelsList[1];
0454     delete m_channelsList[2];
0455 }
0456 
0457 QList<KoChannelInfo *> KoGenericLabHistogramProducer::channels()
0458 {
0459     return m_channelsList;
0460 }
0461 
0462 QString KoGenericLabHistogramProducer::positionToString(qreal pos) const
0463 {
0464     return QString("%1").arg(static_cast<quint16>(pos * UINT16_MAX));
0465 }
0466 
0467 qreal KoGenericLabHistogramProducer::maximalZoom() const
0468 {
0469     return 1.0;
0470 }
0471 
0472 
0473 void KoGenericLabHistogramProducer::addRegionToBin(const quint8 *pixels, const quint8 *selectionMask, quint32 nPixels,  const KoColorSpace *cs)
0474 {
0475     for (int i = 0; i < m_channels; i++) {
0476         m_outRight[i] = 0;
0477         m_outLeft[i] = 0;
0478     }
0479 
0480     qint32 dstPixelSize = m_colorSpace->pixelSize();
0481 
0482     quint8 *dstPixels = new quint8[nPixels * dstPixelSize];
0483     cs->convertPixelsTo(pixels, dstPixels, m_colorSpace, nPixels, KoColorConversionTransformation::IntentAbsoluteColorimetric, KoColorConversionTransformation::Empty);
0484 
0485     qint32 pSize = cs->pixelSize();
0486 
0487     if (selectionMask) {
0488         while (nPixels > 0) {
0489             if (!((m_skipUnselected  && *selectionMask == 0) || (m_skipTransparent && cs->opacityU8(pixels) == OPACITY_TRANSPARENT_U8))) {
0490                 m_count++;
0491             }
0492             pixels += pSize;
0493             selectionMask++;
0494             nPixels--;
0495         }
0496     } else {
0497         quint8 *dst = dstPixels;
0498         while (nPixels > 0) {
0499             if (!(m_skipTransparent && cs->opacityU8(pixels) == OPACITY_TRANSPARENT_U8))  {
0500 
0501                 m_bins[0][m_colorSpace->scaleToU8(dst, 0)]++;
0502                 m_bins[1][m_colorSpace->scaleToU8(dst, 1)]++;
0503                 m_bins[2][m_colorSpace->scaleToU8(dst, 2)]++;
0504 
0505                 m_count++;
0506             }
0507             dst+= dstPixelSize;
0508             nPixels--;
0509         }
0510     }
0511     delete[] dstPixels;
0512 }
0513 
0514 KoGenericLabHistogramProducerFactory::KoGenericLabHistogramProducerFactory()
0515     : KoHistogramProducerFactory(KoID("GENLABHISTO", i18n("Generic L*a*b* Histogram")))
0516 {
0517 }