1 | // Copyright (C) 2016 The Qt Company Ltd. |
---|---|
2 | // Copyright (C) 2004, 2005 Daniel M. Duley., (C) Carsten Haitzler and various contributors., (C) Willem Monsuwe <willem@stack.nl> |
3 | // SPDX-License-Identifier: BSD-2-Clause AND Imlib2 |
4 | #include <private/qimagescale_p.h> |
5 | #include <private/qdrawhelper_p.h> |
6 | #include <private/qimage_p.h> |
7 | |
8 | #include "qimage.h" |
9 | #include "qcolor.h" |
10 | #include "qrgba64_p.h" |
11 | #include "qrgbafloat.h" |
12 | |
13 | #if QT_CONFIG(thread) && !defined(Q_OS_WASM) |
14 | #include <qsemaphore.h> |
15 | #include <qthreadpool.h> |
16 | #include <private/qthreadpool_p.h> |
17 | #endif |
18 | |
19 | QT_BEGIN_NAMESPACE |
20 | |
21 | /* |
22 | * Copyright (C) 2004, 2005 Daniel M. Duley |
23 | * |
24 | * Redistribution and use in source and binary forms, with or without |
25 | * modification, are permitted provided that the following conditions |
26 | * are met: |
27 | * |
28 | * 1. Redistributions of source code must retain the above copyright |
29 | * notice, this list of conditions and the following disclaimer. |
30 | * 2. Redistributions in binary form must reproduce the above copyright |
31 | * notice, this list of conditions and the following disclaimer in the |
32 | * documentation and/or other materials provided with the distribution. |
33 | * |
34 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
35 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
36 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
37 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
38 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
39 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
40 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
41 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
42 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
43 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
44 | * |
45 | */ |
46 | |
47 | /* OTHER CREDITS: |
48 | * |
49 | * This is the normal smoothscale method, based on Imlib2's smoothscale. |
50 | * |
51 | * Originally I took the algorithm used in NetPBM and Qt and added MMX/3dnow |
52 | * optimizations. It ran in about 1/2 the time as Qt. Then I ported Imlib's |
53 | * C algorithm and it ran at about the same speed as my MMX optimized one... |
54 | * Finally I ported Imlib's MMX version and it ran in less than half the |
55 | * time as my MMX algorithm, (taking only a quarter of the time Qt does). |
56 | * After further optimization it seems to run at around 1/6th. |
57 | * |
58 | * Changes include formatting, namespaces and other C++'ings, removal of old |
59 | * #ifdef'ed code, and removal of unneeded border calculation code. |
60 | * Later the code has been refactored, an SSE4.1 optimizated path have been |
61 | * added instead of the removed MMX assembler, and scaling of clipped area |
62 | * removed, and an RGBA64 version written |
63 | * |
64 | * Imlib2 is (C) Carsten Haitzler and various contributors. The MMX code |
65 | * is by Willem Monsuwe <willem@stack.nl>. All other modifications are |
66 | * (C) Daniel M. Duley. |
67 | */ |
68 | |
69 | |
70 | namespace QImageScale { |
71 | static const unsigned int** qimageCalcYPoints(const unsigned int *src, int sw, int sh, int dh); |
72 | static int* qimageCalcXPoints(int sw, int dw); |
73 | static int* qimageCalcApoints(int s, int d, int up); |
74 | static QImageScaleInfo* qimageFreeScaleInfo(QImageScaleInfo *isi); |
75 | static QImageScaleInfo *qimageCalcScaleInfo(const QImage &img, int sw, int sh, int dw, int dh, char aa); |
76 | } |
77 | |
78 | using namespace QImageScale; |
79 | |
80 | // |
81 | // Code ported from Imlib... |
82 | // |
83 | |
84 | static const unsigned int** QImageScale::qimageCalcYPoints(const unsigned int *src, |
85 | int sw, int sh, int dh) |
86 | { |
87 | const unsigned int **p; |
88 | int j = 0, rv = 0; |
89 | qint64 val, inc; |
90 | |
91 | if (dh < 0) { |
92 | dh = -dh; |
93 | rv = 1; |
94 | } |
95 | p = new const unsigned int* [dh+1]; |
96 | |
97 | int up = qAbs(t: dh) >= sh; |
98 | val = up ? 0x8000 * sh / dh - 0x8000 : 0; |
99 | inc = (((qint64)sh) << 16) / dh; |
100 | for (int i = 0; i < dh; i++) { |
101 | p[j++] = src + qMax(a: 0LL, b: val >> 16) * sw; |
102 | val += inc; |
103 | } |
104 | if (rv) { |
105 | for (int i = dh / 2; --i >= 0; ) { |
106 | const unsigned int *tmp = p[i]; |
107 | p[i] = p[dh - i - 1]; |
108 | p[dh - i - 1] = tmp; |
109 | } |
110 | } |
111 | return(p); |
112 | } |
113 | |
114 | static int* QImageScale::qimageCalcXPoints(int sw, int dw) |
115 | { |
116 | int *p, j = 0, rv = 0; |
117 | qint64 val, inc; |
118 | |
119 | if (dw < 0) { |
120 | dw = -dw; |
121 | rv = 1; |
122 | } |
123 | p = new int[dw+1]; |
124 | |
125 | int up = qAbs(t: dw) >= sw; |
126 | val = up ? 0x8000 * sw / dw - 0x8000 : 0; |
127 | inc = (((qint64)sw) << 16) / dw; |
128 | for (int i = 0; i < dw; i++) { |
129 | p[j++] = qMax(a: 0LL, b: val >> 16); |
130 | val += inc; |
131 | } |
132 | |
133 | if (rv) { |
134 | for (int i = dw / 2; --i >= 0; ) { |
135 | int tmp = p[i]; |
136 | p[i] = p[dw - i - 1]; |
137 | p[dw - i - 1] = tmp; |
138 | } |
139 | } |
140 | return p; |
141 | } |
142 | |
143 | static int* QImageScale::qimageCalcApoints(int s, int d, int up) |
144 | { |
145 | int *p, j = 0, rv = 0; |
146 | |
147 | if (d < 0) { |
148 | rv = 1; |
149 | d = -d; |
150 | } |
151 | p = new int[d]; |
152 | |
153 | if (up) { |
154 | /* scaling up */ |
155 | qint64 val = 0x8000 * s / d - 0x8000; |
156 | qint64 inc = (((qint64)s) << 16) / d; |
157 | for (int i = 0; i < d; i++) { |
158 | int pos = val >> 16; |
159 | if (pos < 0) |
160 | p[j++] = 0; |
161 | else if (pos >= (s - 1)) |
162 | p[j++] = 0; |
163 | else |
164 | p[j++] = (val >> 8) - ((val >> 8) & 0xffffff00); |
165 | val += inc; |
166 | } |
167 | } else { |
168 | /* scaling down */ |
169 | qint64 val = 0; |
170 | qint64 inc = (((qint64)s) << 16) / d; |
171 | int Cp = (((d << 14) + s - 1) / s); |
172 | for (int i = 0; i < d; i++) { |
173 | int ap = ((0x10000 - (val & 0xffff)) * Cp) >> 16; |
174 | p[j] = ap | (Cp << 16); |
175 | j++; |
176 | val += inc; |
177 | } |
178 | } |
179 | if (rv) { |
180 | int tmp; |
181 | for (int i = d / 2; --i >= 0; ) { |
182 | tmp = p[i]; |
183 | p[i] = p[d - i - 1]; |
184 | p[d - i - 1] = tmp; |
185 | } |
186 | } |
187 | return p; |
188 | } |
189 | |
190 | static QImageScaleInfo* QImageScale::qimageFreeScaleInfo(QImageScaleInfo *isi) |
191 | { |
192 | if (isi) { |
193 | delete[] isi->xpoints; |
194 | delete[] isi->ypoints; |
195 | delete[] isi->xapoints; |
196 | delete[] isi->yapoints; |
197 | delete isi; |
198 | } |
199 | return nullptr; |
200 | } |
201 | |
202 | static QImageScaleInfo* QImageScale::qimageCalcScaleInfo(const QImage &img, |
203 | int sw, int sh, |
204 | int dw, int dh, char aa) |
205 | { |
206 | QImageScaleInfo *isi; |
207 | int scw, sch; |
208 | |
209 | scw = dw * qlonglong(img.width()) / sw; |
210 | sch = dh * qlonglong(img.height()) / sh; |
211 | |
212 | isi = new QImageScaleInfo; |
213 | if (!isi) |
214 | return nullptr; |
215 | isi->sh = sh; |
216 | isi->sw = sw; |
217 | |
218 | isi->xup_yup = (qAbs(t: dw) >= sw) + ((qAbs(t: dh) >= sh) << 1); |
219 | |
220 | isi->xpoints = qimageCalcXPoints(sw: img.width(), dw: scw); |
221 | if (!isi->xpoints) |
222 | return qimageFreeScaleInfo(isi); |
223 | isi->ypoints = qimageCalcYPoints(src: (const unsigned int *)img.scanLine(0), |
224 | sw: img.bytesPerLine() / 4, sh: img.height(), dh: sch); |
225 | if (!isi->ypoints) |
226 | return qimageFreeScaleInfo(isi); |
227 | if (aa) { |
228 | isi->xapoints = qimageCalcApoints(s: img.width(), d: scw, up: isi->xup_yup & 1); |
229 | if (!isi->xapoints) |
230 | return qimageFreeScaleInfo(isi); |
231 | isi->yapoints = qimageCalcApoints(s: img.height(), d: sch, up: isi->xup_yup & 2); |
232 | if (!isi->yapoints) |
233 | return qimageFreeScaleInfo(isi); |
234 | } |
235 | return isi; |
236 | } |
237 | |
238 | |
239 | static void qt_qimageScaleAARGBA_up_x_down_y(QImageScaleInfo *isi, unsigned int *dest, |
240 | int dw, int dh, int dow, int sow); |
241 | |
242 | static void qt_qimageScaleAARGBA_down_x_up_y(QImageScaleInfo *isi, unsigned int *dest, |
243 | int dw, int dh, int dow, int sow); |
244 | |
245 | static void qt_qimageScaleAARGBA_down_xy(QImageScaleInfo *isi, unsigned int *dest, |
246 | int dw, int dh, int dow, int sow); |
247 | |
248 | #if defined(QT_COMPILER_SUPPORTS_SSE4_1) |
249 | template<bool RGB> |
250 | void qt_qimageScaleAARGBA_up_x_down_y_sse4(QImageScaleInfo *isi, unsigned int *dest, |
251 | int dw, int dh, int dow, int sow); |
252 | template<bool RGB> |
253 | void qt_qimageScaleAARGBA_down_x_up_y_sse4(QImageScaleInfo *isi, unsigned int *dest, |
254 | int dw, int dh, int dow, int sow); |
255 | template<bool RGB> |
256 | void qt_qimageScaleAARGBA_down_xy_sse4(QImageScaleInfo *isi, unsigned int *dest, |
257 | int dw, int dh, int dow, int sow); |
258 | #endif |
259 | |
260 | #if defined(__ARM_NEON__) |
261 | template<bool RGB> |
262 | void qt_qimageScaleAARGBA_up_x_down_y_neon(QImageScaleInfo *isi, unsigned int *dest, |
263 | int dw, int dh, int dow, int sow); |
264 | template<bool RGB> |
265 | void qt_qimageScaleAARGBA_down_x_up_y_neon(QImageScaleInfo *isi, unsigned int *dest, |
266 | int dw, int dh, int dow, int sow); |
267 | template<bool RGB> |
268 | void qt_qimageScaleAARGBA_down_xy_neon(QImageScaleInfo *isi, unsigned int *dest, |
269 | int dw, int dh, int dow, int sow); |
270 | #endif |
271 | |
272 | template<typename T> |
273 | static inline void multithread_pixels_function(QImageScaleInfo *isi, int dh, const T &scaleSection) |
274 | { |
275 | #if QT_CONFIG(thread) && !defined(Q_OS_WASM) |
276 | int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16); |
277 | segments = std::min(a: segments, b: dh); |
278 | QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance(); |
279 | if (segments > 1 && threadPool && !threadPool->contains(thread: QThread::currentThread())) { |
280 | QSemaphore semaphore; |
281 | int y = 0; |
282 | for (int i = 0; i < segments; ++i) { |
283 | int yn = (dh - y) / (segments - i); |
284 | threadPool->start([&, y, yn]() { |
285 | scaleSection(y, y + yn); |
286 | semaphore.release(n: 1); |
287 | }); |
288 | y += yn; |
289 | } |
290 | semaphore.acquire(n: segments); |
291 | return; |
292 | } |
293 | #else |
294 | Q_UNUSED(isi); |
295 | #endif |
296 | scaleSection(0, dh); |
297 | } |
298 | |
299 | static void qt_qimageScaleAARGBA_up_xy(QImageScaleInfo *isi, unsigned int *dest, |
300 | int dw, int dh, int dow, int sow) |
301 | { |
302 | const unsigned int **ypoints = isi->ypoints; |
303 | int *xpoints = isi->xpoints; |
304 | int *xapoints = isi->xapoints; |
305 | int *yapoints = isi->yapoints; |
306 | |
307 | /* go through every scanline in the output buffer */ |
308 | auto scaleSection = [&] (int yStart, int yEnd) { |
309 | for (int y = yStart; y < yEnd; ++y) { |
310 | /* calculate the source line we'll scan from */ |
311 | const unsigned int *sptr = ypoints[y]; |
312 | unsigned int *dptr = dest + (y * dow); |
313 | const int yap = yapoints[y]; |
314 | if (yap > 0) { |
315 | for (int x = 0; x < dw; x++) { |
316 | const unsigned int *pix = sptr + xpoints[x]; |
317 | const int xap = xapoints[x]; |
318 | if (xap > 0) |
319 | *dptr = interpolate_4_pixels(t: pix, b: pix + sow, distx: xap, disty: yap); |
320 | else |
321 | *dptr = INTERPOLATE_PIXEL_256(x: pix[0], a: 256 - yap, y: pix[sow], b: yap); |
322 | dptr++; |
323 | } |
324 | } else { |
325 | for (int x = 0; x < dw; x++) { |
326 | const unsigned int *pix = sptr + xpoints[x]; |
327 | const int xap = xapoints[x]; |
328 | if (xap > 0) |
329 | *dptr = INTERPOLATE_PIXEL_256(x: pix[0], a: 256 - xap, y: pix[1], b: xap); |
330 | else |
331 | *dptr = pix[0]; |
332 | dptr++; |
333 | } |
334 | } |
335 | } |
336 | }; |
337 | multithread_pixels_function(isi, dh, scaleSection); |
338 | } |
339 | |
340 | /* scale by area sampling - with alpha */ |
341 | static void qt_qimageScaleAARGBA(QImageScaleInfo *isi, unsigned int *dest, |
342 | int dw, int dh, int dow, int sow) |
343 | { |
344 | /* scaling up both ways */ |
345 | if (isi->xup_yup == 3) { |
346 | qt_qimageScaleAARGBA_up_xy(isi, dest, dw, dh, dow, sow); |
347 | } |
348 | /* if we're scaling down vertically */ |
349 | else if (isi->xup_yup == 1) { |
350 | #ifdef QT_COMPILER_SUPPORTS_SSE4_1 |
351 | if (qCpuHasFeature(SSE4_1)) |
352 | qt_qimageScaleAARGBA_up_x_down_y_sse4<false>(isi, dest, dw, dh, dow, sow); |
353 | else |
354 | #elif defined(__ARM_NEON__) |
355 | if (qCpuHasFeature(NEON)) |
356 | qt_qimageScaleAARGBA_up_x_down_y_neon<false>(isi, dest, dw, dh, dow, sow); |
357 | else |
358 | #endif |
359 | qt_qimageScaleAARGBA_up_x_down_y(isi, dest, dw, dh, dow, sow); |
360 | } |
361 | /* if we're scaling down horizontally */ |
362 | else if (isi->xup_yup == 2) { |
363 | #ifdef QT_COMPILER_SUPPORTS_SSE4_1 |
364 | if (qCpuHasFeature(SSE4_1)) |
365 | qt_qimageScaleAARGBA_down_x_up_y_sse4<false>(isi, dest, dw, dh, dow, sow); |
366 | else |
367 | #elif defined(__ARM_NEON__) |
368 | if (qCpuHasFeature(NEON)) |
369 | qt_qimageScaleAARGBA_down_x_up_y_neon<false>(isi, dest, dw, dh, dow, sow); |
370 | else |
371 | #endif |
372 | qt_qimageScaleAARGBA_down_x_up_y(isi, dest, dw, dh, dow, sow); |
373 | } |
374 | /* if we're scaling down horizontally & vertically */ |
375 | else { |
376 | #ifdef QT_COMPILER_SUPPORTS_SSE4_1 |
377 | if (qCpuHasFeature(SSE4_1)) |
378 | qt_qimageScaleAARGBA_down_xy_sse4<false>(isi, dest, dw, dh, dow, sow); |
379 | else |
380 | #elif defined(__ARM_NEON__) |
381 | if (qCpuHasFeature(NEON)) |
382 | qt_qimageScaleAARGBA_down_xy_neon<false>(isi, dest, dw, dh, dow, sow); |
383 | else |
384 | #endif |
385 | qt_qimageScaleAARGBA_down_xy(isi, dest, dw, dh, dow, sow); |
386 | } |
387 | } |
388 | |
389 | inline static void qt_qimageScaleAARGBA_helper(const unsigned int *pix, int xyap, int Cxy, int step, int &r, int &g, int &b, int &a) |
390 | { |
391 | r = qRed(rgb: *pix) * xyap; |
392 | g = qGreen(rgb: *pix) * xyap; |
393 | b = qBlue(rgb: *pix) * xyap; |
394 | a = qAlpha(rgb: *pix) * xyap; |
395 | int j; |
396 | for (j = (1 << 14) - xyap; j > Cxy; j -= Cxy) { |
397 | pix += step; |
398 | r += qRed(rgb: *pix) * Cxy; |
399 | g += qGreen(rgb: *pix) * Cxy; |
400 | b += qBlue(rgb: *pix) * Cxy; |
401 | a += qAlpha(rgb: *pix) * Cxy; |
402 | } |
403 | pix += step; |
404 | r += qRed(rgb: *pix) * j; |
405 | g += qGreen(rgb: *pix) * j; |
406 | b += qBlue(rgb: *pix) * j; |
407 | a += qAlpha(rgb: *pix) * j; |
408 | } |
409 | |
410 | static void qt_qimageScaleAARGBA_up_x_down_y(QImageScaleInfo *isi, unsigned int *dest, |
411 | int dw, int dh, int dow, int sow) |
412 | { |
413 | const unsigned int **ypoints = isi->ypoints; |
414 | int *xpoints = isi->xpoints; |
415 | int *xapoints = isi->xapoints; |
416 | int *yapoints = isi->yapoints; |
417 | |
418 | /* go through every scanline in the output buffer */ |
419 | auto scaleSection = [&] (int yStart, int yEnd) { |
420 | for (int y = yStart; y < yEnd; ++y) { |
421 | int Cy = yapoints[y] >> 16; |
422 | int yap = yapoints[y] & 0xffff; |
423 | |
424 | unsigned int *dptr = dest + (y * dow); |
425 | for (int x = 0; x < dw; x++) { |
426 | const unsigned int *sptr = ypoints[y] + xpoints[x]; |
427 | int r, g, b, a; |
428 | qt_qimageScaleAARGBA_helper(pix: sptr, xyap: yap, Cxy: Cy, step: sow, r, g, b, a); |
429 | |
430 | int xap = xapoints[x]; |
431 | if (xap > 0) { |
432 | int rr, gg, bb, aa; |
433 | qt_qimageScaleAARGBA_helper(pix: sptr + 1, xyap: yap, Cxy: Cy, step: sow, r&: rr, g&: gg, b&: bb, a&: aa); |
434 | |
435 | r = r * (256 - xap); |
436 | g = g * (256 - xap); |
437 | b = b * (256 - xap); |
438 | a = a * (256 - xap); |
439 | r = (r + (rr * xap)) >> 8; |
440 | g = (g + (gg * xap)) >> 8; |
441 | b = (b + (bb * xap)) >> 8; |
442 | a = (a + (aa * xap)) >> 8; |
443 | } |
444 | *dptr++ = qRgba(r: r >> 14, g: g >> 14, b: b >> 14, a: a >> 14); |
445 | } |
446 | } |
447 | }; |
448 | multithread_pixels_function(isi, dh, scaleSection); |
449 | } |
450 | |
451 | static void qt_qimageScaleAARGBA_down_x_up_y(QImageScaleInfo *isi, unsigned int *dest, |
452 | int dw, int dh, int dow, int sow) |
453 | { |
454 | const unsigned int **ypoints = isi->ypoints; |
455 | int *xpoints = isi->xpoints; |
456 | int *xapoints = isi->xapoints; |
457 | int *yapoints = isi->yapoints; |
458 | |
459 | /* go through every scanline in the output buffer */ |
460 | auto scaleSection = [&] (int yStart, int yEnd) { |
461 | for (int y = yStart; y < yEnd; ++y) { |
462 | unsigned int *dptr = dest + (y * dow); |
463 | for (int x = 0; x < dw; x++) { |
464 | int Cx = xapoints[x] >> 16; |
465 | int xap = xapoints[x] & 0xffff; |
466 | |
467 | const unsigned int *sptr = ypoints[y] + xpoints[x]; |
468 | int r, g, b, a; |
469 | qt_qimageScaleAARGBA_helper(pix: sptr, xyap: xap, Cxy: Cx, step: 1, r, g, b, a); |
470 | |
471 | int yap = yapoints[y]; |
472 | if (yap > 0) { |
473 | int rr, gg, bb, aa; |
474 | qt_qimageScaleAARGBA_helper(pix: sptr + sow, xyap: xap, Cxy: Cx, step: 1, r&: rr, g&: gg, b&: bb, a&: aa); |
475 | |
476 | r = r * (256 - yap); |
477 | g = g * (256 - yap); |
478 | b = b * (256 - yap); |
479 | a = a * (256 - yap); |
480 | r = (r + (rr * yap)) >> 8; |
481 | g = (g + (gg * yap)) >> 8; |
482 | b = (b + (bb * yap)) >> 8; |
483 | a = (a + (aa * yap)) >> 8; |
484 | } |
485 | *dptr = qRgba(r: r >> 14, g: g >> 14, b: b >> 14, a: a >> 14); |
486 | dptr++; |
487 | } |
488 | } |
489 | }; |
490 | multithread_pixels_function(isi, dh, scaleSection); |
491 | } |
492 | |
493 | static void qt_qimageScaleAARGBA_down_xy(QImageScaleInfo *isi, unsigned int *dest, |
494 | int dw, int dh, int dow, int sow) |
495 | { |
496 | const unsigned int **ypoints = isi->ypoints; |
497 | int *xpoints = isi->xpoints; |
498 | int *xapoints = isi->xapoints; |
499 | int *yapoints = isi->yapoints; |
500 | |
501 | auto scaleSection = [&] (int yStart, int yEnd) { |
502 | for (int y = yStart; y < yEnd; ++y) { |
503 | int Cy = (yapoints[y]) >> 16; |
504 | int yap = (yapoints[y]) & 0xffff; |
505 | |
506 | unsigned int *dptr = dest + (y * dow); |
507 | for (int x = 0; x < dw; x++) { |
508 | int Cx = xapoints[x] >> 16; |
509 | int xap = xapoints[x] & 0xffff; |
510 | |
511 | const unsigned int *sptr = ypoints[y] + xpoints[x]; |
512 | int rx, gx, bx, ax; |
513 | qt_qimageScaleAARGBA_helper(pix: sptr, xyap: xap, Cxy: Cx, step: 1, r&: rx, g&: gx, b&: bx, a&: ax); |
514 | |
515 | int r = ((rx>>4) * yap); |
516 | int g = ((gx>>4) * yap); |
517 | int b = ((bx>>4) * yap); |
518 | int a = ((ax>>4) * yap); |
519 | |
520 | int j; |
521 | for (j = (1 << 14) - yap; j > Cy; j -= Cy) { |
522 | sptr += sow; |
523 | qt_qimageScaleAARGBA_helper(pix: sptr, xyap: xap, Cxy: Cx, step: 1, r&: rx, g&: gx, b&: bx, a&: ax); |
524 | r += ((rx>>4) * Cy); |
525 | g += ((gx>>4) * Cy); |
526 | b += ((bx>>4) * Cy); |
527 | a += ((ax>>4) * Cy); |
528 | } |
529 | sptr += sow; |
530 | qt_qimageScaleAARGBA_helper(pix: sptr, xyap: xap, Cxy: Cx, step: 1, r&: rx, g&: gx, b&: bx, a&: ax); |
531 | |
532 | r += ((rx>>4) * j); |
533 | g += ((gx>>4) * j); |
534 | b += ((bx>>4) * j); |
535 | a += ((ax>>4) * j); |
536 | |
537 | *dptr = qRgba(r: r >> 24, g: g >> 24, b: b >> 24, a: a >> 24); |
538 | dptr++; |
539 | } |
540 | } |
541 | }; |
542 | multithread_pixels_function(isi, dh, scaleSection); |
543 | } |
544 | |
545 | #if QT_CONFIG(raster_64bit) |
546 | static void qt_qimageScaleRgba64_up_x_down_y(QImageScaleInfo *isi, QRgba64 *dest, |
547 | int dw, int dh, int dow, int sow); |
548 | |
549 | static void qt_qimageScaleRgba64_down_x_up_y(QImageScaleInfo *isi, QRgba64 *dest, |
550 | int dw, int dh, int dow, int sow); |
551 | |
552 | static void qt_qimageScaleRgba64_down_xy(QImageScaleInfo *isi, QRgba64 *dest, |
553 | int dw, int dh, int dow, int sow); |
554 | |
555 | static void qt_qimageScaleRgba64_up_xy(QImageScaleInfo *isi, QRgba64 *dest, |
556 | int dw, int dh, int dow, int sow) |
557 | { |
558 | const QRgba64 **ypoints = (const QRgba64 **)isi->ypoints; |
559 | int *xpoints = isi->xpoints; |
560 | int *xapoints = isi->xapoints; |
561 | int *yapoints = isi->yapoints; |
562 | |
563 | auto scaleSection = [&] (int yStart, int yEnd) { |
564 | for (int y = yStart; y < yEnd; ++y) { |
565 | const QRgba64 *sptr = ypoints[y]; |
566 | QRgba64 *dptr = dest + (y * dow); |
567 | const int yap = yapoints[y]; |
568 | if (yap > 0) { |
569 | for (int x = 0; x < dw; x++) { |
570 | const QRgba64 *pix = sptr + xpoints[x]; |
571 | const int xap = xapoints[x]; |
572 | if (xap > 0) |
573 | *dptr = interpolate_4_pixels_rgb64(t: pix, b: pix + sow, distx: xap * 256, disty: yap * 256); |
574 | else |
575 | *dptr = interpolate256(x: pix[0], alpha1: 256 - yap, y: pix[sow], alpha2: yap); |
576 | dptr++; |
577 | } |
578 | } else { |
579 | for (int x = 0; x < dw; x++) { |
580 | const QRgba64 *pix = sptr + xpoints[x]; |
581 | const int xap = xapoints[x]; |
582 | if (xap > 0) |
583 | *dptr = interpolate256(x: pix[0], alpha1: 256 - xap, y: pix[1], alpha2: xap); |
584 | else |
585 | *dptr = pix[0]; |
586 | dptr++; |
587 | } |
588 | } |
589 | } |
590 | }; |
591 | multithread_pixels_function(isi, dh, scaleSection); |
592 | } |
593 | |
594 | void qt_qimageScaleRgba64(QImageScaleInfo *isi, QRgba64 *dest, |
595 | int dw, int dh, int dow, int sow) |
596 | { |
597 | if (isi->xup_yup == 3) |
598 | qt_qimageScaleRgba64_up_xy(isi, dest, dw, dh, dow, sow); |
599 | else if (isi->xup_yup == 1) |
600 | qt_qimageScaleRgba64_up_x_down_y(isi, dest, dw, dh, dow, sow); |
601 | else if (isi->xup_yup == 2) |
602 | qt_qimageScaleRgba64_down_x_up_y(isi, dest, dw, dh, dow, sow); |
603 | else |
604 | qt_qimageScaleRgba64_down_xy(isi, dest, dw, dh, dow, sow); |
605 | } |
606 | |
607 | inline static void qt_qimageScaleRgba64_helper(const QRgba64 *pix, int xyap, int Cxy, int step, qint64 &r, qint64 &g, qint64 &b, qint64 &a) |
608 | { |
609 | r = pix->red() * xyap; |
610 | g = pix->green() * xyap; |
611 | b = pix->blue() * xyap; |
612 | a = pix->alpha() * xyap; |
613 | int j; |
614 | for (j = (1 << 14) - xyap; j > Cxy; j -= Cxy ){ |
615 | pix += step; |
616 | r += pix->red() * Cxy; |
617 | g += pix->green() * Cxy; |
618 | b += pix->blue() * Cxy; |
619 | a += pix->alpha() * Cxy; |
620 | } |
621 | pix += step; |
622 | r += pix->red() * j; |
623 | g += pix->green() * j; |
624 | b += pix->blue() * j; |
625 | a += pix->alpha() * j; |
626 | } |
627 | |
628 | static void qt_qimageScaleRgba64_up_x_down_y(QImageScaleInfo *isi, QRgba64 *dest, |
629 | int dw, int dh, int dow, int sow) |
630 | { |
631 | const QRgba64 **ypoints = (const QRgba64 **)isi->ypoints; |
632 | int *xpoints = isi->xpoints; |
633 | int *xapoints = isi->xapoints; |
634 | int *yapoints = isi->yapoints; |
635 | |
636 | auto scaleSection = [&] (int yStart, int yEnd) { |
637 | for (int y = yStart; y < yEnd; ++y) { |
638 | int Cy = (yapoints[y]) >> 16; |
639 | int yap = (yapoints[y]) & 0xffff; |
640 | |
641 | QRgba64 *dptr = dest + (y * dow); |
642 | for (int x = 0; x < dw; x++) { |
643 | const QRgba64 *sptr = ypoints[y] + xpoints[x]; |
644 | qint64 r, g, b, a; |
645 | qt_qimageScaleRgba64_helper(pix: sptr, xyap: yap, Cxy: Cy, step: sow, r, g, b, a); |
646 | |
647 | int xap = xapoints[x]; |
648 | if (xap > 0) { |
649 | qint64 rr, gg, bb, aa; |
650 | qt_qimageScaleRgba64_helper(pix: sptr + 1, xyap: yap, Cxy: Cy, step: sow, r&: rr, g&: gg, b&: bb, a&: aa); |
651 | |
652 | r = r * (256 - xap); |
653 | g = g * (256 - xap); |
654 | b = b * (256 - xap); |
655 | a = a * (256 - xap); |
656 | r = (r + (rr * xap)) >> 8; |
657 | g = (g + (gg * xap)) >> 8; |
658 | b = (b + (bb * xap)) >> 8; |
659 | a = (a + (aa * xap)) >> 8; |
660 | } |
661 | *dptr++ = qRgba64(r: r >> 14, g: g >> 14, b: b >> 14, a: a >> 14); |
662 | } |
663 | } |
664 | }; |
665 | multithread_pixels_function(isi, dh, scaleSection); |
666 | } |
667 | |
668 | static void qt_qimageScaleRgba64_down_x_up_y(QImageScaleInfo *isi, QRgba64 *dest, |
669 | int dw, int dh, int dow, int sow) |
670 | { |
671 | const QRgba64 **ypoints = (const QRgba64 **)isi->ypoints; |
672 | int *xpoints = isi->xpoints; |
673 | int *xapoints = isi->xapoints; |
674 | int *yapoints = isi->yapoints; |
675 | |
676 | auto scaleSection = [&] (int yStart, int yEnd) { |
677 | for (int y = yStart; y < yEnd; ++y) { |
678 | QRgba64 *dptr = dest + (y * dow); |
679 | for (int x = 0; x < dw; x++) { |
680 | int Cx = xapoints[x] >> 16; |
681 | int xap = xapoints[x] & 0xffff; |
682 | |
683 | const QRgba64 *sptr = ypoints[y] + xpoints[x]; |
684 | qint64 r, g, b, a; |
685 | qt_qimageScaleRgba64_helper(pix: sptr, xyap: xap, Cxy: Cx, step: 1, r, g, b, a); |
686 | |
687 | int yap = yapoints[y]; |
688 | if (yap > 0) { |
689 | qint64 rr, gg, bb, aa; |
690 | qt_qimageScaleRgba64_helper(pix: sptr + sow, xyap: xap, Cxy: Cx, step: 1, r&: rr, g&: gg, b&: bb, a&: aa); |
691 | |
692 | r = r * (256 - yap); |
693 | g = g * (256 - yap); |
694 | b = b * (256 - yap); |
695 | a = a * (256 - yap); |
696 | r = (r + (rr * yap)) >> 8; |
697 | g = (g + (gg * yap)) >> 8; |
698 | b = (b + (bb * yap)) >> 8; |
699 | a = (a + (aa * yap)) >> 8; |
700 | } |
701 | *dptr = qRgba64(r: r >> 14, g: g >> 14, b: b >> 14, a: a >> 14); |
702 | dptr++; |
703 | } |
704 | } |
705 | }; |
706 | multithread_pixels_function(isi, dh, scaleSection); |
707 | } |
708 | |
709 | static void qt_qimageScaleRgba64_down_xy(QImageScaleInfo *isi, QRgba64 *dest, |
710 | int dw, int dh, int dow, int sow) |
711 | { |
712 | const QRgba64 **ypoints = (const QRgba64 **)isi->ypoints; |
713 | int *xpoints = isi->xpoints; |
714 | int *xapoints = isi->xapoints; |
715 | int *yapoints = isi->yapoints; |
716 | |
717 | auto scaleSection = [&] (int yStart, int yEnd) { |
718 | for (int y = yStart; y < yEnd; ++y) { |
719 | int Cy = (yapoints[y]) >> 16; |
720 | int yap = (yapoints[y]) & 0xffff; |
721 | |
722 | QRgba64 *dptr = dest + (y * dow); |
723 | for (int x = 0; x < dw; x++) { |
724 | int Cx = xapoints[x] >> 16; |
725 | int xap = xapoints[x] & 0xffff; |
726 | |
727 | const QRgba64 *sptr = ypoints[y] + xpoints[x]; |
728 | qint64 rx, gx, bx, ax; |
729 | qt_qimageScaleRgba64_helper(pix: sptr, xyap: xap, Cxy: Cx, step: 1, r&: rx, g&: gx, b&: bx, a&: ax); |
730 | |
731 | qint64 r = rx * yap; |
732 | qint64 g = gx * yap; |
733 | qint64 b = bx * yap; |
734 | qint64 a = ax * yap; |
735 | int j; |
736 | for (j = (1 << 14) - yap; j > Cy; j -= Cy) { |
737 | sptr += sow; |
738 | qt_qimageScaleRgba64_helper(pix: sptr, xyap: xap, Cxy: Cx, step: 1, r&: rx, g&: gx, b&: bx, a&: ax); |
739 | r += rx * Cy; |
740 | g += gx * Cy; |
741 | b += bx * Cy; |
742 | a += ax * Cy; |
743 | } |
744 | sptr += sow; |
745 | qt_qimageScaleRgba64_helper(pix: sptr, xyap: xap, Cxy: Cx, step: 1, r&: rx, g&: gx, b&: bx, a&: ax); |
746 | r += rx * j; |
747 | g += gx * j; |
748 | b += bx * j; |
749 | a += ax * j; |
750 | |
751 | *dptr = qRgba64(r: r >> 28, g: g >> 28, b: b >> 28, a: a >> 28); |
752 | dptr++; |
753 | } |
754 | } |
755 | }; |
756 | multithread_pixels_function(isi, dh, scaleSection); |
757 | } |
758 | #endif |
759 | |
760 | #if QT_CONFIG(raster_fp) |
761 | static void qt_qimageScaleRgbaFP_up_x_down_y(QImageScaleInfo *isi, QRgbaFloat32 *dest, |
762 | int dw, int dh, int dow, int sow); |
763 | |
764 | static void qt_qimageScaleRgbaFP_down_x_up_y(QImageScaleInfo *isi, QRgbaFloat32 *dest, |
765 | int dw, int dh, int dow, int sow); |
766 | |
767 | static void qt_qimageScaleRgbaFP_down_xy(QImageScaleInfo *isi, QRgbaFloat32 *dest, |
768 | int dw, int dh, int dow, int sow); |
769 | |
770 | static void qt_qimageScaleRgbaFP_up_xy(QImageScaleInfo *isi, QRgbaFloat32 *dest, |
771 | int dw, int dh, int dow, int sow) |
772 | { |
773 | const QRgbaFloat32 **ypoints = (const QRgbaFloat32 **)isi->ypoints; |
774 | int *xpoints = isi->xpoints; |
775 | int *xapoints = isi->xapoints; |
776 | int *yapoints = isi->yapoints; |
777 | |
778 | auto scaleSection = [&] (int yStart, int yEnd) { |
779 | for (int y = yStart; y < yEnd; ++y) { |
780 | const QRgbaFloat32 *sptr = ypoints[y]; |
781 | QRgbaFloat32 *dptr = dest + (y * dow); |
782 | const int yap = yapoints[y]; |
783 | if (yap > 0) { |
784 | for (int x = 0; x < dw; x++) { |
785 | const QRgbaFloat32 *pix = sptr + xpoints[x]; |
786 | const int xap = xapoints[x]; |
787 | if (xap > 0) |
788 | *dptr = interpolate_4_pixels_rgba32f(t: pix, b: pix + sow, distx: xap * 256, disty: yap * 256); |
789 | else |
790 | *dptr = interpolate_rgba32f(x: pix[0], alpha1: 256 - yap, y: pix[sow], alpha2: yap); |
791 | dptr++; |
792 | } |
793 | } else { |
794 | for (int x = 0; x < dw; x++) { |
795 | const QRgbaFloat32 *pix = sptr + xpoints[x]; |
796 | const int xap = xapoints[x]; |
797 | if (xap > 0) |
798 | *dptr = interpolate_rgba32f(x: pix[0], alpha1: 256 - xap, y: pix[1], alpha2: xap); |
799 | else |
800 | *dptr = pix[0]; |
801 | dptr++; |
802 | } |
803 | } |
804 | } |
805 | }; |
806 | multithread_pixels_function(isi, dh, scaleSection); |
807 | } |
808 | |
809 | void qt_qimageScaleRgbaFP(QImageScaleInfo *isi, QRgbaFloat32 *dest, |
810 | int dw, int dh, int dow, int sow) |
811 | { |
812 | if (isi->xup_yup == 3) |
813 | qt_qimageScaleRgbaFP_up_xy(isi, dest, dw, dh, dow, sow); |
814 | else if (isi->xup_yup == 1) |
815 | qt_qimageScaleRgbaFP_up_x_down_y(isi, dest, dw, dh, dow, sow); |
816 | else if (isi->xup_yup == 2) |
817 | qt_qimageScaleRgbaFP_down_x_up_y(isi, dest, dw, dh, dow, sow); |
818 | else |
819 | qt_qimageScaleRgbaFP_down_xy(isi, dest, dw, dh, dow, sow); |
820 | } |
821 | |
822 | inline static void qt_qimageScaleRgbaFP_helper(const QRgbaFloat32 *pix, int xyap, int Cxy, int step, float &r, float &g, float &b, float &a) |
823 | { |
824 | constexpr float f = (1.0f / float(1<<14)); |
825 | const float xyapf = xyap * f; |
826 | const float Cxyf = Cxy * f; |
827 | r = pix->red() * xyapf; |
828 | g = pix->green() * xyapf; |
829 | b = pix->blue() * xyapf; |
830 | a = pix->alpha() * xyapf; |
831 | int j; |
832 | for (j = (1 << 14) - xyap; j > Cxy; j -= Cxy ){ |
833 | pix += step; |
834 | r += pix->red() * Cxyf; |
835 | g += pix->green() * Cxyf; |
836 | b += pix->blue() * Cxyf; |
837 | a += pix->alpha() * Cxyf; |
838 | } |
839 | pix += step; |
840 | const float jf = j * f; |
841 | r += pix->red() * jf; |
842 | g += pix->green() * jf; |
843 | b += pix->blue() * jf; |
844 | a += pix->alpha() * jf; |
845 | } |
846 | |
847 | static void qt_qimageScaleRgbaFP_up_x_down_y(QImageScaleInfo *isi, QRgbaFloat32 *dest, |
848 | int dw, int dh, int dow, int sow) |
849 | { |
850 | const QRgbaFloat32 **ypoints = (const QRgbaFloat32 **)isi->ypoints; |
851 | int *xpoints = isi->xpoints; |
852 | int *xapoints = isi->xapoints; |
853 | int *yapoints = isi->yapoints; |
854 | |
855 | auto scaleSection = [&] (int yStart, int yEnd) { |
856 | for (int y = yStart; y < yEnd; ++y) { |
857 | int Cy = (yapoints[y]) >> 16; |
858 | int yap = (yapoints[y]) & 0xffff; |
859 | |
860 | QRgbaFloat32 *dptr = dest + (y * dow); |
861 | for (int x = 0; x < dw; x++) { |
862 | const QRgbaFloat32 *sptr = ypoints[y] + xpoints[x]; |
863 | float r, g, b, a; |
864 | qt_qimageScaleRgbaFP_helper(pix: sptr, xyap: yap, Cxy: Cy, step: sow, r, g, b, a); |
865 | |
866 | int xap = xapoints[x]; |
867 | float xapf = xap * (1.f / 256.f); |
868 | if (xap > 0) { |
869 | float rr, gg, bb, aa; |
870 | qt_qimageScaleRgbaFP_helper(pix: sptr + 1, xyap: yap, Cxy: Cy, step: sow, r&: rr, g&: gg, b&: bb, a&: aa); |
871 | |
872 | r = (r * (1.0f - xapf) + (rr * xapf)); |
873 | g = (g * (1.0f - xapf) + (gg * xapf)); |
874 | b = (b * (1.0f - xapf) + (bb * xapf)); |
875 | a = (a * (1.0f - xapf) + (aa * xapf)); |
876 | } |
877 | *dptr++ = QRgbaFloat32{.r: r, .g: g, .b: b, .a: a}; |
878 | } |
879 | } |
880 | }; |
881 | multithread_pixels_function(isi, dh, scaleSection); |
882 | } |
883 | |
884 | static void qt_qimageScaleRgbaFP_down_x_up_y(QImageScaleInfo *isi, QRgbaFloat32 *dest, |
885 | int dw, int dh, int dow, int sow) |
886 | { |
887 | const QRgbaFloat32 **ypoints = (const QRgbaFloat32 **)isi->ypoints; |
888 | int *xpoints = isi->xpoints; |
889 | int *xapoints = isi->xapoints; |
890 | int *yapoints = isi->yapoints; |
891 | |
892 | auto scaleSection = [&] (int yStart, int yEnd) { |
893 | for (int y = yStart; y < yEnd; ++y) { |
894 | QRgbaFloat32 *dptr = dest + (y * dow); |
895 | for (int x = 0; x < dw; x++) { |
896 | int Cx = xapoints[x] >> 16; |
897 | int xap = xapoints[x] & 0xffff; |
898 | |
899 | const QRgbaFloat32 *sptr = ypoints[y] + xpoints[x]; |
900 | float r, g, b, a; |
901 | qt_qimageScaleRgbaFP_helper(pix: sptr, xyap: xap, Cxy: Cx, step: 1, r, g, b, a); |
902 | |
903 | int yap = yapoints[y]; |
904 | float yapf = yap * (1.f / 256.f); |
905 | if (yap > 0) { |
906 | float rr, gg, bb, aa; |
907 | qt_qimageScaleRgbaFP_helper(pix: sptr + sow, xyap: xap, Cxy: Cx, step: 1, r&: rr, g&: gg, b&: bb, a&: aa); |
908 | |
909 | r = (r * (1.0f - yapf) + (rr * yapf)); |
910 | g = (g * (1.0f - yapf) + (gg * yapf)); |
911 | b = (b * (1.0f - yapf) + (bb * yapf)); |
912 | a = (a * (1.0f - yapf) + (aa * yapf)); |
913 | } |
914 | *dptr++ = QRgbaFloat32{.r: r, .g: g, .b: b, .a: a}; |
915 | } |
916 | } |
917 | }; |
918 | multithread_pixels_function(isi, dh, scaleSection); |
919 | } |
920 | |
921 | static void qt_qimageScaleRgbaFP_down_xy(QImageScaleInfo *isi, QRgbaFloat32 *dest, |
922 | int dw, int dh, int dow, int sow) |
923 | { |
924 | const QRgbaFloat32 **ypoints = (const QRgbaFloat32 **)isi->ypoints; |
925 | int *xpoints = isi->xpoints; |
926 | int *xapoints = isi->xapoints; |
927 | int *yapoints = isi->yapoints; |
928 | |
929 | auto scaleSection = [&] (int yStart, int yEnd) { |
930 | constexpr float f = 1.f / float(1 << 14); |
931 | for (int y = yStart; y < yEnd; ++y) { |
932 | int Cy = (yapoints[y]) >> 16; |
933 | int yap = (yapoints[y]) & 0xffff; |
934 | |
935 | QRgbaFloat32 *dptr = dest + (y * dow); |
936 | for (int x = 0; x < dw; x++) { |
937 | int Cx = xapoints[x] >> 16; |
938 | int xap = xapoints[x] & 0xffff; |
939 | |
940 | const QRgbaFloat32 *sptr = ypoints[y] + xpoints[x]; |
941 | float rx, gx, bx, ax; |
942 | qt_qimageScaleRgbaFP_helper(pix: sptr, xyap: xap, Cxy: Cx, step: 1, r&: rx, g&: gx, b&: bx, a&: ax); |
943 | |
944 | const float yapf = yap * f; |
945 | const float Cyf = Cy * f; |
946 | float r = rx * yapf; |
947 | float g = gx * yapf; |
948 | float b = bx * yapf; |
949 | float a = ax * yapf; |
950 | int j; |
951 | for (j = (1 << 14) - yap; j > Cy; j -= Cy) { |
952 | sptr += sow; |
953 | qt_qimageScaleRgbaFP_helper(pix: sptr, xyap: xap, Cxy: Cx, step: 1, r&: rx, g&: gx, b&: bx, a&: ax); |
954 | r += rx * Cyf; |
955 | g += gx * Cyf; |
956 | b += bx * Cyf; |
957 | a += ax * Cyf; |
958 | } |
959 | sptr += sow; |
960 | qt_qimageScaleRgbaFP_helper(pix: sptr, xyap: xap, Cxy: Cx, step: 1, r&: rx, g&: gx, b&: bx, a&: ax); |
961 | const float jf = j * f; |
962 | r += rx * jf; |
963 | g += gx * jf; |
964 | b += bx * jf; |
965 | a += ax * jf; |
966 | |
967 | *dptr++ = QRgbaFloat32{.r: r, .g: g, .b: b, .a: a}; |
968 | } |
969 | } |
970 | }; |
971 | multithread_pixels_function(isi, dh, scaleSection); |
972 | } |
973 | #endif |
974 | |
975 | static void qt_qimageScaleAARGB_up_x_down_y(QImageScaleInfo *isi, unsigned int *dest, |
976 | int dw, int dh, int dow, int sow); |
977 | |
978 | static void qt_qimageScaleAARGB_down_x_up_y(QImageScaleInfo *isi, unsigned int *dest, |
979 | int dw, int dh, int dow, int sow); |
980 | |
981 | static void qt_qimageScaleAARGB_down_xy(QImageScaleInfo *isi, unsigned int *dest, |
982 | int dw, int dh, int dow, int sow); |
983 | |
984 | /* scale by area sampling - IGNORE the ALPHA byte*/ |
985 | static void qt_qimageScaleAARGB(QImageScaleInfo *isi, unsigned int *dest, |
986 | int dw, int dh, int dow, int sow) |
987 | { |
988 | /* scaling up both ways */ |
989 | if (isi->xup_yup == 3) { |
990 | qt_qimageScaleAARGBA_up_xy(isi, dest, dw, dh, dow, sow); |
991 | } |
992 | /* if we're scaling down vertically */ |
993 | else if (isi->xup_yup == 1) { |
994 | #ifdef QT_COMPILER_SUPPORTS_SSE4_1 |
995 | if (qCpuHasFeature(SSE4_1)) |
996 | qt_qimageScaleAARGBA_up_x_down_y_sse4<true>(isi, dest, dw, dh, dow, sow); |
997 | else |
998 | #elif defined(__ARM_NEON__) |
999 | if (qCpuHasFeature(NEON)) |
1000 | qt_qimageScaleAARGBA_up_x_down_y_neon<true>(isi, dest, dw, dh, dow, sow); |
1001 | else |
1002 | #endif |
1003 | qt_qimageScaleAARGB_up_x_down_y(isi, dest, dw, dh, dow, sow); |
1004 | } |
1005 | /* if we're scaling down horizontally */ |
1006 | else if (isi->xup_yup == 2) { |
1007 | #ifdef QT_COMPILER_SUPPORTS_SSE4_1 |
1008 | if (qCpuHasFeature(SSE4_1)) |
1009 | qt_qimageScaleAARGBA_down_x_up_y_sse4<true>(isi, dest, dw, dh, dow, sow); |
1010 | else |
1011 | #elif defined(__ARM_NEON__) |
1012 | if (qCpuHasFeature(NEON)) |
1013 | qt_qimageScaleAARGBA_down_x_up_y_neon<true>(isi, dest, dw, dh, dow, sow); |
1014 | else |
1015 | #endif |
1016 | qt_qimageScaleAARGB_down_x_up_y(isi, dest, dw, dh, dow, sow); |
1017 | } |
1018 | /* if we're scaling down horizontally & vertically */ |
1019 | else { |
1020 | #ifdef QT_COMPILER_SUPPORTS_SSE4_1 |
1021 | if (qCpuHasFeature(SSE4_1)) |
1022 | qt_qimageScaleAARGBA_down_xy_sse4<true>(isi, dest, dw, dh, dow, sow); |
1023 | else |
1024 | #elif defined(__ARM_NEON__) |
1025 | if (qCpuHasFeature(NEON)) |
1026 | qt_qimageScaleAARGBA_down_xy_neon<true>(isi, dest, dw, dh, dow, sow); |
1027 | else |
1028 | #endif |
1029 | qt_qimageScaleAARGB_down_xy(isi, dest, dw, dh, dow, sow); |
1030 | } |
1031 | } |
1032 | |
1033 | |
1034 | inline static void qt_qimageScaleAARGB_helper(const unsigned int *pix, int xyap, int Cxy, int step, int &r, int &g, int &b) |
1035 | { |
1036 | r = qRed(rgb: *pix) * xyap; |
1037 | g = qGreen(rgb: *pix) * xyap; |
1038 | b = qBlue(rgb: *pix) * xyap; |
1039 | int j; |
1040 | for (j = (1 << 14) - xyap; j > Cxy; j -= Cxy) { |
1041 | pix += step; |
1042 | r += qRed(rgb: *pix) * Cxy; |
1043 | g += qGreen(rgb: *pix) * Cxy; |
1044 | b += qBlue(rgb: *pix) * Cxy; |
1045 | } |
1046 | pix += step; |
1047 | r += qRed(rgb: *pix) * j; |
1048 | g += qGreen(rgb: *pix) * j; |
1049 | b += qBlue(rgb: *pix) * j; |
1050 | } |
1051 | |
1052 | static void qt_qimageScaleAARGB_up_x_down_y(QImageScaleInfo *isi, unsigned int *dest, |
1053 | int dw, int dh, int dow, int sow) |
1054 | { |
1055 | const unsigned int **ypoints = isi->ypoints; |
1056 | int *xpoints = isi->xpoints; |
1057 | int *xapoints = isi->xapoints; |
1058 | int *yapoints = isi->yapoints; |
1059 | |
1060 | /* go through every scanline in the output buffer */ |
1061 | auto scaleSection = [&] (int yStart, int yEnd) { |
1062 | for (int y = yStart; y < yEnd; ++y) { |
1063 | int Cy = yapoints[y] >> 16; |
1064 | int yap = yapoints[y] & 0xffff; |
1065 | |
1066 | unsigned int *dptr = dest + (y * dow); |
1067 | for (int x = 0; x < dw; x++) { |
1068 | const unsigned int *sptr = ypoints[y] + xpoints[x]; |
1069 | int r, g, b; |
1070 | qt_qimageScaleAARGB_helper(pix: sptr, xyap: yap, Cxy: Cy, step: sow, r, g, b); |
1071 | |
1072 | int xap = xapoints[x]; |
1073 | if (xap > 0) { |
1074 | int rr, bb, gg; |
1075 | qt_qimageScaleAARGB_helper(pix: sptr + 1, xyap: yap, Cxy: Cy, step: sow, r&: rr, g&: gg, b&: bb); |
1076 | |
1077 | r = r * (256 - xap); |
1078 | g = g * (256 - xap); |
1079 | b = b * (256 - xap); |
1080 | r = (r + (rr * xap)) >> 8; |
1081 | g = (g + (gg * xap)) >> 8; |
1082 | b = (b + (bb * xap)) >> 8; |
1083 | } |
1084 | *dptr++ = qRgb(r: r >> 14, g: g >> 14, b: b >> 14); |
1085 | } |
1086 | } |
1087 | }; |
1088 | multithread_pixels_function(isi, dh, scaleSection); |
1089 | } |
1090 | |
1091 | static void qt_qimageScaleAARGB_down_x_up_y(QImageScaleInfo *isi, unsigned int *dest, |
1092 | int dw, int dh, int dow, int sow) |
1093 | { |
1094 | const unsigned int **ypoints = isi->ypoints; |
1095 | int *xpoints = isi->xpoints; |
1096 | int *xapoints = isi->xapoints; |
1097 | int *yapoints = isi->yapoints; |
1098 | |
1099 | /* go through every scanline in the output buffer */ |
1100 | auto scaleSection = [&] (int yStart, int yEnd) { |
1101 | for (int y = yStart; y < yEnd; ++y) { |
1102 | unsigned int *dptr = dest + (y * dow); |
1103 | for (int x = 0; x < dw; x++) { |
1104 | int Cx = xapoints[x] >> 16; |
1105 | int xap = xapoints[x] & 0xffff; |
1106 | |
1107 | const unsigned int *sptr = ypoints[y] + xpoints[x]; |
1108 | int r, g, b; |
1109 | qt_qimageScaleAARGB_helper(pix: sptr, xyap: xap, Cxy: Cx, step: 1, r, g, b); |
1110 | |
1111 | int yap = yapoints[y]; |
1112 | if (yap > 0) { |
1113 | int rr, bb, gg; |
1114 | qt_qimageScaleAARGB_helper(pix: sptr + sow, xyap: xap, Cxy: Cx, step: 1, r&: rr, g&: gg, b&: bb); |
1115 | |
1116 | r = r * (256 - yap); |
1117 | g = g * (256 - yap); |
1118 | b = b * (256 - yap); |
1119 | r = (r + (rr * yap)) >> 8; |
1120 | g = (g + (gg * yap)) >> 8; |
1121 | b = (b + (bb * yap)) >> 8; |
1122 | } |
1123 | *dptr++ = qRgb(r: r >> 14, g: g >> 14, b: b >> 14); |
1124 | } |
1125 | } |
1126 | }; |
1127 | multithread_pixels_function(isi, dh, scaleSection); |
1128 | } |
1129 | |
1130 | static void qt_qimageScaleAARGB_down_xy(QImageScaleInfo *isi, unsigned int *dest, |
1131 | int dw, int dh, int dow, int sow) |
1132 | { |
1133 | const unsigned int **ypoints = isi->ypoints; |
1134 | int *xpoints = isi->xpoints; |
1135 | int *xapoints = isi->xapoints; |
1136 | int *yapoints = isi->yapoints; |
1137 | |
1138 | auto scaleSection = [&] (int yStart, int yEnd) { |
1139 | for (int y = yStart; y < yEnd; ++y) { |
1140 | int Cy = yapoints[y] >> 16; |
1141 | int yap = yapoints[y] & 0xffff; |
1142 | |
1143 | unsigned int *dptr = dest + (y * dow); |
1144 | for (int x = 0; x < dw; x++) { |
1145 | int Cx = xapoints[x] >> 16; |
1146 | int xap = xapoints[x] & 0xffff; |
1147 | |
1148 | const unsigned int *sptr = ypoints[y] + xpoints[x]; |
1149 | int rx, gx, bx; |
1150 | qt_qimageScaleAARGB_helper(pix: sptr, xyap: xap, Cxy: Cx, step: 1, r&: rx, g&: gx, b&: bx); |
1151 | |
1152 | int r = (rx >> 4) * yap; |
1153 | int g = (gx >> 4) * yap; |
1154 | int b = (bx >> 4) * yap; |
1155 | |
1156 | int j; |
1157 | for (j = (1 << 14) - yap; j > Cy; j -= Cy) { |
1158 | sptr += sow; |
1159 | qt_qimageScaleAARGB_helper(pix: sptr, xyap: xap, Cxy: Cx, step: 1, r&: rx, g&: gx, b&: bx); |
1160 | |
1161 | r += (rx >> 4) * Cy; |
1162 | g += (gx >> 4) * Cy; |
1163 | b += (bx >> 4) * Cy; |
1164 | } |
1165 | sptr += sow; |
1166 | qt_qimageScaleAARGB_helper(pix: sptr, xyap: xap, Cxy: Cx, step: 1, r&: rx, g&: gx, b&: bx); |
1167 | |
1168 | r += (rx >> 4) * j; |
1169 | g += (gx >> 4) * j; |
1170 | b += (bx >> 4) * j; |
1171 | |
1172 | *dptr = qRgb(r: r >> 24, g: g >> 24, b: b >> 24); |
1173 | dptr++; |
1174 | } |
1175 | } |
1176 | }; |
1177 | multithread_pixels_function(isi, dh, scaleSection); |
1178 | } |
1179 | |
1180 | QImage qSmoothScaleImage(const QImage &src, int dw, int dh) |
1181 | { |
1182 | QImage buffer; |
1183 | if (src.isNull() || dw <= 0 || dh <= 0) |
1184 | return buffer; |
1185 | |
1186 | int w = src.width(); |
1187 | int h = src.height(); |
1188 | QImageScaleInfo *scaleinfo = |
1189 | qimageCalcScaleInfo(img: src, sw: w, sh: h, dw, dh, aa: true); |
1190 | if (!scaleinfo) |
1191 | return buffer; |
1192 | |
1193 | buffer = QImage(dw, dh, src.format()); |
1194 | if (buffer.isNull()) { |
1195 | qWarning(msg: "QImage: out of memory, returning null"); |
1196 | qimageFreeScaleInfo(isi: scaleinfo); |
1197 | return QImage(); |
1198 | } |
1199 | |
1200 | #if QT_CONFIG(raster_fp) |
1201 | if (qt_fpColorPrecision(format: src.format())) |
1202 | qt_qimageScaleRgbaFP(isi: scaleinfo, dest: (QRgbaFloat32 *)buffer.scanLine(0), |
1203 | dw, dh, dow: dw, sow: src.bytesPerLine() / 16); |
1204 | else |
1205 | #endif |
1206 | #if QT_CONFIG(raster_64bit) |
1207 | if (src.depth() > 32) |
1208 | qt_qimageScaleRgba64(isi: scaleinfo, dest: (QRgba64 *)buffer.scanLine(0), |
1209 | dw, dh, dow: dw, sow: src.bytesPerLine() / 8); |
1210 | else |
1211 | #endif |
1212 | if (src.hasAlphaChannel() || src.format() == QImage::Format_CMYK8888) |
1213 | qt_qimageScaleAARGBA(isi: scaleinfo, dest: (unsigned int *)buffer.scanLine(0), |
1214 | dw, dh, dow: dw, sow: src.bytesPerLine() / 4); |
1215 | else |
1216 | qt_qimageScaleAARGB(isi: scaleinfo, dest: (unsigned int *)buffer.scanLine(0), |
1217 | dw, dh, dow: dw, sow: src.bytesPerLine() / 4); |
1218 | |
1219 | qimageFreeScaleInfo(isi: scaleinfo); |
1220 | return buffer; |
1221 | } |
1222 | |
1223 | QT_END_NAMESPACE |
1224 |
Definitions
- qimageCalcYPoints
- qimageCalcXPoints
- qimageCalcApoints
- qimageFreeScaleInfo
- qimageCalcScaleInfo
- multithread_pixels_function
- qt_qimageScaleAARGBA_up_xy
- qt_qimageScaleAARGBA
- qt_qimageScaleAARGBA_helper
- qt_qimageScaleAARGBA_up_x_down_y
- qt_qimageScaleAARGBA_down_x_up_y
- qt_qimageScaleAARGBA_down_xy
- qt_qimageScaleRgba64_up_xy
- qt_qimageScaleRgba64
- qt_qimageScaleRgba64_helper
- qt_qimageScaleRgba64_up_x_down_y
- qt_qimageScaleRgba64_down_x_up_y
- qt_qimageScaleRgba64_down_xy
- qt_qimageScaleRgbaFP_up_xy
- qt_qimageScaleRgbaFP
- qt_qimageScaleRgbaFP_helper
- qt_qimageScaleRgbaFP_up_x_down_y
- qt_qimageScaleRgbaFP_down_x_up_y
- qt_qimageScaleRgbaFP_down_xy
- qt_qimageScaleAARGB
- qt_qimageScaleAARGB_helper
- qt_qimageScaleAARGB_up_x_down_y
- qt_qimageScaleAARGB_down_x_up_y
- qt_qimageScaleAARGB_down_xy
Learn Advanced QML with KDAB
Find out more