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