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