X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fcolorcorrection%2Frgbparadegenerator.cpp;h=6d85d08168601b29535c30ba22218c79b66cf1df;hb=f5a501e9143701fb25054d859d0e0d1d5eb5b4dc;hp=fe494e8399f1f62ca718a96f8abfa754af22682f;hpb=2ce698b921225589844447f223963614d4b74158;p=kdenlive diff --git a/src/colorcorrection/rgbparadegenerator.cpp b/src/colorcorrection/rgbparadegenerator.cpp index fe494e83..6d85d081 100644 --- a/src/colorcorrection/rgbparadegenerator.cpp +++ b/src/colorcorrection/rgbparadegenerator.cpp @@ -10,41 +10,46 @@ #include "rgbparadegenerator.h" +#include + #include -#include #include -#include -#include #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); - QImage parade(paradeSize, QImage::Format_ARGB32); - - if (paradeSize.width() <= 0 || paradeSize.height() <= 0) { - qCritical("Wave size should not be 0."); + if (paradeSize.width() <= 0 || paradeSize.height() <= 0 || image.width() <= 0 || image.height() <= 0) { + return QImage(); } else { - - qDebug() << "Wave calculation started."; - - // Fill with transparent color - parade.fill(qRgba(0,0,0,0)); + QImage parade(paradeSize, QImage::Format_ARGB32); + parade.fill(Qt::transparent); QRgb *col; - QRgb paradeCol; - QPoint paradePoint; QPainter davinci(¶de); double dx, dy; @@ -53,37 +58,40 @@ QImage RGBParadeGenerator::calculateRGBParade(const QSize ¶deSize, const QIm 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); @@ -91,20 +99,9 @@ QImage RGBParadeGenerator::calculateRGBParade(const QSize ¶deSize, const QIm 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; } @@ -118,6 +115,31 @@ QImage RGBParadeGenerator::calculateRGBParade(const QSize ¶deSize, const QIm 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. @@ -125,34 +147,41 @@ QImage RGBParadeGenerator::calculateRGBParade(const QSize ¶deSize, const QIm 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)); @@ -163,15 +192,9 @@ QImage RGBParadeGenerator::calculateRGBParade(const QSize ¶deSize, const QIm 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; } - - return parade; } #undef CHOP255