From: Simon A. Eugster Date: Wed, 21 Jul 2010 18:54:19 +0000 (+0000) Subject: RGB Parade added. X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=2ce698b921225589844447f223963614d4b74158;p=kdenlive RGB Parade added. Testwidget removed, not necessary anymore. svn path=/trunk/kdenlive/; revision=4616 --- diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 14334550..40732b5b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -93,7 +93,7 @@ kde4_add_ui_files(kdenlive_UI widgets/vectorscope_ui.ui widgets/colorplaneexport_ui.ui widgets/waveform_ui.ui - widgets/testwidget_ui.ui + widgets/rgbparade_ui.ui ) set(kdenlive_SRCS @@ -201,9 +201,10 @@ set(kdenlive_SRCS colortools.cpp rebuildgroupcommand.cpp waveform.cpp + rgbparade.cpp colorcorrection/waveformgenerator.cpp colorcorrection/vectorscopegenerator.cpp - testwidget.cpp + colorcorrection/rgbparadegenerator.cpp razorgroupcommand.cpp ) diff --git a/src/colorcorrection/rgbparadegenerator.cpp b/src/colorcorrection/rgbparadegenerator.cpp new file mode 100644 index 00000000..fe494e83 --- /dev/null +++ b/src/colorcorrection/rgbparadegenerator.cpp @@ -0,0 +1,177 @@ +/*************************************************************************** + * Copyright (C) 2010 by Simon Andreas Eugster (simon.eu@gmail.com) * + * This file is part of kdenlive. See www.kdenlive.org. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "rgbparadegenerator.h" + +#include +#include +#include +#include +#include + +#define CHOP255(a) ((255) < (a) ? (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); + +RGBParadeGenerator::RGBParadeGenerator() +{ +} + +QImage RGBParadeGenerator::calculateRGBParade(const QSize ¶deSize, const QImage &image, const bool &drawAxis, const 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."); + + } else { + + qDebug() << "Wave calculation started."; + + // Fill with transparent color + parade.fill(qRgba(0,0,0,0)); + + QRgb *col; + QRgb paradeCol; + QPoint paradePoint; + QPainter davinci(¶de); + + double dx, dy; + + const uint ww = paradeSize.width(); + const uint wh = paradeSize.height(); + const uint iw = image.bytesPerLine(); + const uint ih = image.height(); + const uint byteCount = iw*ih; + + 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; + + 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); + unscaled.fill(qRgba(0, 0, 0, 0)); + + const float wPrediv = (float)(partW-1)/(iw-1); + + const uchar *bits = image.bits(); + const uint stepsize = 4*accelFactor; + + for (uint i = 0, x = 0; i < byteCount; i += stepsize) { + + col = (QRgb *)bits; + r = qRed(*col); + g = qGreen(*col); + b = qBlue(*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)); + + + if (r < minR) { minR = r; } + if (g < minG) { minG = g; } + if (b < minB) { minB = b; } + if (r > maxR) { maxR = r; } + if (g > maxG) { maxG = g; } + if (b > maxB) { maxB = b; } + + bits += stepsize; + x += stepsize; + x %= iw; // Modulo image width, to represent the current x position in the image + } + // 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. + davinci.drawImage(0, 0, unscaled.mirrored(false, true).scaled(unscaled.width(), partH, Qt::IgnoreAspectRatio, Qt::FastTransformation)); + + if (drawAxis) { + QRgb opx; + for (uint i = 0; i <= 10; i++) { + dy = (float)i/10 * (partH-1); + for (uint x = 0; x < ww-right; x++) { + opx = parade.pixel(x, dy); + parade.setPixel(x,dy, qRgba(CHOP255(150+qRed(opx)), 255, + CHOP255(200+qBlue(opx)), CHOP255(32+qAlpha(opx)))); + } + } + } + + + const int d = 50; + + // Show numerical minimum + if (minR == 0) { davinci.setPen(colHighlight); } else { davinci.setPen(colSoft); } + davinci.drawText(0, wh, "min: "); + if (minG == 0) { davinci.setPen(colHighlight); } else { davinci.setPen(colSoft); } + davinci.drawText(partW + offset, wh, "min: "); + if (minB == 0) { davinci.setPen(colHighlight); } else { davinci.setPen(colSoft); } + davinci.drawText(2*partW + 2*offset, wh, "min: "); + + // Show numerical maximum + if (maxR == 255) { davinci.setPen(colHighlight); } else { davinci.setPen(colSoft); } + davinci.drawText(0, wh-20, "max: "); + if (maxG == 255) { davinci.setPen(colHighlight); } else { davinci.setPen(colSoft); } + davinci.drawText(partW + offset, wh-20, "max: "); + if (maxB == 255) { davinci.setPen(colHighlight); } else { davinci.setPen(colSoft); } + davinci.drawText(2*partW + 2*offset, wh-20, "max: "); + + davinci.setPen(colLight); + davinci.drawText(d, wh, QString::number(minR, 'f', 0)); + davinci.drawText(partW + offset + d, wh, QString::number(minG, 'f', 0)); + davinci.drawText(2*partW + 2*offset + d, wh, QString::number(minB, 'f', 0)); + + davinci.drawText(d, wh-20, QString::number(maxR, '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; +} + +#undef CHOP255 diff --git a/src/colorcorrection/rgbparadegenerator.h b/src/colorcorrection/rgbparadegenerator.h new file mode 100644 index 00000000..e3722103 --- /dev/null +++ b/src/colorcorrection/rgbparadegenerator.h @@ -0,0 +1,30 @@ +/*************************************************************************** + * Copyright (C) 2010 by Simon Andreas Eugster (simon.eu@gmail.com) * + * This file is part of kdenlive. See www.kdenlive.org. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#ifndef RGBPARADEGENERATOR_H +#define RGBPARADEGENERATOR_H + +#include + +class QColor; +class QImage; +class QSize; +class RGBParadeGenerator : public QObject +{ +public: + RGBParadeGenerator(); + QImage calculateRGBParade(const QSize ¶deSize, const QImage &image, const bool &drawAxis, const uint &accelFactor = 1); + + static const QColor colHighlight; + static const QColor colLight; + static const QColor colSoft; +}; + +#endif // RGBPARADEGENERATOR_H diff --git a/src/colorcorrection/waveformgenerator.cpp b/src/colorcorrection/waveformgenerator.cpp index 648691c5..62c5c74e 100644 --- a/src/colorcorrection/waveformgenerator.cpp +++ b/src/colorcorrection/waveformgenerator.cpp @@ -111,3 +111,4 @@ QImage WaveformGenerator::calculateWaveform(const QSize &waveformSize, const QIm return wave; } +#undef CHOP255 diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 7cdcafcf..836fa7fb 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -54,7 +54,7 @@ #include "ui_templateclip_ui.h" #include "vectorscope.h" #include "waveform.h" -#include "testwidget.h" +#include "rgbparade.h" #include #include @@ -217,21 +217,21 @@ MainWindow::MainWindow(const QString &MltPath, const KUrl & Url, QWidget *parent m_vectorscope = new Vectorscope(m_projectMonitor, m_clipMonitor, this); m_vectorscopeDock = new QDockWidget(i18n("Vectorscope"), this); - m_vectorscopeDock->setObjectName("vectorscope"); + m_vectorscopeDock->setObjectName(m_vectorscope->widgetName()); m_vectorscopeDock->setWidget(m_vectorscope); addDockWidget(Qt::TopDockWidgetArea, m_vectorscopeDock); m_waveform = new Waveform(m_projectMonitor, m_clipMonitor, this); m_waveformDock = new QDockWidget(i18n("Waveform"), this); - m_waveformDock->setObjectName("waveform"); + m_waveformDock->setObjectName(m_waveform->widgetName()); m_waveformDock->setWidget(m_waveform); addDockWidget(Qt::TopDockWidgetArea, m_waveformDock); - m_test = new TestWidget(m_projectMonitor, m_clipMonitor, this); - m_testDock = new QDockWidget("Test", this); - m_testDock->setObjectName("test"); - m_testDock->setWidget(m_test); - addDockWidget(Qt::TopDockWidgetArea, m_testDock); + m_RGBParade = new RGBParade(m_projectMonitor, m_clipMonitor, this); + m_RGBParadeDock = new QDockWidget("RGB Parade", this); + m_RGBParadeDock->setObjectName(m_RGBParade->widgetName()); + m_RGBParadeDock->setWidget(m_RGBParade); + addDockWidget(Qt::TopDockWidgetArea, m_RGBParadeDock); m_undoViewDock = new QDockWidget(i18n("Undo History"), this); @@ -263,6 +263,7 @@ MainWindow::MainWindow(const QString &MltPath, const KUrl & Url, QWidget *parent #endif tabifyDockWidget(m_vectorscopeDock, m_waveformDock); + tabifyDockWidget(m_vectorscopeDock, m_RGBParadeDock); tabifyDockWidget(m_vectorscopeDock, m_undoViewDock); tabifyDockWidget(m_vectorscopeDock, m_effectListDock); @@ -423,6 +424,7 @@ MainWindow::MainWindow(const QString &MltPath, const KUrl & Url, QWidget *parent connect(m_monitorManager, SIGNAL(raiseClipMonitor(bool)), this, SLOT(slotRaiseMonitor(bool))); connect(m_monitorManager, SIGNAL(raiseClipMonitor(bool)), m_vectorscope, SLOT(slotActiveMonitorChanged(bool))); connect(m_monitorManager, SIGNAL(raiseClipMonitor(bool)), m_waveform, SLOT(slotActiveMonitorChanged(bool))); + connect(m_monitorManager, SIGNAL(raiseClipMonitor(bool)), m_RGBParade, SLOT(slotActiveMonitorChanged(bool))); connect(m_effectList, SIGNAL(addEffect(const QDomElement)), this, SLOT(slotAddEffect(const QDomElement))); connect(m_effectList, SIGNAL(reloadEffects()), this, SLOT(slotReloadEffects())); @@ -3610,6 +3612,7 @@ void MainWindow::slotShowTitleBars(bool show) m_undoViewDock->setTitleBarWidget(0); m_vectorscopeDock->setTitleBarWidget(0); m_waveformDock->setTitleBarWidget(0); + m_RGBParadeDock->setTitleBarWidget(0); } else { if (!m_effectStackDock->isFloating()) { m_effectStackDock->setTitleBarWidget(new QWidget(this)); } if (!m_clipMonitorDock->isFloating()) { m_clipMonitorDock->setTitleBarWidget(new QWidget(this)); } @@ -3623,6 +3626,7 @@ void MainWindow::slotShowTitleBars(bool show) if (!m_undoViewDock->isFloating()) { m_undoViewDock->setTitleBarWidget(new QWidget(this)); } if (!m_vectorscopeDock->isFloating()) { m_vectorscopeDock->setTitleBarWidget(new QWidget(this)); } if (!m_waveformDock->isFloating()) { m_waveformDock->setTitleBarWidget(new QWidget(this)); } + if (!m_RGBParadeDock->isFloating()) { m_RGBParadeDock->setTitleBarWidget(new QWidget(this)); } } KdenliveSettings::setShowtitlebars(show); } diff --git a/src/mainwindow.h b/src/mainwindow.h index 0e8c2935..983d4867 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -63,7 +63,7 @@ class Render; class Transition; class Vectorscope; class Waveform; -class TestWidget; +class RGBParade; class KActionCollection; class MainWindow : public KXmlGuiWindow @@ -159,8 +159,8 @@ private: QDockWidget *m_waveformDock; Waveform *m_waveform; - QDockWidget *m_testDock; - TestWidget *m_test; + QDockWidget *m_RGBParadeDock; + RGBParade *m_RGBParade; QDockWidget *m_undoViewDock; QUndoView *m_undoView; diff --git a/src/rgbparade.cpp b/src/rgbparade.cpp new file mode 100644 index 00000000..7e891540 --- /dev/null +++ b/src/rgbparade.cpp @@ -0,0 +1,53 @@ +/*************************************************************************** + * Copyright (C) 2010 by Simon Andreas Eugster (simon.eu@gmail.com) * + * This file is part of kdenlive. See www.kdenlive.org. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include +#include +#include "renderer.h" +#include "rgbparade.h" +#include "rgbparadegenerator.h" + +RGBParade::RGBParade(Monitor *projMonitor, Monitor *clipMonitor, QWidget *parent) : + AbstractScopeWidget(projMonitor, clipMonitor, parent) +{ + ui = new Ui::RGBParade_UI(); + ui->setupUi(this); + m_rgbParadeGenerator = new RGBParadeGenerator(); +} + +RGBParade::~RGBParade() +{ + delete ui; + delete m_rgbParadeGenerator; +} + +QString RGBParade::widgetName() const { return "RGB Parade"; } + +QRect RGBParade::scopeRect() +{ + QPoint topleft(offset, ui->line->y() + 2*offset); + return QRect(topleft, QPoint(this->size().width() - offset, this->size().height() - offset) - topleft); +} + +QImage RGBParade::renderHUD(uint) { return QImage(); } +QImage RGBParade::renderScope(uint accelerationFactor) +{ + QTime start = QTime::currentTime(); + start.start(); + QImage parade = m_rgbParadeGenerator->calculateRGBParade(m_scopeRect.size(), m_activeRender->extractFrame(m_activeRender->seekFramePosition()), + true, accelerationFactor); + emit signalScopeRenderingFinished(start.elapsed(), accelerationFactor); + return parade; +} +QImage RGBParade::renderBackground(uint) { return QImage(); } + +bool RGBParade::isHUDDependingOnInput() const { return false; } +bool RGBParade::isScopeDependingOnInput() const { return true; } +bool RGBParade::isBackgroundDependingOnInput() const { return false; } diff --git a/src/testwidget.h b/src/rgbparade.h similarity index 72% rename from src/testwidget.h rename to src/rgbparade.h index ff567572..a02fb8da 100644 --- a/src/testwidget.h +++ b/src/rgbparade.h @@ -8,40 +8,39 @@ * (at your option) any later version. * ***************************************************************************/ -#ifndef TESTWIDGET_H -#define TESTWIDGET_H +#ifndef RGBPARADE_H +#define RGBPARADE_H -#include +#include #include "abstractscopewidget.h" -#include "ui_testwidget_ui.h" +#include "ui_rgbparade_ui.h" -class AbstractScopeWidget; -class TestWidget_UI; +class Monitor; +class QImage; +class RGBParade_UI; +class RGBParadeGenerator; -class TestWidget : public AbstractScopeWidget { - Q_OBJECT +class RGBParade : public AbstractScopeWidget +{ public: - TestWidget(Monitor *projMonitor, Monitor *clipMonitor, QWidget *parent = 0); - virtual ~TestWidget(); - + RGBParade(Monitor *projMonitor, Monitor *clipMonitor, QWidget *parent = 0); + ~RGBParade(); QString widgetName() const; - /// Implemented methods /// - QImage renderHUD(uint accelerationFactor); - QImage renderScope(uint accelerationFactor); - QImage renderBackground(uint accelerationFactor); - bool isHUDDependingOnInput() const; - bool isScopeDependingOnInput() const; - bool isBackgroundDependingOnInput() const; - protected: QRect scopeRect(); private: - Ui::TestWidget_UI *ui; + Ui::RGBParade_UI *ui; + RGBParadeGenerator *m_rgbParadeGenerator; - QAction *m_aTest; + bool isHUDDependingOnInput() const; + bool isScopeDependingOnInput() const; + bool isBackgroundDependingOnInput() const; + QImage renderHUD(uint accelerationFactor); + QImage renderScope(uint accelerationFactor); + QImage renderBackground(uint accelerationFactor); }; -#endif // TESTWIDGET_H +#endif // RGBPARADE_H diff --git a/src/testwidget.cpp b/src/testwidget.cpp deleted file mode 100644 index 0e6c942a..00000000 --- a/src/testwidget.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2010 by Simon Andreas Eugster (simon.eu@gmail.com) * - * This file is part of kdenlive. See www.kdenlive.org. * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - ***************************************************************************/ - -#include "testwidget.h" -#include "ui_testwidget_ui.h" - -#include -#include - -TestWidget::TestWidget(Monitor *projMonitor, Monitor *clipMonitor, QWidget *parent) : - AbstractScopeWidget(projMonitor, clipMonitor, parent) -{ - ui = new Ui::TestWidget_UI(); - ui->setupUi(this); - - m_aTest = new QAction("Hallo. ", this); - m_menu->addAction(m_aTest); -} - -TestWidget::~TestWidget() -{ - delete ui; - delete m_aTest; -} - -///// Implemented Methods ///// - -QImage TestWidget::renderHUD(uint) -{ - emit signalHUDRenderingFinished(0, 1); - return QImage(); -} - -QImage TestWidget::renderScope(uint) -{ - emit signalScopeRenderingFinished(0, 1); - return QImage(); -} - -QImage TestWidget::renderBackground(uint) -{ - emit signalBackgroundRenderingFinished(0, 1); - return QImage(); -} - -QString TestWidget::widgetName() const { return "Testwidget"; } -bool TestWidget::isHUDDependingOnInput() const { return false; } -bool TestWidget::isScopeDependingOnInput() const { return false; } -bool TestWidget::isBackgroundDependingOnInput() const { return false; } - -QRect TestWidget::scopeRect() -{ - return QRect(QPoint(offset, ui->line->y() + 2*offset), this->rect().bottomRight() - QPoint(offset, offset)); -} - diff --git a/src/vectorscope.cpp b/src/vectorscope.cpp index 7a966e3a..841e76d2 100644 --- a/src/vectorscope.cpp +++ b/src/vectorscope.cpp @@ -26,7 +26,6 @@ const float P75 = .75; const unsigned char DEFAULT_Y = 255; -//const unsigned int REALTIME_FPS = 15; // in fps. const QPointF YUV_R(-.147, .615); const QPointF YUV_G(-.289, -.515); @@ -114,9 +113,7 @@ Vectorscope::~Vectorscope() delete m_a75PBox; } -QString Vectorscope::widgetName() const { - return QString("Vectorscope"); -} +QString Vectorscope::widgetName() const { return QString("Vectorscope"); } QRect Vectorscope::scopeRect() { diff --git a/src/widgets/testwidget_ui.ui b/src/widgets/rgbparade_ui.ui similarity index 54% rename from src/widgets/testwidget_ui.ui rename to src/widgets/rgbparade_ui.ui index 1eefcdd5..f711ca6e 100644 --- a/src/widgets/testwidget_ui.ui +++ b/src/widgets/rgbparade_ui.ui @@ -1,7 +1,7 @@ - TestWidget_UI - + RGBParade_UI + 0 @@ -11,13 +11,30 @@ - Form + RGB Parade + + 5 + + + + + + 0 + 0 + + + + - + + + Paint mode + + - + Qt::Vertical @@ -30,7 +47,7 @@ - + Qt::Horizontal