2
* Copyright (c) 2005 Bart Coppens <kde@bartcoppens.be>
4
* This program is free software; you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License as published by
6
* the Free Software Foundation; either version 2 of the License, or
7
* (at your option) any later version.
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program; if not, write to the Free Software
16
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
28
#include "kis_global.h"
29
#include "kis_basic_histogram_producers.h"
30
#include "kis_integer_maths.h"
31
#include "kis_channelinfo.h"
32
#include "kis_colorspace.h"
33
#include "kis_lab_colorspace.h"
35
KisLabColorSpace* KisGenericLabHistogramProducer::m_labCs = 0;
38
KisBasicHistogramProducer::KisBasicHistogramProducer(const KisID& id, int channels, int nrOfBins, KisColorSpace *cs)
39
: m_channels(channels),
44
m_bins.resize(m_channels);
45
for (int i = 0; i < m_channels; i++)
46
m_bins.at(i).resize(m_nrOfBins);
47
m_outLeft.resize(m_channels);
48
m_outRight.resize(m_channels);
54
void KisBasicHistogramProducer::clear() {
56
for (int i = 0; i < m_channels; i++) {
57
for (int j = 0; j < m_nrOfBins; j++) {
58
m_bins.at(i).at(j) = 0;
65
void KisBasicHistogramProducer::makeExternalToInternal() {
66
// This function assumes that the pixel is has no 'gaps'. That is to say: if we start
67
// at byte 0, we can get to the end of the pixel by adding consecutive size()s of
69
QValueVector<KisChannelInfo *> c = channels();
70
uint count = c.count();
73
for (uint i = 0; i < count; i++) {
74
for (uint j = 0; j < count; j++) {
75
if (c.at(j)->pos() == currentPos) {
80
currentPos += c.at(m_external.at(m_external.count() - 1))->size();
84
// ------------ U8 ---------------------
86
KisBasicU8HistogramProducer::KisBasicU8HistogramProducer(const KisID& id, KisColorSpace *cs)
87
: KisBasicHistogramProducer(id, cs->nChannels(), 256, cs)
91
QString KisBasicU8HistogramProducer::positionToString(double pos) const {
92
return QString("%1").arg(static_cast<Q_UINT8>(pos * UINT8_MAX));
95
void KisBasicU8HistogramProducer::addRegionToBin(Q_UINT8 * pixels, Q_UINT8 * selectionMask, Q_UINT32 nPixels, KisColorSpace *cs)
97
Q_INT32 pSize = cs->pixelSize();
99
if ( selectionMask ) {
100
while (nPixels > 0) {
101
if ( ! (m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT) ) {
103
for (int i = 0; i < m_channels; i++) {
104
m_bins.at(i).at(pixels[i])++;
116
while (nPixels > 0) {
117
if ( ! (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT) ) {
119
for (int i = 0; i < m_channels; i++) {
120
m_bins.at(i).at(pixels[i])++;
132
// ------------ U16 ---------------------
134
KisBasicU16HistogramProducer::KisBasicU16HistogramProducer(const KisID& id, KisColorSpace *cs)
135
: KisBasicHistogramProducer(id, cs->nChannels(), 256, cs)
139
QString KisBasicU16HistogramProducer::positionToString(double pos) const
141
return QString("%1").arg(static_cast<Q_UINT8>(pos * UINT8_MAX));
144
double KisBasicU16HistogramProducer::maximalZoom() const
149
void KisBasicU16HistogramProducer::addRegionToBin(Q_UINT8 * pixels, Q_UINT8 * selectionMask, Q_UINT32 nPixels, KisColorSpace *cs)
152
Q_UINT16 from = static_cast<Q_UINT16>(m_from * UINT16_MAX);
153
Q_UINT16 width = static_cast<Q_UINT16>(m_width * UINT16_MAX + 0.5); // We include the end
154
Q_UINT16 to = from + width;
155
double factor = 255.0 / width;
157
Q_INT32 pSize = cs->pixelSize();
159
if ( selectionMask ) {
160
Q_UINT16* pixel = reinterpret_cast<Q_UINT16*>(pixels);
161
while (nPixels > 0) {
162
if ( ! ((m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) ) {
163
for (int i = 0; i < m_channels; i++) {
164
Q_UINT16 value = pixel[i];
167
else if (value < from)
170
m_bins.at(i).at(static_cast<Q_UINT8>((value - from) * factor))++;
180
while (nPixels > 0) {
181
Q_UINT16* pixel = reinterpret_cast<Q_UINT16*>(pixels);
183
if ( ! (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) {
184
for (int i = 0; i < m_channels; i++) {
185
Q_UINT16 value = pixel[i];
188
else if (value < from)
191
m_bins.at(i).at(static_cast<Q_UINT8>((value - from) * factor))++;
202
// ------------ Float32 ---------------------
203
KisBasicF32HistogramProducer::KisBasicF32HistogramProducer(const KisID& id, KisColorSpace *cs)
204
: KisBasicHistogramProducer(id, cs->nChannels(), 256, cs)
208
QString KisBasicF32HistogramProducer::positionToString(double pos) const {
209
return QString("%1").arg(static_cast<float>(pos)); // XXX I doubt this is correct!
212
double KisBasicF32HistogramProducer::maximalZoom() const {
213
// 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
217
void KisBasicF32HistogramProducer::addRegionToBin(Q_UINT8 * pixels, Q_UINT8 * selectionMask, Q_UINT32 nPixels, KisColorSpace *cs) {
219
float from = static_cast<float>(m_from);
220
float width = static_cast<float>(m_width);
221
float to = from + width;
222
float factor = 255.0 / width;
224
Q_INT32 pSize = cs->pixelSize();
226
if ( selectionMask ) {
227
while (nPixels > 0) {
229
float* pixel = reinterpret_cast<float*>(pixels);
230
if ( !((m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) ) {
231
for (int i = 0; i < m_channels; i++) {
232
float value = pixel[i];
235
else if (value < from)
238
m_bins.at(i).at(static_cast<Q_UINT8>((value - from) * factor))++;
250
while (nPixels > 0) {
252
float* pixel = reinterpret_cast<float*>(pixels);
253
if ( !(m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) {
254
for (int i = 0; i < m_channels; i++) {
255
float value = pixel[i];
258
else if (value < from)
261
m_bins.at(i).at(static_cast<Q_UINT8>((value - from) * factor))++;
274
// ------------ Float16 Half ---------------------
275
KisBasicF16HalfHistogramProducer::KisBasicF16HalfHistogramProducer(const KisID& id,
277
: KisBasicHistogramProducer(id, cs->nChannels(), 256, cs) {
280
QString KisBasicF16HalfHistogramProducer::positionToString(double pos) const {
281
return QString("%1").arg(static_cast<float>(pos)); // XXX I doubt this is correct!
284
double KisBasicF16HalfHistogramProducer::maximalZoom() const {
285
// 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
289
void KisBasicF16HalfHistogramProducer::addRegionToBin(Q_UINT8 * pixels, Q_UINT8 * selectionMask, Q_UINT32 nPixels, KisColorSpace *cs) {
291
float from = static_cast<float>(m_from);
292
float width = static_cast<float>(m_width);
293
float to = from + width;
294
float factor = 255.0 / width;
296
Q_INT32 pSize = cs->pixelSize();
297
if ( selectionMask ) {
298
while (nPixels > 0) {
299
half* pixel = reinterpret_cast<half*>(pixels);
300
if ( !((m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) ) {
301
for (int i = 0; i < m_channels; i++) {
302
float value = pixel[i];
305
else if (value < from)
308
m_bins.at(i).at(static_cast<Q_UINT8>((value - from) * factor))++;
318
while (nPixels > 0) {
319
half* pixel = reinterpret_cast<half*>(pixels);
320
if ( !(m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) {
321
for (int i = 0; i < m_channels; i++) {
322
float value = pixel[i];
325
else if (value < from)
328
m_bins.at(i).at(static_cast<Q_UINT8>((value - from) * factor))++;
339
// ------------ Generic RGB ---------------------
340
KisGenericRGBHistogramProducer::KisGenericRGBHistogramProducer()
341
: KisBasicHistogramProducer(KisID("GENRGBHISTO", i18n("Generic RGB Histogram")),
343
/* we set 0 as colorspece, because we are not based on a specific colorspace. This
344
is no problem for the superclass since we override channels() */
345
m_channelsList.append(new KisChannelInfo(i18n("R"), 0, KisChannelInfo::COLOR, KisChannelInfo::UINT8, 1, QColor(255,0,0)));
346
m_channelsList.append(new KisChannelInfo(i18n("G"), 1, KisChannelInfo::COLOR, KisChannelInfo::UINT8, 1, QColor(0,255,0)));
347
m_channelsList.append(new KisChannelInfo(i18n("B"), 2, KisChannelInfo::COLOR, KisChannelInfo::UINT8, 1, QColor(0,0,255)));
350
QValueVector<KisChannelInfo *> KisGenericRGBHistogramProducer::channels() {
351
return m_channelsList;
354
QString KisGenericRGBHistogramProducer::positionToString(double pos) const {
355
return QString("%1").arg(static_cast<Q_UINT8>(pos * UINT8_MAX));
358
double KisGenericRGBHistogramProducer::maximalZoom() const {
363
void KisGenericRGBHistogramProducer::addRegionToBin(Q_UINT8 * pixels, Q_UINT8 * selectionMask, Q_UINT32 nPixels, KisColorSpace *cs)
365
for (int i = 0; i < m_channels; i++) {
366
m_outRight.at(i) = 0;
371
Q_INT32 pSize = cs->pixelSize();
373
while (nPixels > 0) {
374
if ( !((m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) ) {
375
cs->toQColor(pixels, &c);
376
m_bins.at(0).at(c.red())++;
377
m_bins.at(1).at(c.green())++;
378
m_bins.at(2).at(c.blue())++;
389
while (nPixels > 0) {
391
if ( !(m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) {
392
cs->toQColor(pixels, &c);
393
m_bins.at(0).at(c.red())++;
394
m_bins.at(1).at(c.green())++;
395
m_bins.at(2).at(c.blue())++;
405
// ------------ Generic L*a*b* ---------------------
406
KisGenericLabHistogramProducer::KisGenericLabHistogramProducer()
407
: KisBasicHistogramProducer(KisID("GENLABHISTO", i18n("L*a*b* Histogram")), 3, 256, 0) {
408
/* we set 0 as colorspace, because we are not based on a specific colorspace. This
409
is no problem for the superclass since we override channels() */
410
m_channelsList.append(new KisChannelInfo(i18n("L*"), 0, KisChannelInfo::COLOR, KisChannelInfo::UINT8));
411
m_channelsList.append(new KisChannelInfo(i18n("a*"), 1, KisChannelInfo::COLOR, KisChannelInfo::UINT8));
412
m_channelsList.append(new KisChannelInfo(i18n("b*"), 2, KisChannelInfo::COLOR, KisChannelInfo::UINT8));
415
KisProfile *labProfile = new KisProfile(cmsCreateLabProfile(NULL));
416
m_labCs = new KisLabColorSpace(0, labProfile);
418
m_colorSpace = m_labCs;
420
KisGenericLabHistogramProducer::~KisGenericLabHistogramProducer()
422
delete m_channelsList[0];
423
delete m_channelsList[1];
424
delete m_channelsList[2];
427
QValueVector<KisChannelInfo *> KisGenericLabHistogramProducer::channels() {
428
return m_channelsList;
431
QString KisGenericLabHistogramProducer::positionToString(double pos) const {
432
return QString("%1").arg(static_cast<Q_UINT16>(pos * UINT16_MAX));
435
double KisGenericLabHistogramProducer::maximalZoom() const {
440
void KisGenericLabHistogramProducer::addRegionToBin(Q_UINT8 * pixels, Q_UINT8 * selectionMask, Q_UINT32 nPixels, KisColorSpace *cs)
442
for (int i = 0; i < m_channels; i++) {
443
m_outRight.at(i) = 0;
448
Q_INT32 pSize = cs->pixelSize();
451
while (nPixels > 0) {
452
if ( !((m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) ) {
454
cs->toQColor(pixels, &c);
455
m_bins.at(0).at(c.red())++;
465
while (nPixels > 0) {
466
if ( !(m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) {
468
cs->convertPixelsTo(pixels, dst, m_colorSpace, 1);
469
m_bins.at(0).at(m_colorSpace->scaleToU8(dst, 0))++;
470
m_bins.at(1).at(m_colorSpace->scaleToU8(dst, 1))++;
471
m_bins.at(2).at(m_colorSpace->scaleToU8(dst, 2))++;