/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <private/qimagescale_p.h>
#include <private/qdrawhelper_p.h>
#include "qimage.h"
#include "qcolor.h"
QT_BEGIN_NAMESPACE
namespace QImageScale {
struct QImageScaleInfo;
}
typedef void (*qt_qimageScaleFunc)(QImageScale::QImageScaleInfo *isi, unsigned int *dest,
int dxx, int dyy, int dx, int dy, int dw,
int dh, int dow, int sow);
static void qt_qimageScaleAARGB(QImageScale::QImageScaleInfo *isi, unsigned int *dest,
int dxx, int dyy, int dx, int dy, int dw,
int dh, int dow, int sow);
static void qt_qimageScaleAARGBA(QImageScale::QImageScaleInfo *isi, unsigned int *dest,
int dxx, int dyy, int dx, int dy, int dw,
int dh, int dow, int sow);
qt_qimageScaleFunc qt_qimageScaleArgb = qt_qimageScaleAARGBA;
qt_qimageScaleFunc qt_qimageScaleRgb = qt_qimageScaleAARGB;
/*
* Copyright (C) 2004, 2005 Daniel M. Duley
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/* OTHER CREDITS:
*
* This is the normal smoothscale method, based on Imlib2's smoothscale.
*
* Originally I took the algorithm used in NetPBM and Qt and added MMX/3dnow
* optimizations. It ran in about 1/2 the time as Qt. Then I ported Imlib's
* C algorithm and it ran at about the same speed as my MMX optimized one...
* Finally I ported Imlib's MMX version and it ran in less than half the
* time as my MMX algorithm, (taking only a quarter of the time Qt does).
* After further optimization it seems to run at around 1/6th.
*
* Changes include formatting, namespaces and other C++'ings, removal of old
* #ifdef'ed code, and removal of unneeded border calculation code.
*
* Imlib2 is (C) Carsten Haitzler and various contributors. The MMX code
* is by Willem Monsuwe <willem@stack.nl>. All other modifications are
* (C) Daniel M. Duley.
*/
namespace QImageScale {
struct QImageScaleInfo {
int *xpoints;
unsigned int **ypoints;
int *xapoints, *yapoints;
int xup_yup;
};
unsigned int** qimageCalcYPoints(unsigned int *src, int sw, int sh,
int dh);
int* qimageCalcXPoints(int sw, int dw);
int* qimageCalcApoints(int s, int d, int up);
QImageScaleInfo* qimageFreeScaleInfo(QImageScaleInfo *isi);
QImageScaleInfo *qimageCalcScaleInfo(const QImage &img, int sw, int sh,
int dw, int dh, char aa);
}
using namespace QImageScale;
//
// Code ported from Imlib...
//
// FIXME: replace with qRed, etc... These work on pointers to pixels, not
// pixel values
#define A_VAL(p) (qAlpha(*p))
#define R_VAL(p) (qRed(*p))
#define G_VAL(p) (qGreen(*p))
#define B_VAL(p) (qBlue(*p))
#define INV_XAP (256 - xapoints[x])
#define XAP (xapoints[x])
#define INV_YAP (256 - yapoints[dyy + y])
#define YAP (yapoints[dyy + y])
unsigned int** QImageScale::qimageCalcYPoints(unsigned int *src,
int sw, int sh, int dh)
{
unsigned int **p;
int i, j = 0;
int val, inc, rv = 0;
if(dh < 0){
dh = -dh;
rv = 1;
}
p = new unsigned int* [dh+1];
int up = qAbs(dh) >= sh;
val = up ? 0x8000 * sh / dh - 0x8000 : 0;
inc = (sh << 16) / dh;
for(i = 0; i < dh; i++){
p[j++] = src + qMax(0, val >> 16) * sw;
val += inc;
}
if(rv){
for(i = dh / 2; --i >= 0; ){
unsigned int *tmp = p[i];
p[i] = p[dh - i - 1];
p[dh - i - 1] = tmp;
}
}
return(p);
}
int* QImageScale::qimageCalcXPoints(int sw, int dw)
{
int *p, i, j = 0;
int val, inc, rv = 0;
if(dw < 0){
dw = -dw;
rv = 1;
}
p = new int[dw+1];
int up = qAbs(dw) >= sw;
val = up ? 0x8000 * sw / dw - 0x8000 : 0;
inc = (sw << 16) / dw;
for(i = 0; i < dw; i++){
p[j++] = qMax(0, val >> 16);
val += inc;
}
if(rv){
for(i = dw / 2; --i >= 0; ){
int tmp = p[i];
p[i] = p[dw - i - 1];
p[dw - i - 1] = tmp;
}
}
return(p);
}
int* QImageScale::qimageCalcApoints(int s, int d, int up)
{
int *p, i, j = 0, rv = 0;
if(d < 0){
rv = 1;
d = -d;
}
p = new int[d];
/* scaling up */
if(up){
int val, inc;
val = 0x8000 * s / d - 0x8000;
inc = (s << 16) / d;
for(i = 0; i < d; i++){
int pos = val >> 16;
if (pos < 0)
p[j++] = 0;
else if (pos >= (s - 1))
p[j++] = 0;
else
p[j++] = (val >> 8) - ((val >> 8) & 0xffffff00);
val += inc;
}
}
/* scaling down */
else{
int val, inc, ap, Cp;
val = 0;
inc = (s << 16) / d;
Cp = ((d << 14) / s) + 1;
for(i = 0; i < d; i++){
ap = ((0x100 - ((val >> 8) & 0xff)) * Cp) >> 8;
p[j] = ap | (Cp << 16);
j++;
val += inc;
}
}
if(rv){
int tmp;
for(i = d / 2; --i >= 0; ){
tmp = p[i];
p[i] = p[d - i - 1];
p[d - i - 1] = tmp;
}
}
return(p);
}
QImageScaleInfo* QImageScale::qimageFreeScaleInfo(QImageScaleInfo *isi)
{
if(isi){
delete[] isi->xpoints;
delete[] isi->ypoints;
delete[] isi->xapoints;
delete[] isi->yapoints;
delete isi;
}
return 0;
}
QImageScaleInfo* QImageScale::qimageCalcScaleInfo(const QImage &img,
int sw, int sh,
int dw, int dh, char aa)
{
QImageScaleInfo *isi;
int scw, sch;
scw = dw * qlonglong(img.width()) / sw;
sch = dh * qlonglong(img.height()) / sh;
isi = new QImageScaleInfo;
if(!isi)
return 0;
memset(isi, 0, sizeof(QImageScaleInfo));
isi->xup_yup = (qAbs(dw) >= sw) + ((qAbs(dh) >= sh) << 1);
isi->xpoints = qimageCalcXPoints(img.width(), scw);
if(!isi->xpoints)
return(qimageFreeScaleInfo(isi));
isi->ypoints = qimageCalcYPoints((unsigned int *)img.scanLine(0),
img.bytesPerLine() / 4, img.height(), sch);
if (!isi->ypoints)
return(qimageFreeScaleInfo(isi));
if(aa) {
isi->xapoints = qimageCalcApoints(img.width(), scw, isi->xup_yup & 1);
if(!isi->xapoints)
return(qimageFreeScaleInfo(isi));
isi->yapoints = qimageCalcApoints(img.height(), sch, isi->xup_yup & 2);
if(!isi->yapoints)
return(qimageFreeScaleInfo(isi));
}
return(isi);
}
/* FIXME: NEED to optimise ScaleAARGBA - currently its "ok" but needs work*/
/* scale by area sampling */
static void qt_qimageScaleAARGBA(QImageScaleInfo *isi, unsigned int *dest,
int dxx, int dyy, int dx, int dy, int dw,
int dh, int dow, int sow)
{
unsigned int *sptr, *dptr;
int x, y, end;
unsigned int **ypoints = isi->ypoints;
int *xpoints = isi->xpoints;
int *xapoints = isi->xapoints;
int *yapoints = isi->yapoints;
end = dxx + dw;
/* scaling up both ways */
if(isi->xup_yup == 3){
/* go through every scanline in the output buffer */
for(y = 0; y < dh; y++){
/* calculate the source line we'll scan from */
dptr = dest + dx + ((y + dy) * dow);
sptr = ypoints[dyy + y];
if(YAP > 0){
for(x = dxx; x < end; x++){
int r, g, b, a;
int rr, gg, bb, aa;
unsigned int *pix;
if(XAP > 0){
pix = ypoints[dyy + y] + xpoints[x];
r = R_VAL(pix) * INV_XAP;
g = G_VAL(pix) * INV_XAP;
b = B_VAL(pix) * INV_XAP;
a = A_VAL(pix) * INV_XAP;
pix++;
r += R_VAL(pix) * XAP;
g += G_VAL(pix) * XAP;
b += B_VAL(pix) * XAP;
a += A_VAL(pix) * XAP;
pix += sow;
rr = R_VAL(pix) * XAP;
gg = G_VAL(pix) * XAP;
bb = B_VAL(pix) * XAP;
aa = A_VAL(pix) * XAP;
pix--;
rr += R_VAL(pix) * INV_XAP;
gg += G_VAL(pix) * INV_XAP;
bb += B_VAL(pix) * INV_XAP;
aa += A_VAL(pix) * INV_XAP;
r = ((rr * YAP) + (r * INV_YAP)) >> 16;
g = ((gg * YAP) + (g * INV_YAP)) >> 16;
b = ((bb * YAP) + (b * INV_YAP)) >> 16;
a = ((aa * YAP) + (a * INV_YAP)) >> 16;
*dptr++ = qRgba(r, g, b, a);
}
else{
pix = ypoints[dyy + y] + xpoints[x];
r = R_VAL(pix) * INV_YAP;
g = G_VAL(pix) * INV_YAP;
b = B_VAL(pix) * INV_YAP;
a = A_VAL(pix) * INV_YAP;
pix += sow;
r += R_VAL(pix) * YAP;
g += G_VAL(pix) * YAP;
b += B_VAL(pix) * YAP;
a += A_VAL(pix) * YAP;
r >>= 8;
g >>= 8;
b >>= 8;
a >>= 8;
*dptr++ = qRgba(r, g, b, a);
}
}
}
else{
for(x = dxx; x < end; x++){
int r, g, b, a;
unsigned int *pix;
if(XAP > 0){
pix = ypoints[dyy + y] + xpoints[x];
r = R_VAL(pix) * INV_XAP;
g = G_VAL(pix) * INV_XAP;
b = B_VAL(pix) * INV_XAP;
a = A_VAL(pix) * INV_XAP;
pix++;
r += R_VAL(pix) * XAP;
g += G_VAL(pix) * XAP;
b += B_VAL(pix) * XAP;
a += A_VAL(pix) * XAP;
r >>= 8;
g >>= 8;
b >>= 8;
a >>= 8;
*dptr++ = qRgba(r, g, b, a);
}
else
*dptr++ = sptr[xpoints[x] ];
}
}
}
}
/* if we're scaling down vertically */
else if(isi->xup_yup == 1){
/*\ 'Correct' version, with math units prepared for MMXification \*/
int Cy, j;
unsigned int *pix;
int r, g, b, a, rr, gg, bb, aa;
int yap;
/* go through every scanline in the output buffer */
for(y = 0; y < dh; y++){
Cy = YAP >> 16;
yap = YAP & 0xffff;
dptr = dest + dx + ((y + dy) * dow);
for(x = dxx; x < end; x++){
pix = ypoints[dyy + y] + xpoints[x];
r = R_VAL(pix) * yap;
g = G_VAL(pix) * yap;
b = B_VAL(pix) * yap;
a = A_VAL(pix) * yap;
for(j = (1 << 14) - yap; j > Cy; j -= Cy){
pix += sow;
r += R_VAL(pix) * Cy;
g += G_VAL(pix) * Cy;
b += B_VAL(pix) * Cy;
a += A_VAL(pix) * Cy;
}
if(j > 0){
pix += sow;
r += R_VAL(pix) * j;
g += G_VAL(pix) * j;
b += B_VAL(pix) * j;
a += A_VAL(pix) * j;
}
if(XAP > 0){
pix = ypoints[dyy + y] + xpoints[x] + 1;
rr = R_VAL(pix) * yap;
gg = G_VAL(pix) * yap;
bb = B_VAL(pix) * yap;
aa = A_VAL(pix) * yap;
for(j = (1 << 14) - yap; j > Cy; j -= Cy){
pix += sow;
rr += R_VAL(pix) * Cy;
gg += G_VAL(pix) * Cy;
bb += B_VAL(pix) * Cy;
aa += A_VAL(pix) * Cy;
}
if(j > 0){
pix += sow;
rr += R_VAL(pix) * j;
gg += G_VAL(pix) * j;
bb += B_VAL(pix) * j;
aa += A_VAL(pix) * j;
}
r = r * INV_XAP;
g = g * INV_XAP;
b = b * INV_XAP;
a = a * INV_XAP;
r = (r + ((rr * XAP))) >> 12;
g = (g + ((gg * XAP))) >> 12;
b = (b + ((bb * XAP))) >> 12;
a = (a + ((aa * XAP))) >> 12;
}
else{
r >>= 4;
g >>= 4;
b >>= 4;
a >>= 4;
}
*dptr = qRgba(r >> 10, g >> 10, b >> 10, a >> 10);
dptr++;
}
}
}
/* if we're scaling down horizontally */
else if(isi->xup_yup == 2){
/*\ 'Correct' version, with math units prepared for MMXification \*/
int Cx, j;
unsigned int *pix;
int r, g, b, a, rr, gg, bb, aa;
int xap;
/* go through every scanline in the output buffer */
for(y = 0; y < dh; y++){
dptr = dest + dx + ((y + dy) * dow);
for(x = dxx; x < end; x++){
Cx = XAP >> 16;
xap = XAP & 0xffff;
pix = ypoints[dyy + y] + xpoints[x];
r = R_VAL(pix) * xap;
g = G_VAL(pix) * xap;
b = B_VAL(pix) * xap;
a = A_VAL(pix) * xap;
for(j = (1 << 14) - xap; j > Cx; j -= Cx){
pix++;
r += R_VAL(pix) * Cx;
g += G_VAL(pix) * Cx;
b += B_VAL(pix) * Cx;
a += A_VAL(pix) * Cx;
}
if(j > 0){
pix++;
r += R_VAL(pix) * j;
g += G_VAL(pix) * j;
b += B_VAL(pix) * j;
a += A_VAL(pix) * j;
}
if(YAP > 0){
pix = ypoints[dyy + y] + xpoints[x] + sow;
rr = R_VAL(pix) * xap;
gg = G_VAL(pix) * xap;
bb = B_VAL(pix) * xap;
aa = A_VAL(pix) * xap;
for(j = (1 << 14) - xap; j > Cx; j -= Cx){
pix++;
rr += R_VAL(pix) * Cx;
gg += G_VAL(pix) * Cx;
bb += B_VAL(pix) * Cx;
aa += A_VAL(pix) * Cx;
}
if(j > 0){
pix++;
rr += R_VAL(pix) * j;
gg += G_VAL(pix) * j;
bb += B_VAL(pix) * j;
aa += A_VAL(pix) * j;
}
r = r * INV_YAP;
g = g * INV_YAP;
b = b * INV_YAP;
a = a * INV_YAP;
r = (r + ((rr * YAP))) >> 12;
g = (g + ((gg * YAP))) >> 12;
b = (b + ((bb * YAP))) >> 12;
a = (a + ((aa * YAP))) >> 12;
}
else{
r >>= 4;
g >>= 4;
b >>= 4;
a >>= 4;
}
*dptr = qRgba(r >> 10, g >> 10, b >> 10, a >> 10);
dptr++;
}
}
}
/* if we're scaling down horizontally & vertically */
else{
/*\ 'Correct' version, with math units prepared for MMXification:
|*| The operation 'b = (b * c) >> 16' translates to pmulhw,
|*| so the operation 'b = (b * c) >> d' would translate to
|*| psllw (16 - d), %mmb; pmulh %mmc, %mmb
\*/
int Cx, Cy, i, j;
unsigned int *pix;
int a, r, g, b, ax, rx, gx, bx;
int xap, yap;
for(y = 0; y < dh; y++){
Cy = YAP >> 16;
yap = YAP & 0xffff;
dptr = dest + dx + ((y + dy) * dow);
for(x = dxx; x < end; x++){
Cx = XAP >> 16;
xap = XAP & 0xffff;
sptr = ypoints[dyy + y] + xpoints[x];
pix = sptr;
sptr += sow;
rx = R_VAL(pix) * xap;
gx = G_VAL(pix) * xap;
bx = B_VAL(pix) * xap;
ax = A_VAL(pix) * xap;
pix++;
for(i = (1 << 14) - xap; i > Cx; i -= Cx){
rx += R_VAL(pix) * Cx;
gx += G_VAL(pix) * Cx;
bx += B_VAL(pix) * Cx;
ax += A_VAL(pix) * Cx;
pix++;
}
if(i > 0){
rx += R_VAL(pix) * i;
gx += G_VAL(pix) * i;
bx += B_VAL(pix) * i;
ax += A_VAL(pix) * i;
}
r = (rx >> 5) * yap;
g = (gx >> 5) * yap;
b = (bx >> 5) * yap;
a = (ax >> 5) * yap;
for(j = (1 << 14) - yap; j > Cy; j -= Cy){
pix = sptr;
sptr += sow;
rx = R_VAL(pix) * xap;
gx = G_VAL(pix) * xap;
bx = B_VAL(pix) * xap;
ax = A_VAL(pix) * xap;
pix++;
for(i = (1 << 14) - xap; i > Cx; i -= Cx){
rx += R_VAL(pix) * Cx;
gx += G_VAL(pix) * Cx;
bx += B_VAL(pix) * Cx;
ax += A_VAL(pix) * Cx;
pix++;
}
if(i > 0){
rx += R_VAL(pix) * i;
gx += G_VAL(pix) * i;
bx += B_VAL(pix) * i;
ax += A_VAL(pix) * i;
}
r += (rx >> 5) * Cy;
g += (gx >> 5) * Cy;
b += (bx >> 5) * Cy;
a += (ax >> 5) * Cy;
}
if(j > 0){
pix = sptr;
sptr += sow;
rx = R_VAL(pix) * xap;
gx = G_VAL(pix) * xap;
bx = B_VAL(pix) * xap;
ax = A_VAL(pix) * xap;
pix++;
for(i = (1 << 14) - xap; i > Cx; i -= Cx){
rx += R_VAL(pix) * Cx;
gx += G_VAL(pix) * Cx;
bx += B_VAL(pix) * Cx;
ax += A_VAL(pix) * Cx;
pix++;
}
if(i > 0){
rx += R_VAL(pix) * i;
gx += G_VAL(pix) * i;
bx += B_VAL(pix) * i;
ax += A_VAL(pix) * i;
}
r += (rx >> 5) * j;
g += (gx >> 5) * j;
b += (bx >> 5) * j;
a += (ax >> 5) * j;
}
*dptr = qRgba(r >> 23, g >> 23, b >> 23, a >> 23);
dptr++;
}
}
}
}
/* scale by area sampling - IGNORE the ALPHA byte*/
static void qt_qimageScaleAARGB(QImageScaleInfo *isi, unsigned int *dest,
int dxx, int dyy, int dx, int dy, int dw,
int dh, int dow, int sow)
{
unsigned int *sptr, *dptr;
int x, y, end;
unsigned int **ypoints = isi->ypoints;
int *xpoints = isi->xpoints;
int *xapoints = isi->xapoints;
int *yapoints = isi->yapoints;
end = dxx + dw;
/* scaling up both ways */
if(isi->xup_yup == 3){
/* go through every scanline in the output buffer */
for(y = 0; y < dh; y++){
/* calculate the source line we'll scan from */
dptr = dest + dx + ((y + dy) * dow);
sptr = ypoints[dyy + y];
if(YAP > 0){
for(x = dxx; x < end; x++){
int r = 0, g = 0, b = 0;
int rr = 0, gg = 0, bb = 0;
unsigned int *pix;
if(XAP > 0){
pix = ypoints[dyy + y] + xpoints[x];
r = R_VAL(pix) * INV_XAP;
g = G_VAL(pix) * INV_XAP;
b = B_VAL(pix) * INV_XAP;
pix++;
r += R_VAL(pix) * XAP;
g += G_VAL(pix) * XAP;
b += B_VAL(pix) * XAP;
pix += sow;
rr = R_VAL(pix) * XAP;
gg = G_VAL(pix) * XAP;
bb = B_VAL(pix) * XAP;
pix --;
rr += R_VAL(pix) * INV_XAP;
gg += G_VAL(pix) * INV_XAP;
bb += B_VAL(pix) * INV_XAP;
r = ((rr * YAP) + (r * INV_YAP)) >> 16;
g = ((gg * YAP) + (g * INV_YAP)) >> 16;
b = ((bb * YAP) + (b * INV_YAP)) >> 16;
*dptr++ = qRgba(r, g, b, 0xff);
}
else{
pix = ypoints[dyy + y] + xpoints[x];
r = R_VAL(pix) * INV_YAP;
g = G_VAL(pix) * INV_YAP;
b = B_VAL(pix) * INV_YAP;
pix += sow;
r += R_VAL(pix) * YAP;
g += G_VAL(pix) * YAP;
b += B_VAL(pix) * YAP;
r >>= 8;
g >>= 8;
b >>= 8;
*dptr++ = qRgba(r, g, b, 0xff);
}
}
}
else{
for(x = dxx; x < end; x++){
int r = 0, g = 0, b = 0;
unsigned int *pix;
if(XAP > 0){
pix = ypoints[dyy + y] + xpoints[x];
r = R_VAL(pix) * INV_XAP;
g = G_VAL(pix) * INV_XAP;
b = B_VAL(pix) * INV_XAP;
pix++;
r += R_VAL(pix) * XAP;
g += G_VAL(pix) * XAP;
b += B_VAL(pix) * XAP;
r >>= 8;
g >>= 8;
b >>= 8;
*dptr++ = qRgba(r, g, b, 0xff);
}
else
*dptr++ = sptr[xpoints[x] ];
}
}
}
}
/* if we're scaling down vertically */
else if(isi->xup_yup == 1){
/*\ 'Correct' version, with math units prepared for MMXification \*/
int Cy, j;
unsigned int *pix;
int r, g, b, rr, gg, bb;
int yap;
/* go through every scanline in the output buffer */
for(y = 0; y < dh; y++){
Cy = YAP >> 16;
yap = YAP & 0xffff;
dptr = dest + dx + ((y + dy) * dow);
for(x = dxx; x < end; x++){
pix = ypoints[dyy + y] + xpoints[x];
r = R_VAL(pix) * yap;
g = G_VAL(pix) * yap;
b = B_VAL(pix) * yap;
pix += sow;
for(j = (1 << 14) - yap; j > Cy; j -= Cy){
r += R_VAL(pix) * Cy;
g += G_VAL(pix) * Cy;
b += B_VAL(pix) * Cy;
pix += sow;
}
if(j > 0){
r += R_VAL(pix) * j;
g += G_VAL(pix) * j;
b += B_VAL(pix) * j;
}
if(XAP > 0){
pix = ypoints[dyy + y] + xpoints[x] + 1;
rr = R_VAL(pix) * yap;
gg = G_VAL(pix) * yap;
bb = B_VAL(pix) * yap;
pix += sow;
for(j = (1 << 14) - yap; j > Cy; j -= Cy){
rr += R_VAL(pix) * Cy;
gg += G_VAL(pix) * Cy;
bb += B_VAL(pix) * Cy;
pix += sow;
}
if(j > 0){
rr += R_VAL(pix) * j;
gg += G_VAL(pix) * j;
bb += B_VAL(pix) * j;
}
r = r * INV_XAP;
g = g * INV_XAP;
b = b * INV_XAP;
r = (r + ((rr * XAP))) >> 12;
g = (g + ((gg * XAP))) >> 12;
b = (b + ((bb * XAP))) >> 12;
}
else{
r >>= 4;
g >>= 4;
b >>= 4;
}
*dptr = qRgba(r >> 10, g >> 10, b >> 10, 0xff);
dptr++;
}
}
}
/* if we're scaling down horizontally */
else if(isi->xup_yup == 2){
/*\ 'Correct' version, with math units prepared for MMXification \*/
int Cx, j;
unsigned int *pix;
int r, g, b, rr, gg, bb;
int xap;
/* go through every scanline in the output buffer */
for(y = 0; y < dh; y++){
dptr = dest + dx + ((y + dy) * dow);
for(x = dxx; x < end; x++){
Cx = XAP >> 16;
xap = XAP & 0xffff;
pix = ypoints[dyy + y] + xpoints[x];
r = R_VAL(pix) * xap;
g = G_VAL(pix) * xap;
b = B_VAL(pix) * xap;
pix++;
for(j = (1 << 14) - xap; j > Cx; j -= Cx){
r += R_VAL(pix) * Cx;
g += G_VAL(pix) * Cx;
b += B_VAL(pix) * Cx;
pix++;
}
if(j > 0){
r += R_VAL(pix) * j;
g += G_VAL(pix) * j;
b += B_VAL(pix) * j;
}
if(YAP > 0){
pix = ypoints[dyy + y] + xpoints[x] + sow;
rr = R_VAL(pix) * xap;
gg = G_VAL(pix) * xap;
bb = B_VAL(pix) * xap;
pix++;
for(j = (1 << 14) - xap; j > Cx; j -= Cx){
rr += R_VAL(pix) * Cx;
gg += G_VAL(pix) * Cx;
bb += B_VAL(pix) * Cx;
pix++;
}
if(j > 0){
rr += R_VAL(pix) * j;
gg += G_VAL(pix) * j;
bb += B_VAL(pix) * j;
}
r = r * INV_YAP;
g = g * INV_YAP;
b = b * INV_YAP;
r = (r + ((rr * YAP))) >> 12;
g = (g + ((gg * YAP))) >> 12;
b = (b + ((bb * YAP))) >> 12;
}
else{
r >>= 4;
g >>= 4;
b >>= 4;
}
*dptr = qRgba(r >> 10, g >> 10, b >> 10, 0xff);
dptr++;
}
}
}
/* fully optimized (i think) - onyl change of algorithm can help */
/* if we're scaling down horizontally & vertically */
else{
/*\ 'Correct' version, with math units prepared for MMXification \*/
int Cx, Cy, i, j;
unsigned int *pix;
int r, g, b, rx, gx, bx;
int xap, yap;
for(y = 0; y < dh; y++){
Cy = YAP >> 16;
yap = YAP & 0xffff;
dptr = dest + dx + ((y + dy) * dow);
for(x = dxx; x < end; x++){
Cx = XAP >> 16;
xap = XAP & 0xffff;
sptr = ypoints[dyy + y] + xpoints[x];
pix = sptr;
sptr += sow;
rx = R_VAL(pix) * xap;
gx = G_VAL(pix) * xap;
bx = B_VAL(pix) * xap;
pix++;
for(i = (1 << 14) - xap; i > Cx; i -= Cx){
rx += R_VAL(pix) * Cx;
gx += G_VAL(pix) * Cx;
bx += B_VAL(pix) * Cx;
pix++;
}
if(i > 0){
rx += R_VAL(pix) * i;
gx += G_VAL(pix) * i;
bx += B_VAL(pix) * i;
}
r = (rx >> 5) * yap;
g = (gx >> 5) * yap;
b = (bx >> 5) * yap;
for(j = (1 << 14) - yap; j > Cy; j -= Cy){
pix = sptr;
sptr += sow;
rx = R_VAL(pix) * xap;
gx = G_VAL(pix) * xap;
bx = B_VAL(pix) * xap;
pix++;
for(i = (1 << 14) - xap; i > Cx; i -= Cx){
rx += R_VAL(pix) * Cx;
gx += G_VAL(pix) * Cx;
bx += B_VAL(pix) * Cx;
pix++;
}
if(i > 0){
rx += R_VAL(pix) * i;
gx += G_VAL(pix) * i;
bx += B_VAL(pix) * i;
}
r += (rx >> 5) * Cy;
g += (gx >> 5) * Cy;
b += (bx >> 5) * Cy;
}
if(j > 0){
pix = sptr;
sptr += sow;
rx = R_VAL(pix) * xap;
gx = G_VAL(pix) * xap;
bx = B_VAL(pix) * xap;
pix++;
for(i = (1 << 14) - xap; i > Cx; i -= Cx){
rx += R_VAL(pix) * Cx;
gx += G_VAL(pix) * Cx;
bx += B_VAL(pix) * Cx;
pix++;
}
if(i > 0){
rx += R_VAL(pix) * i;
gx += G_VAL(pix) * i;
bx += B_VAL(pix) * i;
}
r += (rx >> 5) * j;
g += (gx >> 5) * j;
b += (bx >> 5) * j;
}
*dptr = qRgb(r >> 23, g >> 23, b >> 23);
dptr++;
}
}
}
}
#if 0
static void qt_qimageScaleAARGBASetup(QImageScaleInfo *isi, unsigned int *dest,
int dxx, int dyy, int dx, int dy, int dw,
int dh, int dow, int sow)
{
qInitDrawhelperAsm();
qt_qimageScaleAARGBA(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow);
}
static void qt_qimageScaleAARGBSetup(QImageScaleInfo *isi, unsigned int *dest,
int dxx, int dyy, int dx, int dy, int dw,
int dh, int dow, int sow)
{
qInitDrawhelperAsm();
qt_qimageScaleAARGB(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow);
}
#endif
QImage qSmoothScaleImage(const QImage &src, int dw, int dh)
{
QImage buffer;
if (src.isNull() || dw <= 0 || dh <= 0)
return buffer;
int w = src.width();
int h = src.height();
QImageScaleInfo *scaleinfo =
qimageCalcScaleInfo(src, w, h, dw, dh, true);
if (!scaleinfo)
return buffer;
buffer = QImage(dw, dh, src.format());
if (buffer.isNull()) {
qWarning("QImage: out of memory, returning null");
qimageFreeScaleInfo(scaleinfo);
return QImage();
}
if (src.format() == QImage::Format_ARGB32_Premultiplied)
qt_qimageScaleArgb(scaleinfo, (unsigned int *)buffer.scanLine(0),
0, 0, 0, 0, dw, dh, dw, src.bytesPerLine() / 4);
else
qt_qimageScaleRgb(scaleinfo, (unsigned int *)buffer.scanLine(0),
0, 0, 0, 0, dw, dh, dw, src.bytesPerLine() / 4);
qimageFreeScaleInfo(scaleinfo);
return buffer;
}
QT_END_NAMESPACE