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