62 const QPolygonF &polygon,
65 QPainter::CompositionMode compositionMode);
72 const QPointF AB =
B -
A;
73 const QPointF BC =
C -
B;
75 return angle < -
M_PI ? angle + 2.0 *
M_PI : (angle >
M_PI ? angle - 2.0 *
M_PI : angle);
78QPair<QPolygonF, QPolygonF>
84 Q_ASSERT(channel >= 0);
86 QPolygonF linearHistogramShape, logarithmicHistogramShape;
88 const qreal heightfactor = 1.0 /
static_cast<qreal
>(highest);
89 const qreal logHeightFactor = 1.0 / std::log(
static_cast<qreal
>(highest + 1));
90 const qreal widthFactor = 1.0 /
static_cast<qreal
>(bins);
94 linearHistogramShape.append(QPointF(0.0, -0.1));
95 linearHistogramShape.append(QPointF(0.0, 0.0));
96 logarithmicHistogramShape.append(QPointF(0.0, -0.1));
97 logarithmicHistogramShape.append(QPointF(0.0, 0.0));
99 for (
int i = 0; i < bins; ++i) {
100 const QPointF
p = QPointF((
static_cast<qreal
>(i) + 0.5) * widthFactor,
101 static_cast<qreal
>(histogram->
getValue(i)) * heightfactor);
102 const QPointF logP = QPointF(
p.x(), std::log(
static_cast<qreal
>(histogram->
getValue(i) + 1)) * logHeightFactor);
103 linearHistogramShape.append(
p);
104 logarithmicHistogramShape.append(logP);
107 linearHistogramShape.append(QPointF(1.0, 0.0));
108 linearHistogramShape.append(QPointF(1.0, -0.1));
109 logarithmicHistogramShape.append(QPointF(1.0, 0.0));
110 logarithmicHistogramShape.append(QPointF(1.0, -0.1));
112 return {linearHistogramShape, logarithmicHistogramShape};
117 const int binOfPercentile =
static_cast<int>(std::round((1.0 - percentageForPercentile) * (polygon.size() - 4 - 1)));
118 std::nth_element(polygon.begin() + 2,
119 polygon.begin() + 2 + binOfPercentile,
121 [](
const QPointF &
p1,
const QPointF &
p2) ->bool
123 return p1.y() > p2.y();
125 const qreal percentile = polygon[binOfPercentile + 2].y();
131 if (polygon.size() < 5) {
135 for (
int i = 2; i < polygon.size() - 2; ++i) {
136 const qreal leftValue = polygon[i - 1].y();
137 const qreal centerValue = polygon[i].y();
138 const qreal rightValue = polygon[i + 1].y();
139 const qreal leftDelta = std::abs(centerValue - leftValue);
140 const qreal rightDelta = std::abs(centerValue - rightValue);
141 const qreal leftWeight = maximumNeighborWeight * std::exp(-
pow2(10.0 * leftDelta));
142 const qreal rightWeight = maximumNeighborWeight * std::exp(-
pow2(10.0 * rightDelta));
143 const qreal centerWeight = 1.0 - leftWeight - rightWeight;
144 polygon[i].setY(leftValue * leftWeight + centerValue * centerWeight + rightValue * rightWeight);
150 if (polygon.size() < 5) {
154 qreal accumulatedOrientationDeviation = 0.0;
155 int numberOfSimplifiedPoints = 0;
157 for (
int i = polygon.size() - 3; i > 1; --i) {
158 accumulatedOrientationDeviation += orientationDeviation(polygon[i + 1], polygon[i], polygon[i - 1]);
159 ++numberOfSimplifiedPoints;
160 if (std::abs(accumulatedOrientationDeviation) > maximumOrientationDeviation ||
161 numberOfSimplifiedPoints > maximumNumberOfSimplifiedPoints) {
162 accumulatedOrientationDeviation = 0.0;
163 numberOfSimplifiedPoints = 0;
170QPair<QColor, QPainter::CompositionMode>
174 Q_ASSERT(colorSpace);
175 Q_ASSERT(channel >= 0);
178 QPainter::CompositionMode compositionMode = QPainter::CompositionMode_SourceOver;
183 }
else if (channel == 1) {
185 }
else if (channel == 2) {
188 compositionMode = QPainter::CompositionMode_Plus;
192 }
else if (channel == 1) {
194 }
else if (channel == 2) {
197 compositionMode = QPainter::CompositionMode_Plus;
201 }
else if (channel == 1) {
203 }
else if (channel == 2) {
205 }
else if (channel == 3) {
214 compositionMode = QPainter::CompositionMode_Multiply;
218 return {color, compositionMode};
222 const QPolygonF &polygon,
225 QPainter::CompositionMode compositionMode)
227 const qreal w =
static_cast<qreal
>(image.width());
228 const qreal h =
static_cast<qreal
>(image.height());
229 const qreal maxH = h * histogramHeightFactor;
232 p.setRenderHint(QPainter::Antialiasing);
234 p.scale(w, -
scale * maxH);
236 pen.setCosmetic(
true);
237 QBrush brush(QColor(color.red(), color.green(), color.blue(), 200));
240 p.setCompositionMode(compositionMode);
241 p.drawPolygon(polygon);
248 QImage image(imageSize, QImage::Format_ARGB32);
251 const int nChannels = histogramChannelShapeInfo.size();
253 if (nChannels == 0 ||
channels.size() == 0) {
257 qreal overallHighest = 0.0;
259 if (!histogramChannelShapeInfo.contains(channel)) {
263 const qreal channelHighest =
static_cast<qreal
>(histogramChannelShapeInfo[channel].highest);
264 if (channelHighest > overallHighest) {
265 overallHighest = channelHighest;
270 if (!histogramChannelShapeInfo.contains(channel)) {
279 ?
scale * std::log(info.
highest + 1.0) / std::log(overallHighest + 1.0)
292 m_d->defaultColor = Qt::gray;
301 Q_ASSERT(colorSpace);
303 const int nChannels =
static_cast<int>(colorSpace->
channelCount());
306 for (
int i = 0; i < nChannels; ++i) {
311 m_d->histogramChannelShapeInfo.clear();
314 if (channel < 0 || channel >= nChannels ||
m_d->histogramChannelShapeInfo.contains(channel)) {
320 const QPair<QColor, QPainter::CompositionMode> channelPaintingInfo =
330 m_d->histogramChannelShapeInfo.insert(
336 linearBestCutOffHeight,
337 logarithmicBestCutOffHeight,
338 channelPaintingInfo.first,
339 channelPaintingInfo.second
347 return m_d->paintChannels(imageSize,
m_d->channelsToPaint,
m_d->isLogarithmic);
352 return paint(QSize(w, h));
357 const QImage image =
m_d->paintChannels(
rect.size(),
m_d->channelsToPaint,
m_d->isLogarithmic);
358 painter.drawImage(
rect.topLeft(), image);
363 return m_d->histogramChannelShapeInfo.size();
368 return m_d->histogramChannelShapeInfo.keys();
373 return m_d->channelsToPaint;
388 return m_d->defaultColor;
393 m_d->defaultColor = newDefaultColor;
403 m_d->scale = newScale;
413 qreal overallHighest = 0.0;
414 qreal fittedChannelHighest = 0.0;
415 qreal bestCutOffHeight = 0.0;
416 for (
int channel :
m_d->channelsToPaint) {
417 if (!
m_d->histogramChannelShapeInfo.contains(channel)) {
421 const qreal channelBestCutOffHeight =
423 ?
m_d->histogramChannelShapeInfo[channel].logarithmicBestCutOffHeight
424 :
m_d->histogramChannelShapeInfo[channel].linearBestCutOffHeight;
425 const qreal channelHighest =
static_cast<qreal
>(
m_d->histogramChannelShapeInfo[channel].highest);
427 if (channelBestCutOffHeight * channelHighest > bestCutOffHeight * fittedChannelHighest) {
428 bestCutOffHeight = channelBestCutOffHeight;
429 fittedChannelHighest = channelHighest;
432 if (channelHighest > overallHighest) {
433 overallHighest = channelHighest;
436 const qreal overallBestCutOffHeight = bestCutOffHeight * fittedChannelHighest / overallHighest;
437 if (overallBestCutOffHeight < 0.8) {
438 setScale(1.0 / overallBestCutOffHeight);
446 return m_d->isLogarithmic;
451 m_d->isLogarithmic = logarithmic;
const KoID XYZAColorModelID("XYZA", ki18n("XYZ/Alpha"))
const KoID CMYKAColorModelID("CMYKA", ki18n("CMYK/Alpha"))
const KoID RGBAColorModelID("RGBA", ki18n("RGB/Alpha"))
QHash< int, HistogramShapeInfo > histogramChannelShapeInfo
static qreal bestCutOffHeight(QPolygonF polygon)
static void smoothHistogramShape(QPolygonF &polygon)
static constexpr qreal maximumNeighborWeight
static QPair< QColor, QPainter::CompositionMode > computeChannelPaintingInfo(const KoColorSpace *colorSpace, int channel)
QVector< int > channelsToPaint
static constexpr qreal maximumOrientationDeviation
static qreal orientationDeviation(const QPointF &A, const QPointF &B, const QPointF &C)
static constexpr qreal percentageForPercentile
static void paintHistogramShape(QImage &image, const QPolygonF &polygon, qreal scale, const QColor &color, QPainter::CompositionMode compositionMode)
static void simplifyHistogramShape(QPolygonF &polygon)
static constexpr qreal histogramHeightFactor
static constexpr int maximumNumberOfSimplifiedPoints
static QPair< QPolygonF, QPolygonF > computeHistogramShape(KisHistogram *histogram, int channel, quint32 highest)
QImage paintChannels(const QSize &imageSize, const QVector< int > &channels={}, bool logarithmic=false)
QList< int > availableChannels() const
Get a list containing all the indices of the channels that were setup using the "setup" function.
void setLogarithmic(bool logarithmic)
Set if the histogram shape being shown is formed by the logarithmic mapping of the original histogram...
QImage paint(const QSize &imageSize)
Returns a RGBA image of size "imageSize" with the result of rendering the selected histogram channels...
const QVector< int > & channels() const
Get the list of channels that are currently activated (the only ones that will be painted)
void setDefaultColor(const QColor &newDefaultColor)
Set the default color used when there is no preference to color the selected histogram channel.
int totalNumberOfAvailableChannels() const
Get the number of channels that are being used. It can be less than the total number of channels in t...
void setScaleToFit()
Set the scale used to paint the histograms to 1.
void setScaleToCutLongPeaks()
Sometimes there can be some outliers in the histogram that show in the painted shape as long vertical...
qreal scale() const
Return the vertical scale that is used to paint the histogram shape. A scale of 1 will paint all the ...
void setChannels(const QVector< int > &channels)
Set currently active channels (the ones that will be painted)
void setup(KisHistogram *histogram, const KoColorSpace *colorSpace, QVector< int > channels={})
Sets up the painter by passing a KisHistogram, the color space for the histogram and the channels tha...
QColor defaultColor() const
Returns the color that is being used to paint a generic histogram. All the histogram channels will us...
bool isLogarithmic() const
Returns true if the histogram shape being painted is formed by the logarithmic mapping of the origina...
void setChannel(int channel)
Set currently active channel (the one that will be painted)
QScopedPointer< Private > m_d
void setScale(qreal newScale)
Set the scale used to paint the histograms.
quint32 getHighest()
This function return the highest value of the histogram.
void setChannel(qint32 channel)
quint32 getValue(quint8 i)
KoHistogramProducer * producer()
Calculations calculations()
virtual KoID colorModelId() const =0
virtual quint32 channelCount() const =0
KoColor convertedTo(const KoColorSpace *cs, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const
void toQColor(QColor *c) const
a convenience method for the above.
virtual qint32 numberOfBins()=0
static bool qFuzzyIsNull(half h)
qreal angleBetweenVectors(const QPointF &v1, const QPointF &v2)
qreal linearBestCutOffHeight
QPolygonF logarithmicHistogram
QPolygonF linearHistogram
QPainter::CompositionMode compositionMode
qreal logarithmicBestCutOffHeight
static KoColorSpaceRegistry * instance()