]> git.sesse.net Git - kdenlive/blob - src/colorcorrection/levelsgenerator.cpp
7a216aaa558eb76cdab705a283c48a2819aa46a3
[kdenlive] / src / colorcorrection / levelsgenerator.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 <algorithm>
12 #include <math.h>
13 #include <QDebug>
14 #include <QImage>
15 #include <QPainter>
16 #include "levelsgenerator.h"
17
18 LevelsGenerator::LevelsGenerator()
19 {
20 }
21
22 QImage LevelsGenerator::calculateLevels(const QSize &paradeSize, const QImage &image, const int &components, const uint &accelFactor) const
23 {
24     qDebug() << "Levels rect size is: " << paradeSize.width() << "/" << paradeSize.height();
25     if (paradeSize.height() <= 0 || paradeSize.width() <= 0) {
26         return QImage();
27     }
28
29     bool drawY = (components & LevelsGenerator::ComponentY) != 0;
30     bool drawR = (components & LevelsGenerator::ComponentR) != 0;
31     bool drawG = (components & LevelsGenerator::ComponentG) != 0;
32     bool drawB = (components & LevelsGenerator::ComponentB) != 0;
33
34     int r[256], g[256], b[256], y[256];
35     // Initialize the values to zero
36     std::fill(r, r+255, 0);
37     std::fill(g, g+255, 0);
38     std::fill(b, b+255, 0);
39     std::fill(y, y+255, 0);
40
41     const uint iw = image.bytesPerLine();
42     const uint ih = image.height();
43     const uint ww = paradeSize.width();
44     const uint wh = paradeSize.height();
45     const uint byteCount = iw*ih;
46     const uint stepsize = 4*accelFactor;
47
48     const uchar *bits = image.bits();
49     QRgb *col;
50
51
52     // Read the stats from the input image
53     for (uint i = 0; i < byteCount; i += stepsize) {
54         col = (QRgb *)bits;
55
56         r[qRed(*col)]++;
57         g[qGreen(*col)]++;
58         b[qBlue(*col)]++;
59         y[(int)floor(.299*qRed(*col) + .587*qGreen(*col) + .114*qBlue(*col))]++;
60
61         bits += stepsize;
62     }
63
64
65     const int nParts = (drawY ? 1 : 0) + (drawR ? 1 : 0) + (drawG ? 1 : 0) + (drawB ? 1 : 0);
66     if (nParts == 0) {
67         // Nothing to draw
68         return QImage();
69     }
70
71     const int d = 20; // Distance for text
72     const int partH = (wh-4*d)/nParts;
73     const float scaling = (float)partH/(byteCount >> 7);
74
75     int wy = 0; // Drawing position
76     int partY; // Vertical position for the dots
77
78     QImage levels(paradeSize, QImage::Format_ARGB32);
79     QImage component(256, partH, QImage::Format_ARGB32);
80     QPainter davinci(&levels);
81     levels.fill(qRgba(0, 0, 0, 0));
82
83     if (drawY) {
84         qDebug() << "Drawing Y at " << wy << " with height " << partH;
85         component.fill(qRgba(0, 0, 0, 0));
86
87         for (int x = 0; x < 256; x++) {
88             // Calculate the height of the curve at position x
89             partY = scaling*y[x];
90
91             // Invert the y axis
92             if (partY > partH-1) { partY = partH-1; }
93             partY = partH-1 - partY;
94
95             for (int k = partH-1; k >= partY; k--) {
96                 component.setPixel(x, k, qRgba(220, 220, 210, 255));
97             }
98         }
99
100         davinci.drawImage(0, wy, component.scaled(ww, component.height(), Qt::IgnoreAspectRatio, Qt::FastTransformation));
101
102         wy += partH + d;
103     }
104
105     if (drawR) {
106         qDebug() << "Drawing R at " << wy << " with height " << partH;
107         component.fill(qRgba(0, 0, 0, 0));
108
109         for (int x = 0; x < 256; x++) {
110             // Calculate the height of the curve at position x
111             partY = scaling*r[x];
112
113             // Invert the y axis
114             if (partY > partH-1) { partY = partH-1; }
115             partY = partH-1 - partY;
116
117             for (int k = partH-1; k >= partY; k--) {
118                 component.setPixel(x, k, qRgba(255, 128, 0, 255));
119             }
120         }
121
122         davinci.drawImage(0, wy, component.scaled(ww, component.height(), Qt::IgnoreAspectRatio, Qt::FastTransformation));
123
124         wy += partH + d;
125     }
126
127     if (drawG) {
128         qDebug() << "Drawing G at " << wy << " with height " << partH;
129         component.fill(qRgba(0, 0, 0, 0));
130
131         for (int x = 0; x < 256; x++) {
132             // Calculate the height of the curve at position x
133             partY = scaling*g[x];
134
135             // Invert the y axis
136             if (partY > partH-1) { partY = partH-1; }
137             partY = partH-1 - partY;
138
139             for (int k = partH-1; k >= partY; k--) {
140                 component.setPixel(x, k, qRgba(128, 255, 0, 255));
141             }
142         }
143
144         davinci.drawImage(0, wy, component.scaled(ww, component.height(), Qt::IgnoreAspectRatio, Qt::FastTransformation));
145
146         wy += partH + d;
147     }
148
149     if (drawB) {
150         qDebug() << "Drawing B at " << wy << " with height " << partH;
151         component.fill(qRgba(0, 0, 0, 0));
152
153         for (int x = 0; x < 256; x++) {
154             // Calculate the height of the curve at position x
155             partY = scaling*b[x];
156
157             // Invert the y axis
158             if (partY > partH-1) { partY = partH-1; }
159             partY = partH-1 - partY;
160
161             for (int k = partH-1; k >= partY; k--) {
162                 component.setPixel(x, k, qRgba(0, 128, 255, 255));
163             }
164         }
165
166         davinci.drawImage(0, wy, component.scaled(ww, component.height(), Qt::IgnoreAspectRatio, Qt::FastTransformation));
167
168         wy += partH + d;
169     }
170
171     return levels;
172 }