1 /***************************************************************************
2 * Copyright (C) 2010 by Simon Andreas Eugster (simon.eu@gmail.com) *
3 * This file is part of kdenlive. See www.kdenlive.org. *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 ***************************************************************************/
12 #include "colortools.h"
14 ColorTools::ColorTools()
20 QImage ColorTools::yuvColorWheel(const QSize &size, const unsigned char &Y, const float &scaling, const bool &modifiedVersion, const bool &circleOnly)
22 QImage wheel(size, QImage::Format_ARGB32);
23 if (size.width() == 0 || size.height() == 0) {
24 qCritical("ERROR: Size of the color wheel must not be 0!");
28 wheel.fill(qRgba(0,0,0,0));
31 double dr, dg, db, du, dv, dmax;
33 const int w = size.width();
34 const int h = size.height();
35 const float w2 = (float)w/2;
36 const float h2 = (float)h/2;
38 for (int u = 0; u < w; u++) {
39 // Transform u from {0,...,w} to [-1,1]
40 du = (double) 2*u/(w-1) - 1;
43 for (int v = 0; v < h; v++) {
44 dv = (double) 2*v/(h-1) - 1;
48 // Ellipsis equation: x²/a² + y²/b² = 1
49 // Here: x=ru, y=rv, a=w/2, b=h/2, 1=rr
50 // For rr > 1, the point lies outside. Don't draw it.
53 rr = ru*ru/(w2*w2) + rv*rv/(h2*h2);
59 // Calculate the RGB values from YUV
61 dg = Y - 100.6*du - 148*dv;
64 if (modifiedVersion) {
65 // Scale the RGB values down, or up, to max 255
67 if (fabs(dg) > dmax) dmax = fabs(dg);
68 if (fabs(db) > dmax) dmax = fabs(db);
76 // Avoid overflows (which would generate intersting patterns).
77 // Note that not all possible (y,u,v) values with u,v \in [-1,1]
78 // have a correct RGB representation, therefore some RGB values
79 // may exceed {0,...,255}.
83 if (dr > 255) dr = 255;
84 if (dg > 255) dg = 255;
85 if (db > 255) db = 255;
87 wheel.setPixel(u, (h-v-1), qRgba(dr, dg, db, 255));
91 emit signalYuvWheelCalculationFinished();
95 QImage ColorTools::yuvVerticalPlane(const QSize &size, const float &angle, const float &scaling)
97 QImage plane(size, QImage::Format_ARGB32);
98 if (size.width() == 0 || size.height() == 0) {
99 qCritical("ERROR: Size of the color plane must not be 0!");
103 double dr, dg, db, du, dv, Y;
104 const int w = size.width();
105 const int h = size.height();
106 const double uscaling = scaling*cos(M_PI*angle/180);
107 const double vscaling = scaling*sin(M_PI*angle/180);
109 for (int uv = 0; uv < w; uv++) {
110 du = uscaling*((double)2*uv/w - 1);//(double)?
111 dv = vscaling*((double)2*uv/w - 1);
113 for (int y = 0; y < h; y++) {
116 // See yuv2rgb, yuvColorWheel
118 dg = Y - 100.6*du - 148*dv;
123 if (dr > 255) dr = 255;
124 if (dg > 255) dg = 255;
125 if (db > 255) db = 255;
127 plane.setPixel(uv, (h-y-1), qRgba(dr, dg, db, 255));
137 QImage ColorTools::rgbCurvePlane(const QSize &size, const ColorTools::ColorsRGB &color, float scaling)
139 Q_ASSERT(scaling > 0 && scaling <= 1);
141 QImage plane(size, QImage::Format_ARGB32);
142 if (size.width() == 0 || size.height() == 0) {
143 qCritical("ERROR: Size of the color plane must not be 0!");
147 const int w = size.width();
148 const int h = size.height();
153 for (int x = 0; x < w; x++) {
154 dval = (double)255*x/(w-1);
156 for (int y = 0; y < h; y++) {
157 dy = (double)y/(h-1);
158 dx = (double)x/(w-1);
160 if (1-scaling < 0.0001) {
161 dcol = (double)255*dy;
163 dcol = (double)255 * (dy - (dy-dx)*(1-scaling));
166 if (color == ColorTools::COL_R) {
167 plane.setPixel(x, (h-y-1), qRgb(dcol, dval, dval));
168 } else if (color == ColorTools::COL_G) {
169 plane.setPixel(x, (h-y-1), qRgb(dval, dcol, dval));
170 } else if (color == ColorTools::COL_B){
171 plane.setPixel(x, (h-y-1), qRgb(dval, dval, dcol));
173 plane.setPixel(x, (h-y-1), qRgb(dcol, dcol, dcol));
181 QImage ColorTools::yPbPrColorWheel(const QSize &size, const unsigned char &Y, const float &scaling, const bool &circleOnly)
184 QImage wheel(size, QImage::Format_ARGB32);
185 if (size.width() == 0 || size.height() == 0) {
186 qCritical("ERROR: Size of the color wheel must not be 0!");
190 wheel.fill(qRgba(0,0,0,0));
193 double dr, dg, db, dpB, dpR;
195 const int w = size.width();
196 const int h = size.height();
197 const float w2 = (float)w/2;
198 const float h2 = (float)h/2;
200 for (int b = 0; b < w; b++) {
201 // Transform pB from {0,...,w} to [-0.5,0.5]
202 dpB = (double) b/(w-1) - .5;
205 for (int r = 0; r < h; r++) {
206 dpR = (double) r/(h-1) - .5;
213 rr = rB*rB/(w2*w2) + rR*rR/(h2*h2);
219 // Calculate the RGB values from YPbPr
221 dg = Y - 87.75*dpB - 182.1*dpR;
224 // Avoid overflows (which would generate intersting patterns).
225 // Note that not all possible (y,u,v) values with u,v \in [-1,1]
226 // have a correct RGB representation, therefore some RGB values
227 // may exceed {0,...,255}.
231 if (dr > 255) dr = 255;
232 if (dg > 255) dg = 255;
233 if (db > 255) db = 255;
235 wheel.setPixel(b, (h-r-1), qRgba(dr, dg, db, 255));