mirror of
https://bitbucket.org/smil3y/katie.git
synced 2025-02-27 04:13:08 +00:00
1034 lines
35 KiB
C++
1034 lines
35 KiB
C++
![]() |
/****************************************************************************
|
||
|
**
|
||
|
** Copyright (C) 2015 The Qt Company Ltd.
|
||
|
** Contact: http://www.qt.io/licensing/
|
||
|
**
|
||
|
** This file is part of the QtGui module of the Qt Toolkit.
|
||
|
**
|
||
|
** $QT_BEGIN_LICENSE:LGPL$
|
||
|
** Commercial License Usage
|
||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||
|
** accordance with the commercial license agreement provided with the
|
||
|
** Software or, alternatively, in accordance with the terms contained in
|
||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||
|
** and conditions see http://www.qt.io/terms-conditions. For further
|
||
|
** information use the contact form at http://www.qt.io/contact-us.
|
||
|
**
|
||
|
** 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 or version 3 as published by the Free
|
||
|
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
||
|
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
||
|
** following information to ensure the GNU Lesser General Public License
|
||
|
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
||
|
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||
|
**
|
||
|
** As a special exception, The Qt Company gives you certain additional
|
||
|
** rights. These rights are described in The Qt Company LGPL Exception
|
||
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||
|
**
|
||
|
** GNU General Public License Usage
|
||
|
** Alternatively, this file may be used under the terms of the GNU
|
||
|
** General Public License version 3.0 as published by the Free Software
|
||
|
** Foundation and appearing in the file LICENSE.GPL included in the
|
||
|
** packaging of this file. Please review the following information to
|
||
|
** ensure the GNU General Public License version 3.0 requirements will be
|
||
|
** met: http://www.gnu.org/copyleft/gpl.html.
|
||
|
**
|
||
|
** $QT_END_LICENSE$
|
||
|
**
|
||
|
****************************************************************************/
|
||
|
#include <qimagescale_p.h>
|
||
|
#include <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 optimize 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
|
||
|
|
||
|
|