File indexing completed on 2024-12-22 04:14:49
0001 /* 0002 * SPDX-FileCopyrightText: 2016 Eugene Ingerman <geneing at gmail dot com> 0003 * 0004 * SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "histogramdockerwidget.h" 0008 0009 #include <QThread> 0010 #include <QVector> 0011 #include <limits> 0012 #include <algorithm> 0013 #include <QTime> 0014 #include <QPainter> 0015 #include <QPainterPath> 0016 #include <functional> 0017 0018 #include "KoChannelInfo.h" 0019 #include "KisViewManager.h" 0020 #include "kis_canvas2.h" 0021 0022 0023 0024 HistogramDockerWidget::HistogramDockerWidget(QWidget *parent, const char *name, Qt::WindowFlags f) 0025 : KisWidgetWithIdleTask<QLabel>(parent, f) 0026 { 0027 setObjectName(name); 0028 qRegisterMetaType<HistogramData>(); 0029 } 0030 0031 HistogramDockerWidget::~HistogramDockerWidget() 0032 { 0033 } 0034 0035 void HistogramDockerWidget::receiveNewHistogram(HistogramData data) 0036 { 0037 m_histogramData = data.bins; 0038 m_colorSpace = data.colorSpace; 0039 update(); 0040 } 0041 0042 KisIdleTasksManager::TaskGuard HistogramDockerWidget::registerIdleTask(KisCanvas2 *canvas) 0043 { 0044 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(canvas, KisIdleTasksManager::TaskGuard()); 0045 0046 return 0047 canvas->viewManager()->idleTasksManager()-> 0048 addIdleTaskWithGuard([this](KisImageSP image) { 0049 HistogramComputationStrokeStrategy* strategy = 0050 new HistogramComputationStrokeStrategy(image); 0051 0052 connect(strategy, SIGNAL(computationResultReady(HistogramData)), this, SLOT(receiveNewHistogram(HistogramData))); 0053 0054 return strategy; 0055 }); 0056 } 0057 0058 void HistogramDockerWidget::clearCachedState() 0059 { 0060 m_colorSpace = 0; 0061 m_histogramData.clear(); 0062 } 0063 0064 void HistogramDockerWidget::paintEvent(QPaintEvent *event) 0065 { 0066 if (m_colorSpace && !m_histogramData.empty()) { 0067 int nBins = m_histogramData.at(0).size(); 0068 const KoColorSpace* cs = m_colorSpace; 0069 0070 QLabel::paintEvent(event); 0071 QPainter painter(this); 0072 painter.fillRect(0, 0, this->width(), this->height(), this->palette().dark().color()); 0073 painter.setPen(this->palette().light().color()); 0074 0075 const int NGRID = 4; 0076 for (int i = 0; i <= NGRID; ++i) { 0077 painter.drawLine(this->width()*i / NGRID, 0., this->width()*i / NGRID, this->height()); 0078 painter.drawLine(0., this->height()*i / NGRID, this->width(), this->height()*i / NGRID); 0079 } 0080 0081 unsigned int nChannels = cs->channelCount(); 0082 const QList<KoChannelInfo *> channels = cs->channels(); 0083 unsigned int highest = 0; 0084 //find the most populous bin in the histogram to scale it properly 0085 for (int chan = 0; chan < channels.size(); chan++) { 0086 if (channels.at(chan)->channelType() != KoChannelInfo::ALPHA) { 0087 std::vector<quint32> histogramTemp = m_histogramData.at(chan); 0088 //use 98th percentile, rather than max for better visual appearance 0089 int nthPercentile = 2 * histogramTemp.size() / 100; 0090 //unsigned int max = *std::max_element(m_histogramData.at(chan).begin(),m_histogramData.at(chan).end()); 0091 std::nth_element(histogramTemp.begin(), 0092 histogramTemp.begin() + nthPercentile, histogramTemp.end(), std::greater<int>()); 0093 unsigned int max = *(histogramTemp.begin() + nthPercentile); 0094 0095 highest = std::max(max, highest); 0096 } 0097 } 0098 0099 painter.setWindow(QRect(-1, 0, nBins + 1, highest)); 0100 painter.setCompositionMode(QPainter::CompositionMode_Plus); 0101 0102 for (int chan = 0; chan < (int)nChannels; chan++) { 0103 if (channels.at(chan)->channelType() != KoChannelInfo::ALPHA) { 0104 QColor color = channels.at(chan)->color(); 0105 0106 //special handling of grayscale color spaces. can't use color returned above. 0107 if(cs->colorChannelCount()==1){ 0108 color = QColor(Qt::gray); 0109 } 0110 0111 QColor fill_color = color; 0112 fill_color.setAlphaF(.25); 0113 painter.setBrush(fill_color); 0114 QPen pen = QPen(color); 0115 pen.setWidth(0); 0116 painter.setPen(pen); 0117 0118 if (m_smoothHistogram) { 0119 QPainterPath path; 0120 path.moveTo(QPointF(-1, highest)); 0121 for (qint32 i = 0; i < nBins; ++i) { 0122 float v = std::max((float)highest - m_histogramData[chan][i], 0.f); 0123 path.lineTo(QPointF(i, v)); 0124 0125 } 0126 path.lineTo(QPointF(nBins + 1, highest)); 0127 path.closeSubpath(); 0128 painter.drawPath(path); 0129 } else { 0130 pen.setWidth(1); 0131 painter.setPen(pen); 0132 for (qint32 i = 0; i < nBins; ++i) { 0133 float v = std::max((float)highest - m_histogramData[chan][i], 0.f); 0134 painter.drawLine(QPointF(i, highest), QPointF(i, v)); 0135 } 0136 } 0137 } 0138 } 0139 } 0140 }