widgets/colorplaneexport_ui.ui
widgets/waveform_ui.ui
widgets/rgbparade_ui.ui
+ widgets/levels_ui.ui
)
set(kdenlive_SRCS
tracksconfigdialog.cpp
configtrackscommand.cpp
abstractscopewidget.cpp
+ rebuildgroupcommand.cpp
+ levels.cpp
+ rgbparade.cpp
vectorscope.cpp
+ waveform.cpp
colorplaneexport.cpp
colortools.cpp
- rebuildgroupcommand.cpp
- waveform.cpp
- rgbparade.cpp
- colorcorrection/waveformgenerator.cpp
- colorcorrection/vectorscopegenerator.cpp
+ colorcorrection/levelsgenerator.cpp
colorcorrection/rgbparadegenerator.cpp
+ colorcorrection/vectorscopegenerator.cpp
+ colorcorrection/waveformgenerator.cpp
razorgroupcommand.cpp
)
initialDimensionUpdateDone = true;
}
+ qDebug() << "Drawing top/left at " << m_scopeRect.topLeft().x() << "/" << m_scopeRect.topLeft().y();
+
QPainter davinci(this);
- davinci.drawImage(scopeRect().topLeft(), m_imgBackground);
- davinci.drawImage(scopeRect().topLeft(), m_imgScope);
- davinci.drawImage(scopeRect().topLeft(), m_imgHUD);
+ davinci.drawImage(m_scopeRect.topLeft(), m_imgBackground);
+ davinci.drawImage(m_scopeRect.topLeft(), m_imgScope);
+ davinci.drawImage(m_scopeRect.topLeft(), m_imgHUD);
}
void AbstractScopeWidget::customContextMenuRequested(const QPoint &pos)
/** Offset from the widget's borders */
const uchar offset;
- /** The rect on the widget we're painting in. */
+ /** The rect on the widget we're painting in.
+ Can be used by the implementing widget, e.g. in the render methods.
+ Is updated when necessary (size changes). */
QRect m_scopeRect;
/** Images storing the calculated layers. Will be used on repaint events. */
--- /dev/null
+/***************************************************************************
+ * 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 <algorithm>
+#include <math.h>
+#include <QDebug>
+#include <QImage>
+#include <QPainter>
+#include "levelsgenerator.h"
+
+LevelsGenerator::LevelsGenerator()
+{
+}
+
+QImage LevelsGenerator::calculateLevels(const QSize ¶deSize, const QImage &image, const int &components, const uint &accelFactor) const
+{
+ qDebug() << "Levels rect size is: " << paradeSize.width() << "/" << paradeSize.height();
+ if (paradeSize.height() <= 0 || paradeSize.width() <= 0) {
+ return QImage();
+ }
+
+ bool drawY = (components & LevelsGenerator::ComponentY) != 0;
+ bool drawR = (components & LevelsGenerator::ComponentR) != 0;
+ bool drawG = (components & LevelsGenerator::ComponentG) != 0;
+ bool drawB = (components & LevelsGenerator::ComponentB) != 0;
+
+ int r[256], g[256], b[256], y[256];
+ // Initialize the values to zero
+ std::fill(r, r+255, 0);
+ std::fill(g, g+255, 0);
+ std::fill(b, b+255, 0);
+ std::fill(y, y+255, 0);
+
+ const uint iw = image.bytesPerLine();
+ const uint ih = image.height();
+ const uint ww = paradeSize.width();
+ const uint wh = paradeSize.height();
+ const uint byteCount = iw*ih;
+ const uint stepsize = 4*accelFactor;
+
+ const uchar *bits = image.bits();
+ QRgb *col;
+
+
+ // Read the stats from the input image
+ for (uint i = 0; i < byteCount; i += stepsize) {
+ col = (QRgb *)bits;
+
+ r[qRed(*col)]++;
+ g[qGreen(*col)]++;
+ b[qBlue(*col)]++;
+ y[(int)floor(.299*qRed(*col) + .587*qGreen(*col) + .114*qBlue(*col))]++;
+
+ bits += stepsize;
+ }
+
+
+ const int nParts = (drawY ? 1 : 0) + (drawR ? 1 : 0) + (drawG ? 1 : 0) + (drawB ? 1 : 0);
+ if (nParts == 0) {
+ // Nothing to draw
+ return QImage();
+ }
+
+ const int d = 20; // Distance for text
+ const int partH = (wh-4*d)/nParts;
+ const float scaling = (float)partH/(byteCount >> 7);
+
+ int wy = 0; // Drawing position
+ int partY; // Vertical position for the dots
+
+ QImage levels(paradeSize, QImage::Format_ARGB32);
+ QImage component(256, partH, QImage::Format_ARGB32);
+ QPainter davinci(&levels);
+ levels.fill(qRgba(0, 0, 0, 0));
+
+ if (drawY) {
+ qDebug() << "Drawing Y at " << wy << " with height " << partH;
+ component.fill(qRgba(0, 0, 0, 0));
+
+ for (int x = 0; x < 256; x++) {
+ // Calculate the height of the curve at position x
+ partY = scaling*y[x];
+
+ // Invert the y axis
+ if (partY > partH-1) { partY = partH-1; }
+ partY = partH-1 - partY;
+
+ for (int k = partH-1; k >= partY; k--) {
+ component.setPixel(x, k, qRgba(220, 220, 210, 255));
+ }
+ }
+
+ davinci.drawImage(0, wy, component.scaled(ww, component.height(), Qt::IgnoreAspectRatio, Qt::FastTransformation));
+
+ wy += partH + d;
+ }
+
+ if (drawR) {
+ qDebug() << "Drawing R at " << wy << " with height " << partH;
+ component.fill(qRgba(0, 0, 0, 0));
+
+ for (int x = 0; x < 256; x++) {
+ // Calculate the height of the curve at position x
+ partY = scaling*r[x];
+
+ // Invert the y axis
+ if (partY > partH-1) { partY = partH-1; }
+ partY = partH-1 - partY;
+
+ for (int k = partH-1; k >= partY; k--) {
+ component.setPixel(x, k, qRgba(255, 128, 0, 255));
+ }
+ }
+
+ davinci.drawImage(0, wy, component.scaled(ww, component.height(), Qt::IgnoreAspectRatio, Qt::FastTransformation));
+
+ wy += partH + d;
+ }
+
+ if (drawG) {
+ qDebug() << "Drawing G at " << wy << " with height " << partH;
+ component.fill(qRgba(0, 0, 0, 0));
+
+ for (int x = 0; x < 256; x++) {
+ // Calculate the height of the curve at position x
+ partY = scaling*g[x];
+
+ // Invert the y axis
+ if (partY > partH-1) { partY = partH-1; }
+ partY = partH-1 - partY;
+
+ for (int k = partH-1; k >= partY; k--) {
+ component.setPixel(x, k, qRgba(128, 255, 0, 255));
+ }
+ }
+
+ davinci.drawImage(0, wy, component.scaled(ww, component.height(), Qt::IgnoreAspectRatio, Qt::FastTransformation));
+
+ wy += partH + d;
+ }
+
+ if (drawB) {
+ qDebug() << "Drawing B at " << wy << " with height " << partH;
+ component.fill(qRgba(0, 0, 0, 0));
+
+ for (int x = 0; x < 256; x++) {
+ // Calculate the height of the curve at position x
+ partY = scaling*b[x];
+
+ // Invert the y axis
+ if (partY > partH-1) { partY = partH-1; }
+ partY = partH-1 - partY;
+
+ for (int k = partH-1; k >= partY; k--) {
+ component.setPixel(x, k, qRgba(0, 128, 255, 255));
+ }
+ }
+
+ davinci.drawImage(0, wy, component.scaled(ww, component.height(), Qt::IgnoreAspectRatio, Qt::FastTransformation));
+
+ wy += partH + d;
+ }
+
+ return levels;
+}
--- /dev/null
+/***************************************************************************
+ * 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 LEVELSGENERATOR_H
+#define LEVELSGENERATOR_H
+
+#include <QObject>
+
+class QImage;
+class QSize;
+
+class LevelsGenerator : public QObject
+{
+public:
+ LevelsGenerator();
+ QImage calculateLevels(const QSize ¶deSize, const QImage &image, const int &components, const uint &accelFactor = 1) const;
+ enum Components { ComponentY = 1<<0, ComponentR = 1<<1, ComponentG = 1<<2, ComponentB = 1<<3 };
+};
+
+#endif // LEVELSGENERATOR_H
--- /dev/null
+/***************************************************************************
+ * 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 <QTime>
+#include "levelsgenerator.h"
+#include "levels.h"
+#include "renderer.h"
+
+Levels::Levels(Monitor *projMonitor, Monitor *clipMonitor, QWidget *parent) :
+ AbstractScopeWidget(projMonitor, clipMonitor, parent)
+{
+ ui = new Ui::Levels_UI();
+ ui->setupUi(this);
+
+ ui->cbY->setChecked(true);
+ ui->cbR->setChecked(true);
+ ui->cbG->setChecked(true);
+ ui->cbB->setChecked(true);
+
+ bool b = true;
+ b &= connect(ui->cbY, SIGNAL(toggled(bool)), this, SLOT(forceUpdateScope()));
+ b &= connect(ui->cbR, SIGNAL(toggled(bool)), this, SLOT(forceUpdateScope()));
+ b &= connect(ui->cbG, SIGNAL(toggled(bool)), this, SLOT(forceUpdateScope()));
+ b &= connect(ui->cbB, SIGNAL(toggled(bool)), this, SLOT(forceUpdateScope()));
+ Q_ASSERT(b);
+}
+
+Levels::~Levels()
+{
+ delete ui;
+}
+
+QString Levels::widgetName() const { return QString("Levels"); }
+
+bool Levels::isHUDDependingOnInput() const { return false; }
+bool Levels::isScopeDependingOnInput() const { return true; }
+bool Levels::isBackgroundDependingOnInput() const { return false; }
+
+QRect Levels::scopeRect()
+{
+ qDebug() << "According to the spacer, the top left point is " << ui->verticalSpacer->geometry().x() << "/" << ui->verticalSpacer->geometry().y();
+ QPoint topleft(offset, offset+ ui->verticalSpacer->geometry().y());
+ return QRect(topleft, this->rect().size() - QSize(topleft.x() + offset, topleft.y() + offset));
+}
+
+QImage Levels::renderHUD(uint)
+{
+ emit signalHUDRenderingFinished(0, 1);
+ return QImage();
+}
+QImage Levels::renderScope(uint accelFactor)
+{
+ QTime start = QTime::currentTime();
+ start.start();
+
+ const int componentFlags = (ui->cbY->isChecked() ? 1 : 0) * LevelsGenerator::ComponentY
+ | (ui->cbR->isChecked() ? 1 : 0) * LevelsGenerator::ComponentR
+ | (ui->cbG->isChecked() ? 1 : 0) * LevelsGenerator::ComponentG
+ | (ui->cbB->isChecked() ? 1 : 0) * LevelsGenerator::ComponentB;
+
+ QImage levels = m_levelsGenerator->calculateLevels(m_scopeRect.size(), m_activeRender->extractFrame(m_activeRender->seekFramePosition()),
+ componentFlags, accelFactor);
+
+ emit signalScopeRenderingFinished(0, 1);
+ return levels;
+}
+QImage Levels::renderBackground(uint)
+{
+ emit signalBackgroundRenderingFinished(0, 1);
+ return QImage();
+}
--- /dev/null
+/***************************************************************************
+ * 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 LEVELS_H
+#define LEVELS_H
+
+#include "abstractscopewidget.h"
+#include "ui_levels_ui.h"
+
+class LevelsGenerator;
+
+class Levels : public AbstractScopeWidget {
+ Q_OBJECT
+
+public:
+ Levels(Monitor *projMonitor, Monitor *clipMonitor, QWidget *parent = 0);
+ ~Levels();
+ QString widgetName() const;
+
+
+private:
+ LevelsGenerator *m_levelsGenerator;
+
+ QRect scopeRect();
+ bool isHUDDependingOnInput() const;
+ bool isScopeDependingOnInput() const;
+ bool isBackgroundDependingOnInput() const;
+ QImage renderHUD(uint accelerationFactor);
+ QImage renderScope(uint accelerationFactor);
+ QImage renderBackground(uint accelerationFactor);
+ Ui::Levels_UI *ui;
+
+};
+
+#endif // LEVELS_H
#include "vectorscope.h"
#include "waveform.h"
#include "rgbparade.h"
+#include "levels.h"
#include <KApplication>
#include <KAction>
m_RGBParadeDock->setWidget(m_RGBParade);
addDockWidget(Qt::TopDockWidgetArea, m_RGBParadeDock);
+ m_levels = new Levels(m_projectMonitor, m_clipMonitor, this);
+ m_levelsDock = new QDockWidget("Levels", this);
+ m_levelsDock->setObjectName(m_levels->widgetName());
+ m_levelsDock->setWidget(m_levels);
+ addDockWidget(Qt::TopDockWidgetArea, m_levelsDock);
+
m_undoViewDock = new QDockWidget(i18n("Undo History"), this);
m_undoViewDock->setObjectName("undo_history");
tabifyDockWidget(m_vectorscopeDock, m_waveformDock);
tabifyDockWidget(m_vectorscopeDock, m_RGBParadeDock);
+ tabifyDockWidget(m_vectorscopeDock, m_levelsDock);
tabifyDockWidget(m_vectorscopeDock, m_undoViewDock);
tabifyDockWidget(m_vectorscopeDock, m_effectListDock);
class DocClipBase;
class Render;
class Transition;
+class Levels;
class Vectorscope;
class Waveform;
class RGBParade;
QDockWidget *m_RGBParadeDock;
RGBParade *m_RGBParade;
+ QDockWidget *m_levelsDock;
+ Levels *m_levels;
+
QDockWidget *m_undoViewDock;
QUndoView *m_undoView;
QUndoGroup *m_commandStack;
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Levels_UI</class>
+ <widget class="QWidget" name="Levels_UI">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QCheckBox" name="cbY">
+ <property name="text">
+ <string>Y</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QCheckBox" name="cbR">
+ <property name="text">
+ <string>R</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2">
+ <widget class="QCheckBox" name="cbG">
+ <property name="text">
+ <string>G</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="3">
+ <widget class="QCheckBox" name="cbB">
+ <property name="text">
+ <string>B</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" colspan="4">
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>