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 }