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