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 (!selectionMask) return;
00100 if (nPixels == 0) return;
00101
00102 Q_INT32 pSize = cs->pixelSize();
00103
00104 if ( selectionMask ) {
00105 while (nPixels > 0) {
00106 if ( ! (m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT) ) {
00107
00108 for (int i = 0; i < m_channels; i++) {
00109 m_bins.at(i).at(pixels[i])++;
00110 }
00111 m_count++;
00112
00113 }
00114
00115 pixels += pSize;
00116 selectionMask++;
00117 nPixels--;
00118 }
00119 }
00120 else {
00121 while (nPixels > 0) {
00122 if ( ! (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT) ) {
00123
00124 for (int i = 0; i < m_channels; i++) {
00125 m_bins.at(i).at(pixels[i])++;
00126 }
00127 m_count++;
00128
00129 }
00130
00131 pixels += pSize;
00132 nPixels--;
00133 }
00134 }
00135 }
00136
00137
00138
00139 KisBasicU16HistogramProducer::KisBasicU16HistogramProducer(const KisID& id, KisColorSpace *cs)
00140 : KisBasicHistogramProducer(id, cs->nChannels(), 256, cs)
00141 {
00142 }
00143
00144 QString KisBasicU16HistogramProducer::positionToString(double pos) const
00145 {
00146 return QString("%1").arg(static_cast<Q_UINT8>(pos * UINT8_MAX));
00147 }
00148
00149 double KisBasicU16HistogramProducer::maximalZoom() const
00150 {
00151 return 1.0 / 255.0;
00152 }
00153
00154 void KisBasicU16HistogramProducer::addRegionToBin(Q_UINT8 * pixels, Q_UINT8 * selectionMask, Q_UINT32 nPixels, KisColorSpace *cs)
00155 {
00156
00157 Q_UINT16 from = static_cast<Q_UINT16>(m_from * UINT16_MAX);
00158 Q_UINT16 width = static_cast<Q_UINT16>(m_width * UINT16_MAX + 0.5);
00159 Q_UINT16 to = from + width;
00160 double factor = 255.0 / width;
00161
00162 Q_INT32 pSize = cs->pixelSize();
00163
00164 if ( selectionMask ) {
00165 Q_UINT16* pixel = reinterpret_cast<Q_UINT16*>(pixels);
00166 while (nPixels > 0) {
00167 if ( ! ((m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) ) {
00168 for (int i = 0; i < m_channels; i++) {
00169 Q_UINT16 value = pixel[i];
00170 if (value > to)
00171 m_outRight.at(i)++;
00172 else if (value < from)
00173 m_outLeft.at(i)++;
00174 else
00175 m_bins.at(i).at(static_cast<Q_UINT8>((value - from) * factor))++;
00176 }
00177 m_count++;
00178 }
00179 pixels += pSize;
00180 selectionMask++;
00181 nPixels--;
00182 }
00183 }
00184 else {
00185 while (nPixels > 0) {
00186 Q_UINT16* pixel = reinterpret_cast<Q_UINT16*>(pixels);
00187
00188 if ( ! (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) {
00189 for (int i = 0; i < m_channels; i++) {
00190 Q_UINT16 value = pixel[i];
00191 if (value > to)
00192 m_outRight.at(i)++;
00193 else if (value < from)
00194 m_outLeft.at(i)++;
00195 else
00196 m_bins.at(i).at(static_cast<Q_UINT8>((value - from) * factor))++;
00197 }
00198 m_count++;
00199 }
00200 pixels += pSize;
00201 nPixels--;
00202
00203 }
00204 }
00205 }
00206
00207
00208 KisBasicF32HistogramProducer::KisBasicF32HistogramProducer(const KisID& id, KisColorSpace *cs)
00209 : KisBasicHistogramProducer(id, cs->nChannels(), 256, cs)
00210 {
00211 }
00212
00213 QString KisBasicF32HistogramProducer::positionToString(double pos) const {
00214 return QString("%1").arg(static_cast<float>(pos));
00215 }
00216
00217 double KisBasicF32HistogramProducer::maximalZoom() const {
00218
00219 return 1.0 / 255.0;
00220 }
00221
00222 void KisBasicF32HistogramProducer::addRegionToBin(Q_UINT8 * pixels, Q_UINT8 * selectionMask, Q_UINT32 nPixels, KisColorSpace *cs) {
00223
00224 float from = static_cast<float>(m_from);
00225 float width = static_cast<float>(m_width);
00226 float to = from + width;
00227 float factor = 255.0 / width;
00228
00229 Q_INT32 pSize = cs->pixelSize();
00230
00231 if ( selectionMask ) {
00232 while (nPixels > 0) {
00233
00234 float* pixel = reinterpret_cast<float*>(pixels);
00235 if ( !((m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) ) {
00236 for (int i = 0; i < m_channels; i++) {
00237 float value = pixel[i];
00238 if (value > to)
00239 m_outRight.at(i)++;
00240 else if (value < from)
00241 m_outLeft.at(i)++;
00242 else
00243 m_bins.at(i).at(static_cast<Q_UINT8>((value - from) * factor))++;
00244 }
00245 m_count++;
00246 }
00247
00248 pixels += pSize;
00249 selectionMask++;
00250 nPixels--;
00251
00252 }
00253 }
00254 else {
00255 while (nPixels > 0) {
00256
00257 float* pixel = reinterpret_cast<float*>(pixels);
00258 if ( !(m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) {
00259 for (int i = 0; i < m_channels; i++) {
00260 float value = pixel[i];
00261 if (value > to)
00262 m_outRight.at(i)++;
00263 else if (value < from)
00264 m_outLeft.at(i)++;
00265 else
00266 m_bins.at(i).at(static_cast<Q_UINT8>((value - from) * factor))++;
00267 }
00268 m_count++;
00269 }
00270
00271 pixels += pSize;
00272 nPixels--;
00273
00274 }
00275 }
00276 }
00277
00278 #ifdef HAVE_OPENEXR
00279
00280 KisBasicF16HalfHistogramProducer::KisBasicF16HalfHistogramProducer(const KisID& id,
00281 KisColorSpace *cs)
00282 : KisBasicHistogramProducer(id, cs->nChannels(), 256, cs) {
00283 }
00284
00285 QString KisBasicF16HalfHistogramProducer::positionToString(double pos) const {
00286 return QString("%1").arg(static_cast<float>(pos));
00287 }
00288
00289 double KisBasicF16HalfHistogramProducer::maximalZoom() const {
00290
00291 return 1.0 / 255.0;
00292 }
00293
00294 void KisBasicF16HalfHistogramProducer::addRegionToBin(Q_UINT8 * pixels, Q_UINT8 * selectionMask, Q_UINT32 nPixels, KisColorSpace *cs) {
00295
00296 float from = static_cast<float>(m_from);
00297 float width = static_cast<float>(m_width);
00298 float to = from + width;
00299 float factor = 255.0 / width;
00300
00301 Q_INT32 pSize = cs->pixelSize();
00302 if ( selectionMask ) {
00303 while (nPixels > 0) {
00304 half* pixel = reinterpret_cast<half*>(pixels);
00305 if ( !((m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) ) {
00306 for (int i = 0; i < m_channels; i++) {
00307 float value = pixel[i];
00308 if (value > to)
00309 m_outRight.at(i)++;
00310 else if (value < from)
00311 m_outLeft.at(i)++;
00312 else
00313 m_bins.at(i).at(static_cast<Q_UINT8>((value - from) * factor))++;
00314 }
00315 m_count++;
00316 }
00317 pixels += pSize;
00318 selectionMask++;
00319 nPixels--;
00320 }
00321 }
00322 else {
00323 while (nPixels > 0) {
00324 half* pixel = reinterpret_cast<half*>(pixels);
00325 if ( !(m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) {
00326 for (int i = 0; i < m_channels; i++) {
00327 float value = pixel[i];
00328 if (value > to)
00329 m_outRight.at(i)++;
00330 else if (value < from)
00331 m_outLeft.at(i)++;
00332 else
00333 m_bins.at(i).at(static_cast<Q_UINT8>((value - from) * factor))++;
00334 }
00335 m_count++;
00336 }
00337 pixels += pSize;
00338 nPixels--;
00339 }
00340 }
00341 }
00342 #endif
00343
00344
00345 KisGenericRGBHistogramProducer::KisGenericRGBHistogramProducer()
00346 : KisBasicHistogramProducer(KisID("GENRGBHISTO", i18n("Generic RGB Histogram")),
00347 3, 256, 0) {
00348
00349
00350 m_channelsList.append(new KisChannelInfo(i18n("R"), i18n("R"), 0, KisChannelInfo::COLOR, KisChannelInfo::UINT8, 1, QColor(255,0,0)));
00351 m_channelsList.append(new KisChannelInfo(i18n("G"), i18n("G"), 1, KisChannelInfo::COLOR, KisChannelInfo::UINT8, 1, QColor(0,255,0)));
00352 m_channelsList.append(new KisChannelInfo(i18n("B"), i18n("B"), 2, KisChannelInfo::COLOR, KisChannelInfo::UINT8, 1, QColor(0,0,255)));
00353 }
00354
00355 QValueVector<KisChannelInfo *> KisGenericRGBHistogramProducer::channels() {
00356 return m_channelsList;
00357 }
00358
00359 QString KisGenericRGBHistogramProducer::positionToString(double pos) const {
00360 return QString("%1").arg(static_cast<Q_UINT8>(pos * UINT8_MAX));
00361 }
00362
00363 double KisGenericRGBHistogramProducer::maximalZoom() const {
00364 return 1.0;
00365 }
00366
00367
00368 void KisGenericRGBHistogramProducer::addRegionToBin(Q_UINT8 * pixels, Q_UINT8 * selectionMask, Q_UINT32 nPixels, KisColorSpace *cs)
00369 {
00370 for (int i = 0; i < m_channels; i++) {
00371 m_outRight.at(i) = 0;
00372 m_outLeft.at(i) = 0;
00373 }
00374
00375 QColor c;
00376 Q_INT32 pSize = cs->pixelSize();
00377 if (selectionMask) {
00378 while (nPixels > 0) {
00379 if ( !((m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) ) {
00380 cs->toQColor(pixels, &c);
00381 m_bins.at(0).at(c.red())++;
00382 m_bins.at(1).at(c.green())++;
00383 m_bins.at(2).at(c.blue())++;
00384
00385 m_count++;
00386 }
00387 pixels += pSize;
00388 selectionMask++;
00389 nPixels--;
00390 }
00391
00392 }
00393 else {
00394 while (nPixels > 0) {
00395
00396 if ( !(m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) {
00397 cs->toQColor(pixels, &c);
00398 m_bins.at(0).at(c.red())++;
00399 m_bins.at(1).at(c.green())++;
00400 m_bins.at(2).at(c.blue())++;
00401
00402 m_count++;
00403 }
00404 pixels += pSize;
00405 nPixels--;
00406 }
00407 }
00408 }
00409
00410
00411 KisGenericLabHistogramProducer::KisGenericLabHistogramProducer()
00412 : KisBasicHistogramProducer(KisID("GENLABHISTO", i18n("L*a*b* Histogram")), 3, 256, 0) {
00413
00414
00415 m_channelsList.append(new KisChannelInfo(i18n("L*"), i18n("L"), 0, KisChannelInfo::COLOR, KisChannelInfo::UINT8));
00416 m_channelsList.append(new KisChannelInfo(i18n("a*"), i18n("a"), 1, KisChannelInfo::COLOR, KisChannelInfo::UINT8));
00417 m_channelsList.append(new KisChannelInfo(i18n("b*"), i18n("b"), 2, KisChannelInfo::COLOR, KisChannelInfo::UINT8));
00418
00419 if (!m_labCs) {
00420 KisProfile *labProfile = new KisProfile(cmsCreateLabProfile(NULL));
00421 m_labCs = new KisLabColorSpace(0, labProfile);
00422 }
00423 m_colorSpace = m_labCs;
00424 }
00425 KisGenericLabHistogramProducer::~KisGenericLabHistogramProducer()
00426 {
00427 delete m_channelsList[0];
00428 delete m_channelsList[1];
00429 delete m_channelsList[2];
00430 }
00431
00432 QValueVector<KisChannelInfo *> KisGenericLabHistogramProducer::channels() {
00433 return m_channelsList;
00434 }
00435
00436 QString KisGenericLabHistogramProducer::positionToString(double pos) const {
00437 return QString("%1").arg(static_cast<Q_UINT16>(pos * UINT16_MAX));
00438 }
00439
00440 double KisGenericLabHistogramProducer::maximalZoom() const {
00441 return 1.0;
00442 }
00443
00444
00445 void KisGenericLabHistogramProducer::addRegionToBin(Q_UINT8 * pixels, Q_UINT8 * selectionMask, Q_UINT32 nPixels, KisColorSpace *cs)
00446 {
00447 for (int i = 0; i < m_channels; i++) {
00448 m_outRight.at(i) = 0;
00449 m_outLeft.at(i) = 0;
00450 }
00451
00452 Q_UINT8 dst[8];
00453 Q_INT32 pSize = cs->pixelSize();
00454
00455 if (selectionMask) {
00456 while (nPixels > 0) {
00457 if ( !((m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) ) {
00458
00459
00460
00461
00462 m_count++;
00463 }
00464 pixels += pSize;
00465 selectionMask++;
00466 nPixels--;
00467 }
00468 }
00469 else {
00470 while (nPixels > 0) {
00471 if ( !(m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) {
00472
00473 cs->convertPixelsTo(pixels, dst, m_colorSpace, 1);
00474 m_bins.at(0).at(m_colorSpace->scaleToU8(dst, 0))++;
00475 m_bins.at(1).at(m_colorSpace->scaleToU8(dst, 1))++;
00476 m_bins.at(2).at(m_colorSpace->scaleToU8(dst, 2))++;
00477
00478 m_count++;
00479 }
00480 pixels += pSize;
00481 nPixels--;
00482 }
00483 }
00484 }
00485