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

source code of qtbase/src/gui/painting/qimagescale.cpp