tResX->setText("800");
tResY->setText("800");
- cbColorspace->addItem(i18n("YUV"), QVariant(CPE_YUV));
+ cbColorspace->addItem(i18n("YUV UV plane"), QVariant(CPE_YUV));
+ cbColorspace->addItem(i18n("YUV Y plane"), QVariant(CPE_YUV_Y));
cbColorspace->addItem(i18n("Modified YUV (Chroma)"), QVariant(CPE_YUV_MOD));
+ cbColorspace->addItem(i18n("RGB plane, one component varying"), QVariant(CPE_RGB_CURVE));
sliderColor->setSliderPosition(128);
connect(kurlrequester, SIGNAL(textChanged(QString)), this, SLOT(slotValidate()));
connect(sliderColor, SIGNAL(valueChanged(int)), this, SLOT(slotUpdateDisplays()));
connect(sliderScaling, SIGNAL(valueChanged(int)), this, SLOT(slotUpdateDisplays()));
+ connect(cbColorspace, SIGNAL(currentIndexChanged(int)), this, SLOT(slotColormodeChanged()));
kurlrequester->setText("/tmp/yuv-plane.png");
delete m_colorTools;
}
+
+
+///// Helper functions /////
+
+void ColorPlaneExport::enableSliderScaling(const bool &enable)
+{
+ sliderScaling->setEnabled(enable);
+ lblScaling->setEnabled(enable);
+ lblScaleNr->setEnabled(enable);
+}
+
+void ColorPlaneExport::enableSliderColor(const bool &enable)
+{
+ sliderColor->setEnabled(enable);
+ lblSliderName->setEnabled(enable);
+ lblColNr->setEnabled(enable);
+}
+
+void ColorPlaneExport::enableCbVariant(const bool &enable)
+{
+ cbVariant->setEnabled(enable);
+ lblVariant->setEnabled(enable);
+ if (!enable) {
+ while (cbVariant->count() > 0) {
+ cbVariant->removeItem(0);
+ }
+ }
+}
+
+
+
+///// Slots /////
+
void ColorPlaneExport::slotUpdateDisplays()
{
m_scaling = 1 - (float)sliderScaling->value()/100;
lblScaleNr->setText("0..." + QString::number(m_scaling, 'f', 2));
- lblColNr->setText(QString::number(sliderColor->value()));
+
+ switch (cbColorspace->itemData(cbColorspace->currentIndex()).toInt()) {
+ case CPE_YUV_Y:
+ lblColNr->setText(i18n("%1 °", QString::number(sliderColor->value())));
+ break;
+ default:
+ lblColNr->setText(QString::number(sliderColor->value()));
+ break;
+ }
lblSize->setText(i18n("%1 px", QVariant(tResX->text()).toInt()*QVariant(tResY->text()).toInt()));
}
case CPE_YUV:
img = m_colorTools->yuvColorWheel(size, sliderColor->value(), m_scaling, false, false);
break;
+ case CPE_YUV_Y:
+ img = m_colorTools->yuvVerticalPlane(size, sliderColor->value(), m_scaling);
+ break;
case CPE_YUV_MOD:
img = m_colorTools->yuvColorWheel(size, sliderColor->value(), m_scaling, true, false);
break;
+ case CPE_RGB_CURVE:
+ img = m_colorTools->rgbCurvePlane(size, (ColorTools::ColorsRGB) (cbVariant->itemData(cbVariant->currentIndex()).toInt()));
+ break;
}
img.save(kurlrequester->text());
}
void ColorPlaneExport::slotColormodeChanged()
{
+ qDebug() << "Color mode changed to " << cbColorspace->itemData(cbColorspace->currentIndex()).toInt();
switch (cbColorspace->itemData(cbColorspace->currentIndex()).toInt()) {
case CPE_YUV:
case CPE_YUV_MOD:
- sliderColor->setVisible(true);
+ enableSliderScaling(true);
+ enableSliderColor(true);
+ enableCbVariant(false);
sliderColor->setRange(0,255);
+ sliderColor->setPageStep(128);
+ lblSliderName->setText(i18n("Y value"));
+ lblSliderName->setToolTip(i18n("The Y value describes the brightness of the colors."));
+ break;
+ case CPE_YUV_Y:
+ qDebug() << "Changing slider range.";
+ enableSliderScaling(true);
+ enableSliderColor(true);
+ enableCbVariant(false);
+ sliderColor->setMaximum(321);
+ sliderColor->setRange(0,179);
+ sliderColor->setPageStep(90);
+ lblSliderName->setText(i18n("UV angle"));
+ lblSliderName->setToolTip(i18n("Angle through the UV plane, with all possible Y values."));
break;
+ case CPE_RGB_CURVE:
+ // deliberately fall through
default:
- sliderColor->setVisible(false);
+ enableSliderScaling(false);
+ enableSliderColor(false);
+ enableCbVariant(true);
+ cbVariant->addItem(i18n("Red"), QVariant(ColorTools::COL_R));
+ cbVariant->addItem(i18n("Green"), QVariant(ColorTools::COL_G));
+ cbVariant->addItem(i18n("Blue"), QVariant(ColorTools::COL_B));
break;
}
+ this->update();
+ slotUpdateDisplays();
}
class ColorPlaneExport_UI;
-enum COLOR_EXPORT_MODE { CPE_YUV, CPE_YUV_MOD };
+enum COLOR_EXPORT_MODE { CPE_YUV, CPE_YUV_Y, CPE_YUV_MOD, CPE_RGB_CURVE };
class ColorPlaneExport : public QDialog, public Ui::ColorPlaneExport_UI {
Q_OBJECT
ColorTools *m_colorTools;
float m_scaling;
float m_Y;
+ void enableSliderScaling(const bool &enable);
+ void enableSliderColor(const bool &enable);
+ void enableCbVariant(const bool &enable);
private slots:
-QImage ColorTools::yuvColorWheel(const QSize &size, unsigned char Y, float scaling, bool modifiedVersion, bool circleOnly)
+QImage ColorTools::yuvColorWheel(const QSize &size, const unsigned char &Y, const float &scaling, const bool &modifiedVersion, const bool &circleOnly)
{
QImage wheel(size, QImage::Format_ARGB32);
if (size.width() == 0 || size.height() == 0) {
emit signalWheelCalculationFinished();
return wheel;
}
+
+QImage ColorTools::yuvVerticalPlane(const QSize &size, const float &angle, const float &scaling)
+{
+ QImage plane(size, QImage::Format_ARGB32);
+ if (size.width() == 0 || size.height() == 0) {
+ qCritical("ERROR: Size of the color plane must not be 0!");
+ return plane;
+ }
+
+ double dr, dg, db, du, dv, Y;
+ const int w = size.width();
+ const int h = size.height();
+ const double uscaling = scaling*cos(M_PI*angle/180);
+ const double vscaling = scaling*sin(M_PI*angle/180);
+
+ for (int uv = 0; uv < w; uv++) {
+ du = uscaling*((double)2*uv/w - 1);//(double)?
+ dv = vscaling*((double)2*uv/w - 1);
+
+ for (int y = 0; y < h; y++) {
+ Y = (double)255*y/h;
+
+ // See yuv2rgb, yuvColorWheel
+ dr = Y + 290.8*dv;
+ dg = Y - 100.6*du - 148*dv;
+ db = Y + 517.2*du;
+ if (dr < 0) dr = 0;
+ if (dg < 0) dg = 0;
+ if (db < 0) db = 0;
+ if (dr > 255) dr = 255;
+ if (dg > 255) dg = 255;
+ if (db > 255) db = 255;
+
+ plane.setPixel(uv, (h-y-1), qRgba(dr, dg, db, 255));
+
+ }
+ }
+
+
+ return plane;
+
+}
+
+QImage ColorTools::rgbCurvePlane(const QSize &size, const ColorsRGB &color)
+{
+ QImage plane(size, QImage::Format_ARGB32);
+ if (size.width() == 0 || size.height() == 0) {
+ qCritical("ERROR: Size of the color plane must not be 0!");
+ return plane;
+ }
+
+ const int w = size.width();
+ const int h = size.height();
+
+ double dcol, dval;
+
+ for (int x = 0; x < w; x++) {
+ dval = (double)255*x/w;
+
+ for (int y = 0; y < h; y++) {
+ dcol = (double)255*y/h;
+
+ if (color == ColorTools::COL_R) {
+ plane.setPixel(x, (h-y-1), qRgb(dcol, dval, dval));
+ } else if (color == ColorTools::COL_G) {
+ plane.setPixel(x, (h-y-1), qRgb(dval, dcol, dval));
+ } else {
+ plane.setPixel(x, (h-y-1), qRgb(dval, dval, dcol));
+ }
+
+ }
+ }
+ return plane;
+}
+
+
+
+
+
+
+
+
#include <QImage>
+
+
class ColorTools : public QObject
{
Q_OBJECT
public:
ColorTools();
+ enum ColorsRGB { COL_R, COL_G, COL_B };
+
/**
@brief Draws a UV plane with given Y value.
scaling defines how far to zoom in (or out). Lower value = zoom in.
If not the full rect should be filled, set circleOnly to true.
See also: http://en.wikipedia.org/wiki/YUV and http://de.wikipedia.org/wiki/Vektorskop
*/
- QImage yuvColorWheel(const QSize& size, const unsigned char Y, const float scaling, const bool modifiedVersion, const bool circleOnly);
+ QImage yuvColorWheel(const QSize& size, const unsigned char &Y, const float &scaling, const bool &modifiedVersion, const bool &circleOnly);
+ /**
+ @brief Draws a UV plane with given UV angle (ratio u:v stays constant)
+ scaling defines how far to zoom in (or out). Lower value = zoom in.
+ angle defines the angle in a default U/V plane. A vertical plane, on which Y goes from 0 to 1,
+ is then laid through the UV plane, with the defined angle.
+ @see yuvColorWheel()
+ */
+ QImage yuvVerticalPlane(const QSize &size, const float &angle, const float &scaling);
+ /**
+ @brief Draws a RGB plane with two values on one axis and one on the other.
+ This is e.g. useful as background for a curves dialog. On the line from bottom left to top right
+ are neutral colors. The colors on the y axis show what the neutral color will look like when modifying the curve.
+ color defines the color to modify on the y axis. The other two components will be increased
+ in equal terms (linear as well) on the x axis.
+ */
+ QImage rgbCurvePlane(const QSize &size, const ColorTools::ColorsRGB &color);
signals:
void signalWheelCalculationFinished();
QPoint pt;
QRgb px;
+ // Just an average for the number of image pixels per scope pixel.
+ double avgPxPerPx = (double) 4*img.byteCount()/scope.size().width()/scope.size().height()/skipPixels;
+ qDebug() << "Expecting " << avgPxPerPx << " pixels per pixel.";
+
const QRect scopeRect(QPoint(0,0), scope.size());
for (int i = 0; i < img.byteCount(); i+= stepsize) {
break;
case PAINT_GREEN:
px = scope.pixel(pt);
- scope.setPixel(pt, qRgba(qRed(px)+(255-qRed(px))/30, 255, qBlue(px)+(255-qBlue(px))/25, qAlpha(px)+(255-qAlpha(px))/20));
+ scope.setPixel(pt, qRgba(qRed(px)+(255-qRed(px))/(3*avgPxPerPx), qGreen(px)+20*(255-qGreen(px))/(avgPxPerPx),
+ qBlue(px)+(255-qBlue(px))/(avgPxPerPx), qAlpha(px)+(255-qAlpha(px))/(avgPxPerPx)));
break;
case PAINT_GREEN2:
px = scope.pixel(pt);
- scope.setPixel(pt, qRgba(qRed(px)+ceil((255-(float)qRed(px))/30), 255,
- qBlue(px)+ceil((255-(float)qBlue(px))/25), qAlpha(px)+ceil((255-(float)qAlpha(px))/20)));
+ scope.setPixel(pt, qRgba(qRed(px)+ceil((255-(float)qRed(px))/(4*avgPxPerPx)), 255,
+ qBlue(px)+ceil((255-(float)qBlue(px))/(avgPxPerPx)), qAlpha(px)+ceil((255-(float)qAlpha(px))/(avgPxPerPx))));
break;
case PAINT_BLACK:
px = scope.pixel(pt);
circleEnabled = false;
}
+
+ // Draw realtime factor (number of skipped pixels)
+ if (m_aRealtime->isChecked()) {
+ davinci.setPen(penThin);
+ davinci.drawText(m_scopeRect.bottomRight()-QPoint(40,15), QVariant(m_skipPixels).toString().append("x"));
+ }
+
}
<rect>
<x>0</x>
<y>0</y>
- <width>488</width>
- <height>213</height>
+ <width>553</width>
+ <height>241</height>
</rect>
</property>
<property name="windowTitle">
<string>Export color plane to PNG</string>
</property>
- <widget class="QWidget" name="gridLayoutWidget">
- <property name="geometry">
- <rect>
- <x>10</x>
- <y>10</y>
- <width>471</width>
- <height>193</height>
- </rect>
- </property>
- <layout class="QGridLayout" name="gridLayout">
- <property name="horizontalSpacing">
- <number>10</number>
- </property>
- <item row="0" column="0">
- <widget class="QLabel" name="lblSpace">
- <property name="text">
- <string>Color space</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1" colspan="3">
- <widget class="QComboBox" name="cbColorspace">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- </widget>
- </item>
- <item row="3" column="0">
- <widget class="QLabel" name="lblRes">
- <property name="text">
- <string>Resolution</string>
- </property>
- </widget>
- </item>
- <item row="3" column="1">
- <widget class="QLineEdit" name="tResX">
- <property name="maxLength">
- <number>5</number>
- </property>
- </widget>
- </item>
- <item row="3" column="3">
- <widget class="QLineEdit" name="tResY">
- <property name="maxLength">
- <number>5</number>
- </property>
- </widget>
- </item>
- <item row="3" column="2">
- <widget class="QLabel" name="lblTimes">
- <property name="text">
- <string notr="true">×</string>
- </property>
- </widget>
- </item>
- <item row="5" column="0">
- <widget class="QLabel" name="lblFilename">
- <property name="text">
- <string>Filename</string>
- </property>
- </widget>
- </item>
- <item row="5" column="1" colspan="3">
- <widget class="KUrlRequester" name="kurlrequester">
- <property name="mode">
- <set>KFile::File|KFile::LocalOnly</set>
- </property>
- </widget>
- </item>
- <item row="4" column="1" colspan="3">
- <widget class="QLabel" name="lblSize">
- <property name="font">
- <font>
- <pointsize>8</pointsize>
- </font>
- </property>
- <property name="text">
- <string notr="true">(notranslate) Total pixels go here</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- </widget>
- </item>
- <item row="6" column="1" colspan="3">
- <widget class="QDialogButtonBox" name="buttonBox">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="standardButtons">
- <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
- </property>
- </widget>
- </item>
- <item row="1" column="1" colspan="2">
- <widget class="QSlider" name="sliderColor">
- <property name="toolTip">
- <string>The Y value describes the brightness of the colors.</string>
- </property>
- <property name="whatsThis">
- <string/>
- </property>
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="lblSliderName">
- <property name="text">
- <string>Y value</string>
- </property>
- </widget>
- </item>
- <item row="1" column="3">
- <widget class="QLabel" name="lblColNr">
- <property name="text">
- <string notr="true">(notranslate) Y display</string>
- </property>
- </widget>
- </item>
- <item row="2" column="1" colspan="2">
- <widget class="QSlider" name="sliderScaling">
- <property name="toolTip">
- <string>How much to zoom in</string>
- </property>
- <property name="whatsThis">
- <string/>
- </property>
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- </widget>
- </item>
- <item row="2" column="3">
- <widget class="QLabel" name="lblScaleNr">
- <property name="text">
- <string>(notranslate) % display</string>
- </property>
- </widget>
- </item>
- <item row="2" column="0">
- <widget class="QLabel" name="lblScaling">
- <property name="text">
- <string>Scaling</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="lblSpace">
+ <property name="text">
+ <string>Color space</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" colspan="3">
+ <widget class="QComboBox" name="cbColorspace">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" colspan="2">
+ <widget class="QLabel" name="lblVariant">
+ <property name="text">
+ <string>Variant</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="3">
+ <widget class="QComboBox" name="cbVariant"/>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="lblSliderName">
+ <property name="text">
+ <string notr="true">(notr.ansl.)</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QSlider" name="sliderColor">
+ <property name="whatsThis">
+ <string/>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="3">
+ <widget class="QLabel" name="lblColNr">
+ <property name="text">
+ <string notr="true">(notranslate) Y display</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="lblScaling">
+ <property name="text">
+ <string>Scaling</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QSlider" name="sliderScaling">
+ <property name="toolTip">
+ <string>How much to zoom in</string>
+ </property>
+ <property name="whatsThis">
+ <string/>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="3">
+ <widget class="QLabel" name="lblScaleNr">
+ <property name="text">
+ <string>(notranslate) % display</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0">
+ <widget class="QLabel" name="lblRes">
+ <property name="text">
+ <string>Resolution</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="QLineEdit" name="tResX">
+ <property name="maxLength">
+ <number>5</number>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="2">
+ <widget class="QLabel" name="lblTimes">
+ <property name="text">
+ <string notr="true">×</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="3">
+ <widget class="QLineEdit" name="tResY">
+ <property name="maxLength">
+ <number>5</number>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="1" colspan="3">
+ <widget class="QLabel" name="lblSize">
+ <property name="font">
+ <font>
+ <pointsize>8</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">(notranslate) Total pixels go here</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="0">
+ <widget class="QLabel" name="lblFilename">
+ <property name="text">
+ <string>Filename</string>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="1" colspan="3">
+ <widget class="KUrlRequester" name="kurlrequester">
+ <property name="mode">
+ <set>KFile::File|KFile::LocalOnly</set>
+ </property>
+ </widget>
+ </item>
+ <item row="7" column="1" colspan="3">
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
</widget>
<customwidgets>
<customwidget>