00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <qstring.h>
00020 #include <klocale.h>
00021
00022 #include "config.h"
00023
00024 #ifdef HAVE_OPENEXR
00025 #include <half.h>
00026 #endif
00027
00028 #include "kis_global.h"
00029 #include "kis_basic_histogram_producers.h"
00030 #include "kis_integer_maths.h"
00031 #include "kis_channelinfo.h"
00032 #include "kis_colorspace.h"
00033 #include "kis_lab_colorspace.h"
00034
00035 KisLabColorSpace* KisGenericLabHistogramProducer::m_labCs = 0;
00036
00037
00038 KisBasicHistogramProducer::KisBasicHistogramProducer(const KisID& id, int channels, int nrOfBins, KisColorSpace *cs)
00039 : m_channels(channels),
00040 m_nrOfBins(nrOfBins),
00041 m_colorSpace(cs),
00042 m_id(id)
00043 {
00044 m_bins.resize(m_channels);
00045 for (int i = 0; i < m_channels; i++)
00046 m_bins.at(i).resize(m_nrOfBins);
00047 m_outLeft.resize(m_channels);
00048 m_outRight.resize(m_channels);
00049 m_count = 0;
00050 m_from = 0.0;
00051 m_width = 1.0;
00052 }
00053
00054 void KisBasicHistogramProducer::clear() {
00055 m_count = 0;
00056 for (int i = 0; i < m_channels; i++) {
00057 for (int j = 0; j < m_nrOfBins; j++) {
00058 m_bins.at(i).at(j) = 0;
00059 }
00060 m_outRight.at(i) = 0;
00061 m_outLeft.at(i) = 0;
00062 }
00063 }
00064
00065 void KisBasicHistogramProducer::makeExternalToInternal() {
00066
00067
00068
00069 QValueVector<KisChannelInfo *> c = channels();
00070 uint count = c.count();
00071 int currentPos = 0;
00072
00073 for (uint i = 0; i < count; i++) {
00074 for (uint j = 0; j < count; j++) {
00075 if (c.at(j)->pos() == currentPos) {
00076 m_external.append(j);
00077 break;
00078 }
00079 }
00080 currentPos += c.at(m_external.at(m_external.count() - 1))->size();
00081 }
00082 }
00083
00084
00085
00086 KisBasicU8HistogramProducer::KisBasicU8HistogramProducer(const KisID& id, KisColorSpace *cs)
00087 : KisBasicHistogramProducer(id, cs->nChannels(), 256, cs)
00088 {
00089 }
00090
00091 QString KisBasicU8HistogramProducer::positionToString(double pos) const {
00092 return QString("%1").arg(static_cast<Q_UINT8>(pos * UINT8_MAX));
00093 }
00094
00095 void KisBasicU8HistogramProducer::addRegionToBin(Q_UINT8 * pixels, Q_UINT8 * selectionMask, Q_UINT32 nPixels, KisColorSpace *cs)
00096 {
00097 if (!pixels) return;
00098 if (!cs) return;
00099 if (nPixels == 0) return;
00100
00101 Q_INT32 pSize = cs->pixelSize();
00102
00103 if ( selectionMask ) {
00104 while (nPixels > 0) {
00105 if ( ! (m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT) ) {
00106
00107 for (int i = 0; i < m_channels; i++) {
00108 m_bins.at(i).at(pixels[i])++;
00109 }
00110 m_count++;
00111
00112 }
00113
00114 pixels += pSize;
00115 selectionMask++;
00116 nPixels--;
00117 }
00118 }
00119 else {
00120 while (nPixels > 0) {
00121 if ( ! (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT) ) {
00122
00123 for (int i = 0; i < m_channels; i++) {
00124 m_bins.at(i).at(pixels[i])++;
00125 }
00126 m_count++;
00127
00128 }
00129
00130 pixels += pSize;
00131 nPixels--;
00132 }
00133 }
00134 }
00135
00136
00137
00138 KisBasicU16HistogramProducer::KisBasicU16HistogramProducer(const KisID& id, KisColorSpace *cs)
00139 : KisBasicHistogramProducer(id, cs->nChannels(), 256, cs)
00140 {
00141 }
00142
00143 QString KisBasicU16HistogramProducer::positionToString(double pos) const
00144 {
00145 return QString("%1").arg(static_cast<Q_UINT8>(pos * UINT8_MAX));
00146 }
00147
00148 double KisBasicU16HistogramProducer::maximalZoom() const
00149 {
00150 return 1.0 / 255.0;
00151 }
00152
00153 void KisBasicU16HistogramProducer::addRegionToBin(Q_UINT8 * pixels, Q_UINT8 * selectionMask, Q_UINT32 nPixels, KisColorSpace *cs)
00154 {
00155
00156 Q_UINT16 from = static_cast<Q_UINT16>(m_from * UINT16_MAX);
00157 Q_UINT16 width = static_cast<Q_UINT16>(m_width * UINT16_MAX + 0.5);
00158 Q_UINT16 to = from + width;
00159 double factor = 255.0 / width;
00160
00161 Q_INT32 pSize = cs->pixelSize();
00162
00163 if ( selectionMask ) {
00164 Q_UINT16* pixel = reinterpret_cast<Q_UINT16*>(pixels);
00165 while (nPixels > 0) {
00166 if ( ! ((m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) ) {
00167 for (int i = 0; i < m_channels; i++) {
00168 Q_UINT16 value = pixel[i];
00169 if (value > to)
00170 m_outRight.at(i)++;
00171 else if (value < from)
00172 m_outLeft.at(i)++;
00173 else
00174 m_bins.at(i).at(static_cast<Q_UINT8>((value - from) * factor))++;
00175 }
00176 m_count++;
00177 }
00178 pixels += pSize;
00179 selectionMask++;
00180 nPixels--;
00181 }
00182 }
00183 else {
00184 while (nPixels > 0) {
00185 Q_UINT16* pixel = reinterpret_cast<Q_UINT16*>(pixels);
00186
00187 if ( ! (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) {
00188 for (int i = 0; i < m_channels; i++) {
00189 Q_UINT16 value = pixel[i];
00190 if (value > to)
00191 m_outRight.at(i)++;
00192 else if (value < from)
00193 m_outLeft.at(i)++;
00194 else
00195 m_bins.at(i).at(static_cast<Q_UINT8>((value - from) * factor))++;
00196 }
00197 m_count++;
00198 }
00199 pixels += pSize;
00200 nPixels--;
00201
00202 }
00203 }
00204 }
00205
00206
00207 KisBasicF32HistogramProducer::KisBasicF32HistogramProducer(const KisID& id, KisColorSpace *cs)
00208 : KisBasicHistogramProducer(id, cs->nChannels(), 256, cs)
00209 {
00210 }
00211
00212 QString KisBasicF32HistogramProducer::positionToString(double pos) const {
00213 return QString("%1").arg(static_cast<float>(pos));
00214 }
00215
00216 double KisBasicF32HistogramProducer::maximalZoom() const {
00217
00218 return 1.0 / 255.0;
00219 }
00220
00221 void KisBasicF32HistogramProducer::addRegionToBin(Q_UINT8 * pixels, Q_UINT8 * selectionMask, Q_UINT32 nPixels, KisColorSpace *cs) {
00222
00223 float from = static_cast<float>(m_from);
00224 float width = static_cast<float>(m_width);
00225 float to = from + width;
00226 float factor = 255.0 / width;
00227
00228 Q_INT32 pSize = cs->pixelSize();
00229
00230 if ( selectionMask ) {
00231 while (nPixels > 0) {
00232
00233 float* pixel = reinterpret_cast<float*>(pixels);
00234 if ( !((m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) ) {
00235 for (int i = 0; i < m_channels; i++) {
00236 float value = pixel[i];
00237 if (value > to)
00238 m_outRight.at(i)++;
00239 else if (value < from)
00240 m_outLeft.at(i)++;
00241 else
00242 m_bins.at(i).at(static_cast<Q_UINT8>((value - from) * factor))++;
00243 }
00244 m_count++;
00245 }
00246
00247 pixels += pSize;
00248 selectionMask++;
00249 nPixels--;
00250
00251 }
00252 }
00253 else {
00254 while (nPixels > 0) {
00255
00256 float* pixel = reinterpret_cast<float*>(pixels);
00257 if ( !(m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) {
00258 for (int i = 0; i < m_channels; i++) {
00259 float value = pixel[i];
00260 if (value > to)
00261 m_outRight.at(i)++;
00262 else if (value < from)
00263 m_outLeft.at(i)++;
00264 else
00265 m_bins.at(i).at(static_cast<Q_UINT8>((value - from) * factor))++;
00266 }
00267 m_count++;
00268 }
00269
00270 pixels += pSize;
00271 nPixels--;
00272
00273 }
00274 }
00275 }
00276
00277 #ifdef HAVE_OPENEXR
00278
00279 KisBasicF16HalfHistogramProducer::KisBasicF16HalfHistogramProducer(const KisID& id,
00280 KisColorSpace *cs)
00281 : KisBasicHistogramProducer(id, cs->nChannels(), 256, cs) {
00282 }
00283
00284 QString KisBasicF16HalfHistogramProducer::positionToString(double pos) const {
00285 return QString("%1").arg(static_cast<float>(pos));
00286 }
00287
00288 double KisBasicF16HalfHistogramProducer::maximalZoom() const {
00289
00290 return 1.0 / 255.0;
00291 }
00292
00293 void KisBasicF16HalfHistogramProducer::addRegionToBin(Q_UINT8 * pixels, Q_UINT8 * selectionMask, Q_UINT32 nPixels, KisColorSpace *cs) {
00294
00295 float from = static_cast<float>(m_from);
00296 float width = static_cast<float>(m_width);
00297 float to = from + width;
00298 float factor = 255.0 / width;
00299
00300 Q_INT32 pSize = cs->pixelSize();
00301 if ( selectionMask ) {
00302 while (nPixels > 0) {
00303 half* pixel = reinterpret_cast<half*>(pixels);
00304 if ( !((m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) ) {
00305 for (int i = 0; i < m_channels; i++) {
00306 float value = pixel[i];
00307 if (value > to)
00308 m_outRight.at(i)++;
00309 else if (value < from)
00310 m_outLeft.at(i)++;
00311 else
00312 m_bins.at(i).at(static_cast<Q_UINT8>((value - from) * factor))++;
00313 }
00314 m_count++;
00315 }
00316 pixels += pSize;
00317 selectionMask++;
00318 nPixels--;
00319 }
00320 }
00321 else {
00322 while (nPixels > 0) {
00323 half* pixel = reinterpret_cast<half*>(pixels);
00324 if ( !(m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) {
00325 for (int i = 0; i < m_channels; i++) {
00326 float value = pixel[i];
00327 if (value > to)
00328 m_outRight.at(i)++;
00329 else if (value < from)
00330 m_outLeft.at(i)++;
00331 else
00332 m_bins.at(i).at(static_cast<Q_UINT8>((value - from) * factor))++;
00333 }
00334 m_count++;
00335 }
00336 pixels += pSize;
00337 nPixels--;
00338 }
00339 }
00340 }
00341 #endif
00342
00343
00344 KisGenericRGBHistogramProducer::KisGenericRGBHistogramProducer()
00345 : KisBasicHistogramProducer(KisID("GENRGBHISTO", i18n("Generic RGB Histogram")),
00346 3, 256, 0) {
00347
00348
00349 m_channelsList.append(new KisChannelInfo(i18n("R"), i18n("R"), 0, KisChannelInfo::COLOR, KisChannelInfo::UINT8, 1, QColor(255,0,0)));
00350 m_channelsList.append(new KisChannelInfo(i18n("G"), i18n("G"), 1, KisChannelInfo::COLOR, KisChannelInfo::UINT8, 1, QColor(0,255,0)));
00351 m_channelsList.append(new KisChannelInfo(i18n("B"), i18n("B"), 2, KisChannelInfo::COLOR, KisChannelInfo::UINT8, 1, QColor(0,0,255)));
00352 }
00353
00354 QValueVector<KisChannelInfo *> KisGenericRGBHistogramProducer::channels() {
00355 return m_channelsList;
00356 }
00357
00358 QString KisGenericRGBHistogramProducer::positionToString(double pos) const {
00359 return QString("%1").arg(static_cast<Q_UINT8>(pos * UINT8_MAX));
00360 }
00361
00362 double KisGenericRGBHistogramProducer::maximalZoom() const {
00363 return 1.0;
00364 }
00365
00366
00367 void KisGenericRGBHistogramProducer::addRegionToBin(Q_UINT8 * pixels, Q_UINT8 * selectionMask, Q_UINT32 nPixels, KisColorSpace *cs)
00368 {
00369 for (int i = 0; i < m_channels; i++) {
00370 m_outRight.at(i) = 0;
00371 m_outLeft.at(i) = 0;
00372 }
00373
00374 QColor c;
00375 Q_INT32 pSize = cs->pixelSize();
00376 if (selectionMask) {
00377 while (nPixels > 0) {
00378 if ( !((m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) ) {
00379 cs->toQColor(pixels, &c);
00380 m_bins.at(0).at(c.red())++;
00381 m_bins.at(1).at(c.green())++;
00382 m_bins.at(2).at(c.blue())++;
00383
00384 m_count++;
00385 }
00386 pixels += pSize;
00387 selectionMask++;
00388 nPixels--;
00389 }
00390
00391 }
00392 else {
00393 while (nPixels > 0) {
00394
00395 if ( !(m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) {
00396 cs->toQColor(pixels, &c);
00397 m_bins.at(0).at(c.red())++;
00398 m_bins.at(1).at(c.green())++;
00399 m_bins.at(2).at(c.blue())++;
00400
00401 m_count++;
00402 }
00403 pixels += pSize;
00404 nPixels--;
00405 }
00406 }
00407 }
00408
00409
00410 KisGenericLabHistogramProducer::KisGenericLabHistogramProducer()
00411 : KisBasicHistogramProducer(KisID("GENLABHISTO", i18n("L*a*b* Histogram")), 3, 256, 0) {
00412
00413
00414 m_channelsList.append(new KisChannelInfo(i18n("L*"), i18n("L"), 0, KisChannelInfo::COLOR, KisChannelInfo::UINT8));
00415 m_channelsList.append(new KisChannelInfo(i18n("a*"), i18n("a"), 1, KisChannelInfo::COLOR, KisChannelInfo::UINT8));
00416 m_channelsList.append(new KisChannelInfo(i18n("b*"), i18n("b"), 2, KisChannelInfo::COLOR, KisChannelInfo::UINT8));
00417
00418 if (!m_labCs) {
00419 KisProfile *labProfile = new KisProfile(cmsCreateLabProfile(NULL));
00420 m_labCs = new KisLabColorSpace(0, labProfile);
00421 }
00422 m_colorSpace = m_labCs;
00423 }
00424 KisGenericLabHistogramProducer::~KisGenericLabHistogramProducer()
00425 {
00426 delete m_channelsList[0];
00427 delete m_channelsList[1];
00428 delete m_channelsList[2];
00429 }
00430
00431 QValueVector<KisChannelInfo *> KisGenericLabHistogramProducer::channels() {
00432 return m_channelsList;
00433 }
00434
00435 QString KisGenericLabHistogramProducer::positionToString(double pos) const {
00436 return QString("%1").arg(static_cast<Q_UINT16>(pos * UINT16_MAX));
00437 }
00438
00439 double KisGenericLabHistogramProducer::maximalZoom() const {
00440 return 1.0;
00441 }
00442
00443
00444 void KisGenericLabHistogramProducer::addRegionToBin(Q_UINT8 * pixels, Q_UINT8 * selectionMask, Q_UINT32 nPixels, KisColorSpace *cs)
00445 {
00446 for (int i = 0; i < m_channels; i++) {
00447 m_outRight.at(i) = 0;
00448 m_outLeft.at(i) = 0;
00449 }
00450
00451 Q_UINT8 dst[8];
00452 Q_INT32 pSize = cs->pixelSize();
00453
00454 if (selectionMask) {
00455 while (nPixels > 0) {
00456 if ( !((m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) ) {
00457
00458
00459
00460
00461 m_count++;
00462 }
00463 pixels += pSize;
00464 selectionMask++;
00465 nPixels--;
00466 }
00467 }
00468 else {
00469 while (nPixels > 0) {
00470 if ( !(m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) {
00471
00472 cs->convertPixelsTo(pixels, dst, m_colorSpace, 1);
00473 m_bins.at(0).at(m_colorSpace->scaleToU8(dst, 0))++;
00474 m_bins.at(1).at(m_colorSpace->scaleToU8(dst, 1))++;
00475 m_bins.at(2).at(m_colorSpace->scaleToU8(dst, 2))++;
00476
00477 m_count++;
00478 }
00479 pixels += pSize;
00480 nPixels--;
00481 }
00482 }
00483 }
00484