Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_filter_weights_applicator.h
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2012 Dmitry Kazakov <dimula73@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7#ifndef __KIS_FILTER_WEIGHTS_APPLICATOR_H
8#define __KIS_FILTER_WEIGHTS_APPLICATOR_H
9
12#include "kis_iterator_ng.h"
13
14
15#include <KoColorSpace.h>
16#include <KoMixColorsOp.h>
17
18
19namespace tmp {
20 template <class iter> iter createIterator(KisPaintDeviceSP dev, qint32 start, qint32 lineNum, qint32 len);
21
23 (KisPaintDeviceSP dev, qint32 start, qint32 lineNum, qint32 len)
24 {
25 return dev->createHLineIteratorNG(start, lineNum, len);
26 }
27
29 (KisPaintDeviceSP dev, qint32 start, qint32 lineNum, qint32 len)
30 {
31 return dev->createVLineIteratorNG(lineNum, start, len);
32 }
33}
34
95{
96public:
99 qreal realScale, qreal shear,
100 qreal dx,
101 bool clampToEdge)
102 : m_src(src),
103 m_dst(dst),
104 m_realScale(realScale),
105 m_shear(shear),
106 m_dx(dx),
107 m_clampToEdge(clampToEdge)
108 {
109 }
110
117
118 inline BlendSpan calculateBlendSpan(int dst_l, int line, KisFilterWeightsBuffer *buffer) const {
119 KisFixedPoint dst_c = l_to_c(dst_l);
120 KisFixedPoint dst_c_in_src = dstToSrc(dst_c.toFloat(), line);
121
122 // gives the nearest center of the pixel in src ( x e (0, 1> => f(x) = 0.5, x e (1, 2> => f(x) = 1.5 etc. )
123 KisFixedPoint next_c_in_src = (dst_c_in_src - qreal(0.5)).toIntCeil() + qreal(0.5);
124
125 BlendSpan span;
126 span.offset = (next_c_in_src - dst_c_in_src) * buffer->weightsPositionScale();
127 span.offsetInc = buffer->weightsPositionScale();
128
129 Q_ASSERT(span.offset <= span.offsetInc);
130
131 span.weights = buffer->weights(span.offset);
132 span.firstBlendPixel = next_c_in_src.toIntFloor() - span.weights->centerIndex;
133
134 return span;
135 }
136
137 class LinePos {
138 public:
140 : m_start(0), m_size(0)
141 {
142 }
143
146 {
147 }
148
149 inline int start() const {
150 return m_start;
151 }
152
160 inline int end() const {
161 return m_start + m_size;
162 }
163
164 inline int size() const {
165 return m_size;
166 }
167
168 inline void unite(const LinePos &rhs) {
169 if (m_size > 0) {
170 int newStart = qMin(start(), rhs.start());
171 int newEnd = qMax(end(), rhs.end());
172
173 m_start = newStart;
174 m_size = newEnd - newStart;
175 } else {
176 m_start = rhs.start();
177 m_size = rhs.size();
178 }
179 }
180
181 private:
184 };
185
186 template <class T>
187 LinePos processLine(LinePos srcLine, int line, KisFilterWeightsBuffer *buffer, qreal filterSupport) {
188 int dstStart;
189 int dstEnd;
190
191 int leftSrcBorder;
192 int rightSrcBorder;
193
194 if (m_realScale >= 0) {
195 dstStart = findAntialiasedDstStart(srcLine.start(), filterSupport, line);
196 dstEnd = findAntialiasedDstEnd(srcLine.end(), filterSupport, line);
197
201 if (dstStart == dstEnd) {
202 dstEnd = dstStart + 1;
203 }
204
205 leftSrcBorder = getLeftSrcNeedBorder(dstStart, line, buffer);
206 rightSrcBorder = getRightSrcNeedBorder(dstEnd - 1, line, buffer);
207 }
208 else {
209 dstStart = findAntialiasedDstStart(srcLine.end(), filterSupport, line);
210 dstEnd = findAntialiasedDstEnd(srcLine.start(), filterSupport, line);
211
215 if (dstStart == dstEnd) {
216 dstEnd = dstStart + 1;
217 }
218
219 leftSrcBorder = getLeftSrcNeedBorder(dstEnd - 1, line, buffer);
220 rightSrcBorder = getRightSrcNeedBorder(dstStart, line, buffer);
221 }
222
223 if (dstStart >= dstEnd) return LinePos(dstStart, 0);
224 if (leftSrcBorder >= rightSrcBorder) return LinePos(dstStart, 0);
225 if (leftSrcBorder > srcLine.start()) {
226 leftSrcBorder = srcLine.start();
227 }
228 if (srcLine.end() > rightSrcBorder) {
229 rightSrcBorder = srcLine.end();
230 }
231
232 int pixelSize = m_src->pixelSize();
234 const KoColor defaultPixelObject = m_src->defaultPixel();
235 const quint8 *defaultPixel = defaultPixelObject.data();
236 const quint8 *borderPixel = defaultPixel;
237 quint8 *srcLineBuf = new quint8[pixelSize * (rightSrcBorder - leftSrcBorder)];
238
239 int i = leftSrcBorder;
240 quint8 *bufPtr = srcLineBuf;
241
242 T srcIt = tmp::createIterator<T>(m_src, srcLine.start(), line, srcLine.size());
243
244 if (m_clampToEdge) {
245 borderPixel = srcIt->rawData();
246 }
247
248 for (; i < srcLine.start(); i++, bufPtr+=pixelSize) {
249 memcpy(bufPtr, borderPixel, pixelSize);
250 }
251
252 for (; i < srcLine.end(); i++, bufPtr+=pixelSize) {
253 quint8 *data = srcIt->rawData();
254 memcpy(bufPtr, data, pixelSize);
255 memcpy(data, defaultPixel, pixelSize);
256 srcIt->nextPixel();
257 }
258
259 if (m_clampToEdge) {
260 borderPixel = bufPtr - pixelSize;
261 }
262
263 for (; i < rightSrcBorder; i++, bufPtr+=pixelSize) {
264 memcpy(bufPtr, borderPixel, pixelSize);
265 }
266
267 const quint8 **colors = new const quint8* [buffer->maxSpan()];
268
269 T dstIt = tmp::createIterator<T>(m_dst, dstStart, line, dstEnd - dstStart);
270 for (int i = dstStart; i < dstEnd; i++) {
271 BlendSpan span = calculateBlendSpan(i, line, buffer);
272
273 int bufIndexStart = span.firstBlendPixel - leftSrcBorder;
274 int bufIndexEnd = bufIndexStart + span.weights->span;
275
276 const quint8 **colorsPtr = colors;
277 for (int j = bufIndexStart; j < bufIndexEnd; j++) {
278 *(colorsPtr++) = srcLineBuf + j * pixelSize;
279 }
280
281 mixOp->mixColors(colors, span.weights->weight, span.weights->span, dstIt->rawData());
282 dstIt->nextPixel();
283 }
284
285 delete[] colors;
286 delete[] srcLineBuf;
287
288 return LinePos(dstStart, qMax(0, dstEnd - dstStart));
289 }
290
291private:
292
293 int findAntialiasedDstStart(int src_l, qreal support, int line) {
294 qreal dst = srcToDst(src_l, line);
295 return !m_clampToEdge ? qRound(dst - support) : qRound(dst);
296 }
297
298 int findAntialiasedDstEnd(int src_l, qreal support, int line) {
299 qreal dst = srcToDst(src_l, line);
300 return !m_clampToEdge ? qRound(dst + support) : qRound(dst);
301 }
302
303 int getLeftSrcNeedBorder(int dst_l, int line, KisFilterWeightsBuffer *buffer) {
304 BlendSpan span = calculateBlendSpan(dst_l, line, buffer);
305 return span.firstBlendPixel;
306 }
307
308 int getRightSrcNeedBorder(int dst_l, int line, KisFilterWeightsBuffer *buffer) {
309 BlendSpan span = calculateBlendSpan(dst_l, line, buffer);
310 return span.firstBlendPixel + span.weights->span;
311 }
312
313 inline KisFixedPoint l_to_c(KisFixedPoint pixel_l) const {
314 return pixel_l + KisFixedPoint(qreal(0.5));
315 }
316
317 inline KisFixedPoint c_to_l(KisFixedPoint pixel_c) const {
318 return pixel_c - KisFixedPoint(qreal(0.5));
319 }
320
321 inline qreal srcToDst(qreal src, int line) const {
322 return src * m_realScale + m_dx + line * m_shear;
323 }
324
325 inline qreal dstToSrc(qreal dst, int line) const {
326 return (dst - m_dx - line * m_shear) / m_realScale;
327 }
328
329private:
332
334 qreal m_shear;
335 qreal m_dx;
337};
338
339#endif /* __KIS_FILTER_WEIGHTS_APPLICATOR_H */
qreal srcToDst(qreal src, int line) const
int findAntialiasedDstEnd(int src_l, qreal support, int line)
int findAntialiasedDstStart(int src_l, qreal support, int line)
KisFixedPoint l_to_c(KisFixedPoint pixel_l) const
qreal dstToSrc(qreal dst, int line) const
int getRightSrcNeedBorder(int dst_l, int line, KisFilterWeightsBuffer *buffer)
int getLeftSrcNeedBorder(int dst_l, int line, KisFilterWeightsBuffer *buffer)
BlendSpan calculateBlendSpan(int dst_l, int line, KisFilterWeightsBuffer *buffer) const
KisFilterWeightsApplicator(KisPaintDeviceSP src, KisPaintDeviceSP dst, qreal realScale, qreal shear, qreal dx, bool clampToEdge)
KisFixedPoint c_to_l(KisFixedPoint pixel_c) const
LinePos processLine(LinePos srcLine, int line, KisFilterWeightsBuffer *buffer, qreal filterSupport)
FilterWeights * weights(KisFixedPoint pos) const
KisFixedPoint weightsPositionScale() const
qint32 toIntFloor() const
qreal toFloat() const
quint32 pixelSize() const
KisHLineIteratorSP createHLineIteratorNG(qint32 x, qint32 y, qint32 w)
const KoColorSpace * colorSpace() const
KoColor defaultPixel() const
KisVLineIteratorSP createVLineIteratorNG(qint32 x, qint32 y, qint32 h)
KoMixColorsOp * mixColorsOp
quint8 * data()
Definition KoColor.h:144
virtual void mixColors(const quint8 *const *colors, const qint16 *weights, int nColors, quint8 *dst, int weightSum=255) const =0
iter createIterator(KisPaintDeviceSP dev, qint32 start, qint32 lineNum, qint32 len)
KisHLineIteratorSP createIterator< KisHLineIteratorSP >(KisPaintDeviceSP dev, qint32 start, qint32 lineNum, qint32 len)
KisVLineIteratorSP createIterator< KisVLineIteratorSP >(KisPaintDeviceSP dev, qint32 start, qint32 lineNum, qint32 len)
KisFilterWeightsBuffer::FilterWeights * weights