krita

kis_basic_histogram_producers.cc

00001 /*
00002  *  Copyright (c) 2005 Bart Coppens <kde@bartcoppens.be>
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
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     // This function assumes that the pixel is has no 'gaps'. That is to say: if we start
00067     // at byte 0, we can get to the end of the pixel by adding consecutive size()s of
00068     // the channels
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 // ------------ U8 ---------------------
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 // ------------ U16 ---------------------
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     // The view
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); // We include the end
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 // ------------ Float32 ---------------------
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)); // XXX I doubt this is correct!
00214 }
00215 
00216 double KisBasicF32HistogramProducer::maximalZoom() const {
00217     // 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
00218     return 1.0 / 255.0;
00219 }
00220 
00221 void KisBasicF32HistogramProducer::addRegionToBin(Q_UINT8 * pixels, Q_UINT8 * selectionMask, Q_UINT32 nPixels, KisColorSpace *cs) {
00222     // The view
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 // ------------ Float16 Half ---------------------
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)); // XXX I doubt this is correct!
00286 }
00287 
00288 double KisBasicF16HalfHistogramProducer::maximalZoom() const {
00289     // 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
00290     return 1.0 / 255.0;
00291 }
00292 
00293 void KisBasicF16HalfHistogramProducer::addRegionToBin(Q_UINT8 * pixels, Q_UINT8 * selectionMask, Q_UINT32 nPixels, KisColorSpace *cs) {
00294     // The view
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 // ------------ Generic RGB ---------------------
00344 KisGenericRGBHistogramProducer::KisGenericRGBHistogramProducer()
00345     : KisBasicHistogramProducer(KisID("GENRGBHISTO", i18n("Generic RGB Histogram")),
00346                                 3, 256, 0) {
00347     /* we set 0 as colorspece, because we are not based on a specific colorspace. This
00348        is no problem for the superclass since we override channels() */
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 // ------------ Generic L*a*b* ---------------------
00410 KisGenericLabHistogramProducer::KisGenericLabHistogramProducer()
00411     : KisBasicHistogramProducer(KisID("GENLABHISTO", i18n("L*a*b* Histogram")), 3, 256, 0) {
00412     /* we set 0 as colorspace, because we are not based on a specific colorspace. This
00413        is no problem for the superclass since we override channels() */
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   cs->toQColor(pixels, &c);
00459   m_bins.at(0).at(c.red())++;
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 
KDE Home | KDE Accessibility Home | Description of Access Keys