You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdenetwork/krdc/vnc/scaling.cpp

332 lines
9.5 KiB

/****************************************************************************
**
** Copyright (C) 2015 Timothy Pearson <kb9vqf@pearsoncomputing.net>
**
** This file is part of TDE.
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; see the file COPYING. If not, write to
** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
** Boston, MA 02110-1301, USA.
**
****************************************************************************/
#include <tqimage.h>
/*!
Smooth scaling function with ability to limit scaled region
The selection rectangle is given in terms of destination coordinates
It leaves areas outside of the selection rectangle undefined...
Function code originally taken from qimage.cpp pnmscale () and modified
to only scale a section of the source
This function uses code based on pnmscale.c by Jef Poskanzer.
pnmscale.c - read a portable anymap and scale it
\legalese
Copyright (C) 1989, 1991 by Jef Poskanzer.
Permission to use, copy, modify, and distribute this software and
its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice appear in all
copies and that both that copyright notice and this permission
notice appear in supporting documentation. This software is
provided "as is" without express or implied warranty.
*/
void pnmscale_fractional(const TQImage& src, TQImage& dst, int x, int y, int w, int h)
{
TQRgb* xelrow = 0;
TQRgb* tempxelrow = 0;
TQRgb* xP;
TQRgb* nxP;
int rows, cols, rowsread, newrows, newcols;
int row, col, needtoreadrow;
const uchar maxval = 255;
double xscale, yscale;
long sxscale, syscale;
long fracrowtofill, fracrowleft;
long* as;
long* rs;
long* gs;
long* bs;
int rowswritten = 0;
int colswritten = 0;
cols = src.width();
rows = src.height();
newcols = dst.width();
newrows = dst.height();
long SCALE;
long HALFSCALE;
if (cols > 4096)
{
SCALE = 4096;
HALFSCALE = 2048;
}
else
{
int fac = 4096;
while (cols * fac > 4096)
{
fac /= 2;
}
SCALE = fac * cols;
HALFSCALE = fac * cols / 2;
}
xscale = (double) newcols / (double) cols;
yscale = (double) newrows / (double) rows;
sxscale = (long)(xscale * SCALE);
syscale = (long)(yscale * SCALE);
if ( newrows != rows ) /* shortcut Y scaling if possible */
tempxelrow = new TQRgb[cols];
if ( src.hasAlphaBuffer() ) {
dst.setAlphaBuffer(TRUE);
as = new long[cols];
for ( col = 0; col < cols; ++col )
as[col] = HALFSCALE;
} else {
as = 0;
}
rs = new long[cols];
gs = new long[cols];
bs = new long[cols];
rowsread = 0;
fracrowleft = syscale;
needtoreadrow = 1;
for ( col = 0; col < cols; ++col )
rs[col] = gs[col] = bs[col] = HALFSCALE;
fracrowtofill = SCALE;
for ( row = 0; row < newrows; ++row ) {
/* First scale Y from xelrow into tempxelrow. */
if ( newrows == rows ) {
/* shortcut Y scaling if possible */
tempxelrow = xelrow = (TQRgb*)src.scanLine(rowsread++);
} else {
while ( fracrowleft < fracrowtofill ) {
if ( needtoreadrow && rowsread < rows )
xelrow = (TQRgb*)src.scanLine(rowsread++);
for ( col = 0, xP = xelrow; col < cols; ++col, ++xP ) {
if ((rowswritten >= y) && (rowswritten <= (y + h))) {
if (as) {
as[col] += fracrowleft * tqAlpha( *xP );
rs[col] += fracrowleft * tqRed( *xP ) * tqAlpha( *xP ) / 255;
gs[col] += fracrowleft * tqGreen( *xP ) * tqAlpha( *xP ) / 255;
bs[col] += fracrowleft * tqBlue( *xP ) * tqAlpha( *xP ) / 255;
} else {
rs[col] += fracrowleft * tqRed( *xP );
gs[col] += fracrowleft * tqGreen( *xP );
bs[col] += fracrowleft * tqBlue( *xP );
}
}
}
fracrowtofill -= fracrowleft;
fracrowleft = syscale;
needtoreadrow = 1;
}
/* Now fracrowleft is >= fracrowtofill, so we can produce a row. */
if ( needtoreadrow && rowsread < rows ) {
xelrow = (TQRgb*)src.scanLine(rowsread++);
needtoreadrow = 0;
}
long a=0;
for ( col = 0, xP = xelrow, nxP = tempxelrow, colswritten = 0;
col < cols; ++col, ++xP, ++nxP, ++colswritten )
{
if ((rowswritten >= y) && (rowswritten <= (y + h))) {
long r, g, b;
if ( as ) {
r = rs[col] + fracrowtofill * tqRed( *xP ) * tqAlpha( *xP ) / 255;
g = gs[col] + fracrowtofill * tqGreen( *xP ) * tqAlpha( *xP ) / 255;
b = bs[col] + fracrowtofill * tqBlue( *xP ) * tqAlpha( *xP ) / 255;
a = as[col] + fracrowtofill * tqAlpha( *xP );
if ( a ) {
r = r * 255 / a * SCALE;
g = g * 255 / a * SCALE;
b = b * 255 / a * SCALE;
}
} else {
r = rs[col] + fracrowtofill * tqRed( *xP );
g = gs[col] + fracrowtofill * tqGreen( *xP );
b = bs[col] + fracrowtofill * tqBlue( *xP );
}
r /= SCALE;
if ( r > maxval ) r = maxval;
g /= SCALE;
if ( g > maxval ) g = maxval;
b /= SCALE;
if ( b > maxval ) b = maxval;
if ( as ) {
a /= SCALE;
if ( a > maxval ) a = maxval;
*nxP = tqRgba( (int)r, (int)g, (int)b, (int)a );
as[col] = HALFSCALE;
} else {
*nxP = tqRgb( (int)r, (int)g, (int)b );
}
rs[col] = gs[col] = bs[col] = HALFSCALE;
}
}
fracrowleft -= fracrowtofill;
if ( fracrowleft == 0 ) {
fracrowleft = syscale;
needtoreadrow = 1;
}
fracrowtofill = SCALE;
}
/* Now scale X from tempxelrow into dst and write it out. */
if ( newcols == cols ) {
/* shortcut X scaling if possible */
memcpy(dst.scanLine(rowswritten++), tempxelrow, newcols*4);
} else {
long a, r, g, b;
long fraccoltofill, fraccolleft = 0;
int needcol;
nxP = (TQRgb*)dst.scanLine(rowswritten++);
colswritten = 0;
fraccoltofill = SCALE;
a = r = g = b = HALFSCALE;
needcol = 0;
for ( col = 0, xP = tempxelrow; col < cols; ++col, ++xP ) {
fraccolleft = sxscale;
while ( fraccolleft >= fraccoltofill ) {
if ( needcol ) {
++nxP;
++colswritten;
a = r = g = b = HALFSCALE;
}
if ((colswritten >= x) && (colswritten <= (x + w)) && (rowswritten >= y) && (rowswritten <= (y + h))) {
if ( as ) {
r += fraccoltofill * tqRed( *xP ) * tqAlpha( *xP ) / 255;
g += fraccoltofill * tqGreen( *xP ) * tqAlpha( *xP ) / 255;
b += fraccoltofill * tqBlue( *xP ) * tqAlpha( *xP ) / 255;
a += fraccoltofill * tqAlpha( *xP );
if ( a ) {
r = r * 255 / a * SCALE;
g = g * 255 / a * SCALE;
b = b * 255 / a * SCALE;
}
} else {
r += fraccoltofill * tqRed( *xP );
g += fraccoltofill * tqGreen( *xP );
b += fraccoltofill * tqBlue( *xP );
}
r /= SCALE;
if ( r > maxval ) r = maxval;
g /= SCALE;
if ( g > maxval ) g = maxval;
b /= SCALE;
if ( b > maxval ) b = maxval;
if (as) {
a /= SCALE;
if ( a > maxval ) a = maxval;
*nxP = tqRgba( (int)r, (int)g, (int)b, (int)a );
} else {
*nxP = tqRgb( (int)r, (int)g, (int)b );
}
}
fraccolleft -= fraccoltofill;
fraccoltofill = SCALE;
needcol = 1;
}
if ( fraccolleft > 0 ) {
if ( needcol ) {
++nxP;
++colswritten;
a = r = g = b = HALFSCALE;
needcol = 0;
}
if ((rowswritten >= y) && (rowswritten <= (y + h))) {
if (as) {
a += fraccolleft * tqAlpha( *xP );
r += fraccolleft * tqRed( *xP ) * tqAlpha( *xP ) / 255;
g += fraccolleft * tqGreen( *xP ) * tqAlpha( *xP ) / 255;
b += fraccolleft * tqBlue( *xP ) * tqAlpha( *xP ) / 255;
} else {
r += fraccolleft * tqRed( *xP );
g += fraccolleft * tqGreen( *xP );
b += fraccolleft * tqBlue( *xP );
}
}
fraccoltofill -= fraccolleft;
}
}
if ( fraccoltofill > 0 ) {
--xP;
if ((rowswritten >= y) && (rowswritten <= (y + h))) {
if (as) {
a += fraccolleft * tqAlpha( *xP );
r += fraccoltofill * tqRed( *xP ) * tqAlpha( *xP ) / 255;
g += fraccoltofill * tqGreen( *xP ) * tqAlpha( *xP ) / 255;
b += fraccoltofill * tqBlue( *xP ) * tqAlpha( *xP ) / 255;
if ( a ) {
r = r * 255 / a * SCALE;
g = g * 255 / a * SCALE;
b = b * 255 / a * SCALE;
}
} else {
r += fraccoltofill * tqRed( *xP );
g += fraccoltofill * tqGreen( *xP );
b += fraccoltofill * tqBlue( *xP );
}
}
}
if ( ! needcol ) {
if ((rowswritten >= y) && (rowswritten <= (y + h))) {
r /= SCALE;
if ( r > maxval ) r = maxval;
g /= SCALE;
if ( g > maxval ) g = maxval;
b /= SCALE;
if ( b > maxval ) b = maxval;
if (as) {
a /= SCALE;
if ( a > maxval ) a = maxval;
*nxP = tqRgba( (int)r, (int)g, (int)b, (int)a );
} else {
*nxP = tqRgb( (int)r, (int)g, (int)b );
}
}
}
}
}
if ( newrows != rows && tempxelrow )// Robust, tempxelrow might be 0 1 day
delete [] tempxelrow;
if ( as ) // Avoid purify complaint
delete [] as;
if ( rs ) // Robust, rs might be 0 one day
delete [] rs;
if ( gs ) // Robust, gs might be 0 one day
delete [] gs;
if ( bs ) // Robust, bs might be 0 one day
delete [] bs;
}