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