#include "rgbparadegenerator.h"
+#include <KLocalizedString>
+
#include <QColor>
-#include <QDebug>
#include <QPainter>
-#include <QPoint>
-#include <QTime>
#define CHOP255(a) ((255) < (a) ? (255) : (a))
+#define CHOP1255(a) ((a) < (1) ? (1) : ((a) > (255) ? (255) : (a)))
const QColor RGBParadeGenerator::colHighlight(255, 245, 235, 255);
const QColor RGBParadeGenerator::colLight(200, 200, 200, 255);
const QColor RGBParadeGenerator::colSoft(150, 150, 150, 255);
+
+const uchar RGBParadeGenerator::distRight(40);
+const uchar RGBParadeGenerator::distBottom(40);
+
+struct StructRGB {
+ uint r;
+ uint g;
+ uint b;
+};
+
RGBParadeGenerator::RGBParadeGenerator()
{
}
-QImage RGBParadeGenerator::calculateRGBParade(const QSize ¶deSize, const QImage &image, const bool &drawAxis, const uint &accelFactor)
+QImage RGBParadeGenerator::calculateRGBParade(const QSize ¶deSize, const QImage &image,
+ const RGBParadeGenerator::PaintMode paintMode, bool drawAxis,
+ bool drawGradientRef, uint accelFactor)
{
Q_ASSERT(accelFactor >= 1);
} else {
QImage parade(paradeSize, QImage::Format_ARGB32);
- parade.fill(qRgba(0,0,0,0));
+ parade.fill(Qt::transparent);
QRgb *col;
- QRgb paradeCol;
- QPoint paradePoint;
QPainter davinci(¶de);
double dx, dy;
const uint wh = paradeSize.height();
const uint iw = image.bytesPerLine();
const uint ih = image.height();
- const uint byteCount = iw*ih;
+ const uint byteCount = iw*ih; // Note that 1 px = 4 B
const uchar offset = 10;
- const uchar right = 40;
- const uchar bottom = 40;
- const int partW = (ww - 2*offset - right) / 3;
- const int partH = wh - bottom;
-
- // To get constant brightness, independant of acceleration factor and input image size
- // Must be a float because the acceleration factor can be high, leading to <1 expected px per px.
- const float avgPxPerPx = ((float)(image.width() * image.height()) / (500*partW*accelFactor));
- const float weaken = (avgPxPerPx == 0) ? 1 : (float)4/avgPxPerPx;
- const int vh = weaken*27;
- const int vm = weaken*18;
- const int vl = weaken*9;
+ const uint partW = (ww - 2*offset - distRight) / 3;
+ const uint partH = wh - distBottom;
+ // Statistics
uchar minR = 255, minG = 255, minB = 255, maxR = 0, maxG = 0, maxB = 0, r, g, b;
- qDebug() << "Expecting about " << avgPxPerPx << " pixels per pixel in the RGB parade. Weakening by " << weaken
- << " with an acceleration factor of " << accelFactor;
- QImage unscaled(ww-right, 256, QImage::Format_ARGB32);
+ // Number of input pixels that will fall on one scope pixel.
+ // Must be a float because the acceleration factor can be high, leading to <1 expected px per px.
+ const float pixelDepth = (float)((byteCount>>2) / accelFactor)/(partW*255);
+ const float gain = 255/(8*pixelDepth);
+// qDebug() << "Pixel depth: expected " << pixelDepth << "; Gain: using " << gain << " (acceleration: " << accelFactor << "x)";
+
+ QImage unscaled(ww-distRight, 256, QImage::Format_ARGB32);
unscaled.fill(qRgba(0, 0, 0, 0));
const float wPrediv = (float)(partW-1)/(iw-1);
+ StructRGB paradeVals[partW][256];
+ for (uint i = 0; i < partW; ++i) {
+ for (uint j = 0; j < 256; j++) {
+ paradeVals[i][j].r = 0;
+ paradeVals[i][j].g = 0;
+ paradeVals[i][j].b = 0;
+ }
+ }
+
const uchar *bits = image.bits();
- const uint stepsize = 4*accelFactor;
+ const uint stepsize = image.depth() / 8 *accelFactor;
for (uint i = 0, x = 0; i < byteCount; i += stepsize) {
-
col = (QRgb *)bits;
r = qRed(*col);
g = qGreen(*col);
dx = x*wPrediv;
- paradePoint = QPoint((int)dx, r);
- paradeCol = QRgb(unscaled.pixel(paradePoint));
- unscaled.setPixel(paradePoint, qRgba(CHOP255(vh + qRed(paradeCol)), CHOP255(vm + qGreen(paradeCol)),
- CHOP255(vl + qBlue(paradeCol)), 255));
-
- paradePoint = QPoint((int) (dx + partW + offset), g);
- paradeCol = QRgb(unscaled.pixel(paradePoint));
- unscaled.setPixel(paradePoint, qRgba(CHOP255(vl + qRed(paradeCol)), CHOP255(vh + qGreen(paradeCol)),
- CHOP255(vm + qBlue(paradeCol)), 255));
-
- paradePoint = QPoint((int) (dx + 2*partW + 2*offset), b);
- paradeCol = QRgb(unscaled.pixel(paradePoint));
- unscaled.setPixel(paradePoint, qRgba(CHOP255(vm + qRed(paradeCol)), CHOP255(vl + qGreen(paradeCol)),
- CHOP255(vh + qBlue(paradeCol)), 255));
+ paradeVals[(int)dx][r].r++;
+ paradeVals[(int)dx][g].g++;
+ paradeVals[(int)dx][b].b++;
if (r < minR) { minR = r; }
x += stepsize;
x %= iw; // Modulo image width, to represent the current x position in the image
}
+
+
+ const uint offset1 = partW + offset;
+ const uint offset2 = 2*partW + 2*offset;
+ switch(paintMode) {
+ case PaintMode_RGB:
+ for (uint i = 0; i < partW; ++i) {
+ for (uint j = 0; j < 256; j++) {
+ unscaled.setPixel(i, j, qRgba(255,10,10, CHOP255(gain*paradeVals[i][j].r)));
+ unscaled.setPixel(i+offset1, j, qRgba(10,255,10, CHOP255(gain*paradeVals[i][j].g)));
+ unscaled.setPixel(i+offset2, j, qRgba(10,10,255, CHOP255(gain*paradeVals[i][j].b)));
+ }
+ }
+ break;
+ default:
+ for (uint i = 0; i < partW; ++i) {
+ for (uint j = 0; j < 256; j++) {
+ unscaled.setPixel(i, j, qRgba(255,255,255, CHOP255(gain*paradeVals[i][j].r)));
+ unscaled.setPixel(i+offset1, j, qRgba(255,255,255, CHOP255(gain*paradeVals[i][j].g)));
+ unscaled.setPixel(i+offset2, j, qRgba(255,255,255, CHOP255(gain*paradeVals[i][j].b)));
+ }
+ }
+ break;
+ }
+
// Scale the image to the target height. Scaling is not accomplished before because
// there are only 255 different values which would lead to gaps if the height is not exactly 255.
// Don't use bilinear transformation because the fast transformation meets the goal better.
if (drawAxis) {
QRgb opx;
- for (uint i = 0; i <= 10; i++) {
+ for (uint i = 0; i <= 10; ++i) {
dy = (float)i/10 * (partH-1);
- for (uint x = 0; x < ww-right; x++) {
+ for (uint x = 0; x < ww-distRight; x++) {
opx = parade.pixel(x, dy);
parade.setPixel(x,dy, qRgba(CHOP255(150+qRed(opx)), 255,
CHOP255(200+qBlue(opx)), CHOP255(32+qAlpha(opx))));
}
}
}
+
+ if (drawGradientRef) {
+ davinci.setPen(colLight);
+ davinci.drawLine(0 ,partH, partW, 0);
+ davinci.drawLine( partW + offset,partH, 2*partW + offset,0);
+ davinci.drawLine(2*partW + 2*offset,partH, 3*partW + 2*offset,0);
+ }
const int d = 50;
// Show numerical minimum
if (minR == 0) { davinci.setPen(colHighlight); } else { davinci.setPen(colSoft); }
- davinci.drawText(0, wh, "min: ");
+ davinci.drawText(0, wh, i18n("min: "));
if (minG == 0) { davinci.setPen(colHighlight); } else { davinci.setPen(colSoft); }
- davinci.drawText(partW + offset, wh, "min: ");
+ davinci.drawText(partW + offset, wh, i18n("min: "));
if (minB == 0) { davinci.setPen(colHighlight); } else { davinci.setPen(colSoft); }
- davinci.drawText(2*partW + 2*offset, wh, "min: ");
+ davinci.drawText(2*partW + 2*offset, wh, i18n("min: "));
// Show numerical maximum
if (maxR == 255) { davinci.setPen(colHighlight); } else { davinci.setPen(colSoft); }
- davinci.drawText(0, wh-20, "max: ");
+ davinci.drawText(0, wh-20, i18n("max: "));
if (maxG == 255) { davinci.setPen(colHighlight); } else { davinci.setPen(colSoft); }
- davinci.drawText(partW + offset, wh-20, "max: ");
+ davinci.drawText(partW + offset, wh-20, i18n("max: "));
if (maxB == 255) { davinci.setPen(colHighlight); } else { davinci.setPen(colSoft); }
- davinci.drawText(2*partW + 2*offset, wh-20, "max: ");
+ davinci.drawText(2*partW + 2*offset, wh-20, i18n("max: "));
davinci.setPen(colLight);
davinci.drawText(d, wh, QString::number(minR, 'f', 0));
davinci.drawText(partW + offset + d, wh-20, QString::number(maxG, 'f', 0));
davinci.drawText(2*partW + 2*offset + d, wh-20, QString::number(maxB, 'f', 0));
- davinci.drawText(ww-right+5, 10, "255");
- davinci.drawText(ww-right+5, partH+5, "0");
-
-
return parade;
}