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