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
19QT_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
70namespace 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
78using namespace QImageScale;
79
80//
81// Code ported from Imlib...
82//
83
84static 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
114static 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
143static 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
190static 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
202static 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
239static void qt_qimageScaleAARGBA_up_x_down_y(QImageScaleInfo *isi, unsigned int *dest,
240 int dw, int dh, int dow, int sow);
241
242static void qt_qimageScaleAARGBA_down_x_up_y(QImageScaleInfo *isi, unsigned int *dest,
243 int dw, int dh, int dow, int sow);
244
245static 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)
249template<bool RGB>
250void qt_qimageScaleAARGBA_up_x_down_y_sse4(QImageScaleInfo *isi, unsigned int *dest,
251 int dw, int dh, int dow, int sow);
252template<bool RGB>
253void qt_qimageScaleAARGBA_down_x_up_y_sse4(QImageScaleInfo *isi, unsigned int *dest,
254 int dw, int dh, int dow, int sow);
255template<bool RGB>
256void 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__)
261template<bool RGB>
262void qt_qimageScaleAARGBA_up_x_down_y_neon(QImageScaleInfo *isi, unsigned int *dest,
263 int dw, int dh, int dow, int sow);
264template<bool RGB>
265void qt_qimageScaleAARGBA_down_x_up_y_neon(QImageScaleInfo *isi, unsigned int *dest,
266 int dw, int dh, int dow, int sow);
267template<bool RGB>
268void qt_qimageScaleAARGBA_down_xy_neon(QImageScaleInfo *isi, unsigned int *dest,
269 int dw, int dh, int dow, int sow);
270#endif
271
272template<typename T>
273static 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
299static 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 */
341static 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
389inline 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
410static 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
451static 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
493static 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)
546static void qt_qimageScaleRgba64_up_x_down_y(QImageScaleInfo *isi, QRgba64 *dest,
547 int dw, int dh, int dow, int sow);
548
549static void qt_qimageScaleRgba64_down_x_up_y(QImageScaleInfo *isi, QRgba64 *dest,
550 int dw, int dh, int dow, int sow);
551
552static void qt_qimageScaleRgba64_down_xy(QImageScaleInfo *isi, QRgba64 *dest,
553 int dw, int dh, int dow, int sow);
554
555static 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
594void 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
607inline 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
628static 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
668static 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
709static 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)
761static void qt_qimageScaleRgbaFP_up_x_down_y(QImageScaleInfo *isi, QRgbaFloat32 *dest,
762 int dw, int dh, int dow, int sow);
763
764static void qt_qimageScaleRgbaFP_down_x_up_y(QImageScaleInfo *isi, QRgbaFloat32 *dest,
765 int dw, int dh, int dow, int sow);
766
767static void qt_qimageScaleRgbaFP_down_xy(QImageScaleInfo *isi, QRgbaFloat32 *dest,
768 int dw, int dh, int dow, int sow);
769
770static 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
809void 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
822inline 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
847static 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
884static 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
921static 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
975static void qt_qimageScaleAARGB_up_x_down_y(QImageScaleInfo *isi, unsigned int *dest,
976 int dw, int dh, int dow, int sow);
977
978static void qt_qimageScaleAARGB_down_x_up_y(QImageScaleInfo *isi, unsigned int *dest,
979 int dw, int dh, int dow, int sow);
980
981static 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*/
985static 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
1034inline 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
1052static 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
1091static 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
1130static 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
1180QImage 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
1223QT_END_NAMESPACE
1224

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

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