1 /***************************************************************************
2 * Copyright (C) 2010 by Simon Andreas Eugster (simon.eu@gmail.com) *
3 * This file is part of kdenlive. See www.kdenlive.org. *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 ***************************************************************************/
11 #include "rgbparadegenerator.h"
18 #define CHOP255(a) ((255) < (a) ? (255) : (a))
19 #define CHOP1255(a) ((a) < (1) ? (1) : ((a) > (255) ? (255) : (a)))
21 const QColor RGBParadeGenerator::colHighlight(255, 245, 235, 255);
22 const QColor RGBParadeGenerator::colLight(200, 200, 200, 255);
23 const QColor RGBParadeGenerator::colSoft(150, 150, 150, 255);
26 const uchar RGBParadeGenerator::distRight(40);
27 const uchar RGBParadeGenerator::distBottom(40);
35 RGBParadeGenerator::RGBParadeGenerator()
39 QImage RGBParadeGenerator::calculateRGBParade(const QSize ¶deSize, const QImage &image,
40 const RGBParadeGenerator::PaintMode paintMode, const bool &drawAxis,
41 const bool &drawGradientRef, const uint &accelFactor)
43 Q_ASSERT(accelFactor >= 1);
45 if (paradeSize.width() <= 0 || paradeSize.height() <= 0 || image.width() <= 0 || image.height() <= 0) {
49 QImage parade(paradeSize, QImage::Format_ARGB32);
50 parade.fill(Qt::transparent);
53 QPainter davinci(¶de);
57 const uint ww = paradeSize.width();
58 const uint wh = paradeSize.height();
59 const uint iw = image.bytesPerLine();
60 const uint ih = image.height();
61 const uint byteCount = iw*ih; // Note that 1 px = 4 B
63 const uchar offset = 10;
64 const uint partW = (ww - 2*offset - distRight) / 3;
65 const uint partH = wh - distBottom;
68 uchar minR = 255, minG = 255, minB = 255, maxR = 0, maxG = 0, maxB = 0, r, g, b;
71 // Number of input pixels that will fall on one scope pixel.
72 // Must be a float because the acceleration factor can be high, leading to <1 expected px per px.
73 const float pixelDepth = (float)((byteCount>>2) / accelFactor)/(partW*255);
74 const float gain = 255/(8*pixelDepth);
75 // qDebug() << "Pixel depth: expected " << pixelDepth << "; Gain: using " << gain << " (acceleration: " << accelFactor << "x)";
77 QImage unscaled(ww-distRight, 256, QImage::Format_ARGB32);
78 unscaled.fill(qRgba(0, 0, 0, 0));
80 const float wPrediv = (float)(partW-1)/(iw-1);
82 StructRGB paradeVals[partW][256];
83 for (uint i = 0; i < partW; ++i) {
84 for (uint j = 0; j < 256; j++) {
85 paradeVals[i][j].r = 0;
86 paradeVals[i][j].g = 0;
87 paradeVals[i][j].b = 0;
91 const uchar *bits = image.bits();
92 const uint stepsize = image.depth() / 8 *accelFactor;
94 for (uint i = 0, x = 0; i < byteCount; i += stepsize) {
102 paradeVals[(int)dx][r].r++;
103 paradeVals[(int)dx][g].g++;
104 paradeVals[(int)dx][b].b++;
107 if (r < minR) { minR = r; }
108 if (g < minG) { minG = g; }
109 if (b < minB) { minB = b; }
110 if (r > maxR) { maxR = r; }
111 if (g > maxG) { maxG = g; }
112 if (b > maxB) { maxB = b; }
116 x %= iw; // Modulo image width, to represent the current x position in the image
120 const uint offset1 = partW + offset;
121 const uint offset2 = 2*partW + 2*offset;
124 for (uint i = 0; i < partW; ++i) {
125 for (uint j = 0; j < 256; j++) {
126 unscaled.setPixel(i, j, qRgba(255,10,10, CHOP255(gain*paradeVals[i][j].r)));
127 unscaled.setPixel(i+offset1, j, qRgba(10,255,10, CHOP255(gain*paradeVals[i][j].g)));
128 unscaled.setPixel(i+offset2, j, qRgba(10,10,255, CHOP255(gain*paradeVals[i][j].b)));
133 for (uint i = 0; i < partW; ++i) {
134 for (uint j = 0; j < 256; j++) {
135 unscaled.setPixel(i, j, qRgba(255,255,255, CHOP255(gain*paradeVals[i][j].r)));
136 unscaled.setPixel(i+offset1, j, qRgba(255,255,255, CHOP255(gain*paradeVals[i][j].g)));
137 unscaled.setPixel(i+offset2, j, qRgba(255,255,255, CHOP255(gain*paradeVals[i][j].b)));
143 // Scale the image to the target height. Scaling is not accomplished before because
144 // there are only 255 different values which would lead to gaps if the height is not exactly 255.
145 // Don't use bilinear transformation because the fast transformation meets the goal better.
146 davinci.drawImage(0, 0, unscaled.mirrored(false, true).scaled(unscaled.width(), partH, Qt::IgnoreAspectRatio, Qt::FastTransformation));
150 for (uint i = 0; i <= 10; ++i) {
151 dy = (float)i/10 * (partH-1);
152 for (uint x = 0; x < ww-distRight; x++) {
153 opx = parade.pixel(x, dy);
154 parade.setPixel(x,dy, qRgba(CHOP255(150+qRed(opx)), 255,
155 CHOP255(200+qBlue(opx)), CHOP255(32+qAlpha(opx))));
160 if (drawGradientRef) {
161 davinci.setPen(colLight);
162 davinci.drawLine(0 ,partH, partW, 0);
163 davinci.drawLine( partW + offset,partH, 2*partW + offset,0);
164 davinci.drawLine(2*partW + 2*offset,partH, 3*partW + 2*offset,0);
170 // Show numerical minimum
171 if (minR == 0) { davinci.setPen(colHighlight); } else { davinci.setPen(colSoft); }
172 davinci.drawText(0, wh, "min: ");
173 if (minG == 0) { davinci.setPen(colHighlight); } else { davinci.setPen(colSoft); }
174 davinci.drawText(partW + offset, wh, "min: ");
175 if (minB == 0) { davinci.setPen(colHighlight); } else { davinci.setPen(colSoft); }
176 davinci.drawText(2*partW + 2*offset, wh, "min: ");
178 // Show numerical maximum
179 if (maxR == 255) { davinci.setPen(colHighlight); } else { davinci.setPen(colSoft); }
180 davinci.drawText(0, wh-20, "max: ");
181 if (maxG == 255) { davinci.setPen(colHighlight); } else { davinci.setPen(colSoft); }
182 davinci.drawText(partW + offset, wh-20, "max: ");
183 if (maxB == 255) { davinci.setPen(colHighlight); } else { davinci.setPen(colSoft); }
184 davinci.drawText(2*partW + 2*offset, wh-20, "max: ");
186 davinci.setPen(colLight);
187 davinci.drawText(d, wh, QString::number(minR, 'f', 0));
188 davinci.drawText(partW + offset + d, wh, QString::number(minG, 'f', 0));
189 davinci.drawText(2*partW + 2*offset + d, wh, QString::number(minB, 'f', 0));
191 davinci.drawText(d, wh-20, QString::number(maxR, 'f', 0));
192 davinci.drawText(partW + offset + d, wh-20, QString::number(maxG, 'f', 0));
193 davinci.drawText(2*partW + 2*offset + d, wh-20, QString::number(maxB, 'f', 0));