]> git.sesse.net Git - kdenlive/blob - src/colortools.cpp
RGB Plane export fixed for scale < 1
[kdenlive] / src / colortools.cpp
1 /***************************************************************************
2  *   Copyright (C) 2010 by Simon Andreas Eugster (simon.eu@gmail.com)      *
3  *   This file is part of kdenlive. See www.kdenlive.org.                  *
4  *                                                                         *
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  ***************************************************************************/
10
11 #include <math.h>
12 #include "colortools.h"
13
14 ColorTools::ColorTools()
15 {
16 }
17
18
19
20 QImage ColorTools::yuvColorWheel(const QSize &size, const unsigned char &Y, const float &scaling, const bool &modifiedVersion, const bool &circleOnly)
21 {
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!");
25         return wheel;
26     }
27     if (circleOnly) {
28         wheel.fill(qRgba(0,0,0,0));
29     }
30
31     double dr, dg, db, du, dv, dmax;
32     double ru, rv, rr;
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;
37
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;
41         du = scaling*du;
42
43         for (int v = 0; v < h; v++) {
44             dv = (double) 2*v/(h-1) - 1;
45             dv = scaling*dv;
46
47             if (circleOnly) {
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.
51                 ru = u - w2;
52                 rv = v - h2;
53                 rr = ru*ru/(w2*w2) + rv*rv/(h2*h2);
54                 if (rr > 1) {
55                     continue;
56                 }
57             }
58
59             // Calculate the RGB values from YUV
60             dr = Y + 290.8*dv;
61             dg = Y - 100.6*du - 148*dv;
62             db = Y + 517.2*du;
63
64             if (modifiedVersion) {
65                 // Scale the RGB values down, or up, to max 255
66                 dmax = fabs(dr);
67                 if (fabs(dg) > dmax) dmax = fabs(dg);
68                 if (fabs(db) > dmax) dmax = fabs(db);
69                 dmax = 255/dmax;
70
71                 dr *= dmax;
72                 dg *= dmax;
73                 db *= dmax;
74             }
75
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}.
80             if (dr < 0) dr = 0;
81             if (dg < 0) dg = 0;
82             if (db < 0) db = 0;
83             if (dr > 255) dr = 255;
84             if (dg > 255) dg = 255;
85             if (db > 255) db = 255;
86
87             wheel.setPixel(u, (h-v-1), qRgba(dr, dg, db, 255));
88         }
89     }
90
91     emit signalYuvWheelCalculationFinished();
92     return wheel;
93 }
94
95 QImage ColorTools::yuvVerticalPlane(const QSize &size, const float &angle, const float &scaling)
96 {
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!");
100         return plane;
101     }
102
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);
108
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);
112
113         for (int y = 0; y < h; y++) {
114             Y = (double)255*y/h;
115
116             // See yuv2rgb, yuvColorWheel
117             dr = Y + 290.8*dv;
118             dg = Y - 100.6*du - 148*dv;
119             db = Y + 517.2*du;
120             if (dr < 0) dr = 0;
121             if (dg < 0) dg = 0;
122             if (db < 0) db = 0;
123             if (dr > 255) dr = 255;
124             if (dg > 255) dg = 255;
125             if (db > 255) db = 255;
126
127             plane.setPixel(uv, (h-y-1), qRgba(dr, dg, db, 255));
128
129         }
130     }
131
132
133     return plane;
134
135 }
136
137 QImage ColorTools::rgbCurvePlane(const QSize &size, const ColorTools::ColorsRGB &color, float scaling)
138 {
139     Q_ASSERT(scaling > 0 && scaling <= 1);
140
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!");
144         return plane;
145     }
146
147     const int w = size.width();
148     const int h = size.height();
149
150     double dcol, dval;
151     double dx, dy;
152
153     for (int x = 0; x < w; x++) {
154         dval = (double)255*x/(w-1);
155
156         for (int y = 0; y < h; y++) {
157             dy = (double)y/(h-1);
158             dx = (double)x/(w-1);
159
160             if (1-scaling < 0.0001) {
161                 dcol = (double)255*dy;
162             } else {
163                 dcol = (double)255 * (dy - (dy-dx)*(1-scaling));
164             }
165
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));
172             } else {
173                 plane.setPixel(x, (h-y-1), qRgb(dcol, dcol, dcol));
174             }
175
176         }
177     }
178     return plane;
179 }
180
181 QImage ColorTools::yPbPrColorWheel(const QSize &size, const unsigned char &Y, const float &scaling, const bool &circleOnly)
182 {
183
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!");
187         return wheel;
188     }
189     if (circleOnly) {
190         wheel.fill(qRgba(0,0,0,0));
191     }
192
193     double dr, dg, db, dpB, dpR;
194     double rB, rR, rr;
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;
199
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;
203         dpB = scaling*dpB;
204
205         for (int r = 0; r < h; r++) {
206             dpR = (double) r/(h-1) - .5;
207             dpR = scaling*dpR;
208
209             if (circleOnly) {
210                 // see yuvColorWheel
211                 rB = b - w2;
212                 rR = r - h2;
213                 rr = rB*rB/(w2*w2) + rR*rR/(h2*h2);
214                 if (rr > 1) {
215                     continue;
216                 }
217             }
218
219             // Calculate the RGB values from YPbPr
220             dr = Y + 357.5*dpR;
221             dg = Y - 87.75*dpB - 182.1*dpR;
222             db = Y + 451.86*dpB;
223
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}.
228             if (dr < 0) dr = 0;
229             if (dg < 0) dg = 0;
230             if (db < 0) db = 0;
231             if (dr > 255) dr = 255;
232             if (dg > 255) dg = 255;
233             if (db > 255) db = 255;
234
235             wheel.setPixel(b, (h-r-1), qRgba(dr, dg, db, 255));
236         }
237     }
238
239     return wheel;
240 }
241
242
243
244
245
246
247
248