Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_filter_strategy.cc
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2004 Michael Thaler <michael.thaler@physik.tu-muenchen.de>
3 * SPDX-FileCopyrightText: 2005 C. Boemann <cbo@boemann.dk>
4 * SPDX-FileCopyrightText: 2013 Juan Palacios <jpalaciosdev@gmail.com>
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
10
11#include <math.h>
12
13#include <klocalizedstring.h>
14#include <QGlobalStatic>
15
16#include "kis_debug.h"
17#include <QtMath>
18#include <QSize>
19
21
22qreal KisHermiteFilterStrategy::valueAt(qreal t, qreal weightsPositionScale) const
23{
24 Q_UNUSED(weightsPositionScale);
25 /* f(t) = 2|t|^3 - 3|t|^2 + 1, -1 <= t <= 1 */
26 if (t < 0.0) t = -t;
27 if (t < 1.0) return((2.0 * t - 3.0) * t * t + 1.0);
28 return(0.0);
29}
30
31qint32 KisHermiteFilterStrategy::intValueAt(qint32 t, qreal weightsPositionScale) const
32{
33 Q_UNUSED(weightsPositionScale);
34 /* f(t) = 2|t|^3 - 3|t|^2 + 1, -1 <= t <= 1 */
35 if (t < 0) t = -t;
36 if (t < 256) {
37 t = (2 * t - 3 * 256) * t * t + (256 << 16);
38
39 //go from .24 fixed point to .8 fixedpoint (hack only works with positive numbers, which it is)
40 t = (t + 0x8000) >> 16;
41
42 // go from .8 fixed point to 8bitscale. ie t = (t*255)/256;
43 if (t >= 128)
44 return t - 1;
45 return t;
46 }
47 return(0);
48}
49
50qint32 KisBicubicFilterStrategy::intValueAt(qint32 t, qreal weightsPositionScale) const
51{
52 Q_UNUSED(weightsPositionScale);
53 /* f(t) = 1.5|t|^3 - 2.5|t|^2 + 1, -1 <= t <= 1 */
54 if (t < 0) t = -t;
55 if (t < 256) {
56 t = (3 * t - 5 * 256) * t * t / 2 + (256 << 16);
57
58 //go from .24 fixed point to .8 fixedpoint (hack only works with positive numbers, which it is)
59 t = (t + 0x8000) >> 16;
60
61 // go from .8 fixed point to 8bitscale. ie t = (t*255)/256;
62 if (t >= 128)
63 return t - 1;
64 return t;
65 }
66 if (t < 512) {
67 /* f(t) = -0.5|t|^3 + 2.5|t|^2 + 4|t| - 2, -2 <= t <= 2 */
68 t = ((-t + 5 * 256) * t / 2 - 4 * 256 * 256) * t + (2 * 256 << 16);
69
70 //go from .24 fixed point to .8 fixedpoint (hack only works with positive numbers, which it is)
71 t = (t + 0x8000) >> 16;
72
73 // go from .8 fixed point to 8bitscale. ie t = (t*255)/256;
74 if (t >= 128)
75 return t - 1;
76 return t;
77 }
78 return(0);
79}
80
81qreal KisBoxFilterStrategy::valueAt(qreal t, qreal weightsPositionScale) const
82{
83 if ((t >= -0.5 * weightsPositionScale) && (t < 0.5 * weightsPositionScale)) return(1.0);
84 return(0.0);
85}
86
87qint32 KisBoxFilterStrategy::intValueAt(qint32 t, qreal weightsPositionScale) const
88{
89 /* f(t) = 1, -0.5 < t <= 0.5 */
90 if ((t >= -128 * weightsPositionScale) && (t < 128 * weightsPositionScale))
91 return 255;
92 return 0;
93}
94
95
96qreal KisBoxFilterStrategy::support(qreal weightsPositionScale)
97{
98 return supportVal*weightsPositionScale;
99}
100
101qint32 KisBoxFilterStrategy::intSupport(qreal weightsPositionScale)
102{
103 return qCeil(intSupportVal*weightsPositionScale);
104}
105
106qreal KisBilinearFilterStrategy::valueAt(qreal t, qreal weightsPositionScale) const
107{
108 Q_UNUSED(weightsPositionScale);
109 if (t < 0.0) t = -t;
110 if (t < 1.0) return(1.0 - t);
111 return(0.0);
112}
113
114qint32 KisBilinearFilterStrategy::intValueAt(qint32 t, qreal weightsPositionScale) const
115{
116 Q_UNUSED(weightsPositionScale);
117 /* f(t) = |t|, -1 <= t <= 1 */
118 if (t < 0) t = -t;
119 if (t < 256) {
120 // calc 256-1 but also go from .8 fixed point to 8bitscale. ie t = (t*255)/256; ie: if(t>=128) return t-1;
121 if (t >= 128) return 256 - t;
122 return 255 - t;
123 }
124 return(0);
125}
126
127
128qreal KisBellFilterStrategy::valueAt(qreal t, qreal weightsPositionScale) const
129{
130 Q_UNUSED(weightsPositionScale);
131 if (t < 0) t = -t;
132 if (t < .5) return(.75 - (t * t));
133 if (t < 1.5) {
134 t = (t - 1.5);
135 return(.5 *(t * t));
136 }
137 return(0.0);
138}
139
140qreal KisBSplineFilterStrategy::valueAt(qreal t, qreal weightsPositionScale) const
141{
142 Q_UNUSED(weightsPositionScale);
143 qreal tt;
144
145 if (t < 0) t = -t;
146 if (t < 1) {
147 tt = t * t;
148 return((.5 * tt * t) - tt + (2.0 / 3.0));
149 } else if (t < 2) {
150 t = 2 - t;
151 return((1.0 / 6.0) *(t * t * t));
152 }
153 return(0.0);
154}
155
156qreal KisLanczos3FilterStrategy::valueAt(qreal t, qreal weightsPositionScale) const
157{
158 Q_UNUSED(weightsPositionScale);
159 if (t < 0) t = -t;
160 if (t < 3.0) return(sinc(t) * sinc(t / 3.0));
161 return(0.0);
162}
163
165{
166 const qreal pi = 3.1415926535897932385;
167 x *= pi;
168 if (x != 0) return(sin(x) / x);
169 return(1.0);
170}
171
172qreal KisMitchellFilterStrategy::valueAt(qreal t, qreal weightsPositionScale) const
173{
174 Q_UNUSED(weightsPositionScale);
175 const qreal B = 1.0 / 3.0;
176 const qreal C = 1.0 / 3.0;
177 qreal tt;
178
179 tt = t * t;
180 if (t < 0) t = -t;
181 if (t < 1.0) {
182 t = (((12.0 - 9.0 * B - 6.0 * C) * (t * tt)) + ((-18.0 + 12.0 * B + 6.0 * C) * tt) + (6.0 - 2 * B));
183 return(t / 6.0);
184 } else if (t < 2.0) {
185 t = (((-1.0 * B - 6.0 * C) * (t * tt)) + ((6.0 * B + 30.0 * C) * tt) + ((-12.0 * B - 48.0 * C) * t) + (8.0 * B + 24 * C));
186 return(t / 6.0);
187 }
188 return(0.0);
189}
190
194
196{
197 Q_FOREACH (const QString &id, keys()) {
198 delete get(id);
199 }
200 dbgRegistry << "deleting KisFilterStrategyRegistry";
201}
202
204{
205 if (!s_instance.exists()) {
206 s_instance->add(new KisBoxFilterStrategy);
207 s_instance->addAlias("Box", "NearestNeighbor");
208
209 s_instance->add(new KisHermiteFilterStrategy);
210 s_instance->add(new KisBicubicFilterStrategy);
211 s_instance->add(new KisBilinearFilterStrategy);
212 s_instance->add(new KisBellFilterStrategy);
213 s_instance->add(new KisBSplineFilterStrategy);
214 s_instance->add(new KisLanczos3FilterStrategy);
215 s_instance->add(new KisMitchellFilterStrategy);
216 }
217 return s_instance;
218}
219
221{
222 QList<KoID> answer;
223 Q_FOREACH (const QString key, keys()) {
224 answer.append(KoID(key, get(key)->name()));
225 }
226
227 return answer;
228}
229
231{
232 QString formatedDescription("<html><head/><body>");
233
234 Q_FOREACH (const QString key, keys()) {
235 KisFilterStrategy *strategy = get(key);
236 QString description = strategy->description();
237
238 if (!description.isEmpty()) {
239 formatedDescription.append("<p><span style=\"font-weight:600;\">");
240 formatedDescription.append(strategy->name());
241 formatedDescription.append("</span>: ");
242 formatedDescription.append(description);
243 formatedDescription.append("</p>");
244 }
245 }
246 formatedDescription.append("</body></html>");
247
248 return formatedDescription;
249}
250
251KisFilterStrategy *KisFilterStrategyRegistry::autoFilterStrategy(QSize originalSize, QSize desiredSize) const
252{
253 // Default to nearest neighbor scaling for tiny source images. (i.e: icons or small sprite sheets.)
254 const int pixelArtThreshold = 256;
255 if (originalSize.width() <= pixelArtThreshold ||
256 originalSize.height() <= pixelArtThreshold) {
257 return KisFilterStrategyRegistry::instance()->value("NearestNeighbor");
258 }
259
260 const float xScaleFactor = (float)desiredSize.width() / originalSize.width();
261 const float yScaleFactor = (float)desiredSize.height() / originalSize.height();
262
263 if (xScaleFactor > 1.f || yScaleFactor > 1.f) { // Enlargement.
264 return KisFilterStrategyRegistry::instance()->value("Bicubic");
265 } else if (xScaleFactor < 1.f || yScaleFactor < 1.f) { // Reduction.
266 return KisFilterStrategyRegistry::instance()->value("Bicubic");
267 }
268
269 return KisFilterStrategyRegistry::instance()->value("NearestNeighbor");
270}
Q_GLOBAL_STATIC(KisStoragePluginRegistry, s_instance)
#define C(i, j)
qreal valueAt(qreal t, qreal weightsPositionScale) const override
qreal valueAt(qreal t, qreal weightsPositionScale) const override
qint32 intValueAt(qint32 t, qreal weightsPositionScale) const override
qint32 intValueAt(qint32 t, qreal weightsPositionScale) const override
qreal valueAt(qreal t, qreal weightsPositionScale) const override
qreal valueAt(qreal t, qreal weightsPositionScale) const override
virtual qint32 intSupport(qreal weightsPositionScale) override
virtual qreal support(qreal weightsPositionScale) override
qint32 intValueAt(qint32 t, qreal weightsPositionScale) const override
static KisFilterStrategyRegistry * instance()
KisFilterStrategy * autoFilterStrategy(QSize originalSize, QSize desiredSize) const
QList< KoID > listKeys() const
virtual QString description()
qint32 intValueAt(qint32 t, qreal weightsPositionScale) const override
qreal valueAt(qreal t, qreal weightsPositionScale) const override
qreal valueAt(qreal t, qreal weightsPositionScale) const override
const T value(const QString &id) const
KisFilterStrategy * get(const QString &id) const
Definition KoID.h:30
#define dbgRegistry
Definition kis_debug.h:47