diff options
Diffstat (limited to 'krdc/vnc/scaling.cpp')
-rw-r--r-- | krdc/vnc/scaling.cpp | 331 |
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; +} |