summaryrefslogtreecommitdiffstats
path: root/krdc/vnc/scaling.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'krdc/vnc/scaling.cpp')
-rw-r--r--krdc/vnc/scaling.cpp331
1 files changed, 331 insertions, 0 deletions
diff --git a/krdc/vnc/scaling.cpp b/krdc/vnc/scaling.cpp
new file mode 100644
index 00000000..b79b8873
--- /dev/null
+++ b/krdc/vnc/scaling.cpp
@@ -0,0 +1,331 @@
+/****************************************************************************
+**
+** 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;
+ register TQRgb* xP;
+ register TQRgb* nxP;
+ int rows, cols, rowsread, newrows, newcols;
+ register int row, col, needtoreadrow;
+ const uchar maxval = 255;
+ double xscale, yscale;
+ long sxscale, syscale;
+ register 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;
+ }
+ register long a=0;
+ for ( col = 0, xP = xelrow, nxP = tempxelrow, colswritten = 0;
+ col < cols; ++col, ++xP, ++nxP, ++colswritten )
+ {
+if ((rowswritten >= y) && (rowswritten <= (y + h))) {
+ register 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 {
+ register long a, r, g, b;
+ register long fraccoltofill, fraccolleft = 0;
+ register 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;
+}