-rw-r--r-- | libopie2/opieui/oimageeffect.cpp | 76 |
1 files changed, 25 insertions, 51 deletions
diff --git a/libopie2/opieui/oimageeffect.cpp b/libopie2/opieui/oimageeffect.cpp index 3c28bbe..2855da6 100644 --- a/libopie2/opieui/oimageeffect.cpp +++ b/libopie2/opieui/oimageeffect.cpp @@ -35,67 +35,65 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <stdlib.h> #include <iostream> #include "oimageeffect.h" #define MaxRGB 255L #define DegreesToRadians(x) ((x)*M_PI/180.0) using namespace std; inline unsigned int intensityValue(unsigned int color) { return((unsigned int)((0.299*qRed(color) + 0.587*qGreen(color) + 0.1140000000000001*qBlue(color)))); } //====================================================================== // // Gradient effects // //====================================================================== QImage OImageEffect::gradient(const QSize &size, const QColor &ca, const QColor &cb, GradientType eff, int ncols) { int rDiff, gDiff, bDiff; int rca, gca, bca, rcb, gcb, bcb; QImage image(size, 32); if (size.width() == 0 || size.height() == 0) { -#ifndef NDEBUG - cerr << "WARNING: OImageEffect::gradient: invalid image" << endl; -#endif + qDebug( "WARNING: OImageEffect::gradient: invalid image" ); return image; } register int x, y; rDiff = (rcb = cb.red()) - (rca = ca.red()); gDiff = (gcb = cb.green()) - (gca = ca.green()); bDiff = (bcb = cb.blue()) - (bca = ca.blue()); if( eff == VerticalGradient || eff == HorizontalGradient ){ uint *p; uint rgb; register int rl = rca << 16; register int gl = gca << 16; register int bl = bca << 16; if( eff == VerticalGradient ) { int rcdelta = ((1<<16) / size.height()) * rDiff; int gcdelta = ((1<<16) / size.height()) * gDiff; int bcdelta = ((1<<16) / size.height()) * bDiff; for ( y = 0; y < size.height(); y++ ) { p = (uint *) image.scanLine(y); rl += rcdelta; gl += gcdelta; bl += bcdelta; rgb = qRgb( (rl>>16), (gl>>16), (bl>>16) ); @@ -323,67 +321,65 @@ QImage OImageEffect::unbalancedGradient(const QSize &size, const QColor &ca, const QColor &cb, GradientType eff, int xfactor, int yfactor, int ncols) { int dir; // general parameter used for direction switches bool _xanti = false , _yanti = false; if (xfactor < 0) _xanti = true; // negative on X direction if (yfactor < 0) _yanti = true; // negative on Y direction xfactor = abs(xfactor); yfactor = abs(yfactor); if (!xfactor) xfactor = 1; if (!yfactor) yfactor = 1; if (xfactor > 200 ) xfactor = 200; if (yfactor > 200 ) yfactor = 200; // float xbal = xfactor/5000.; // float ybal = yfactor/5000.; float xbal = xfactor/30./size.width(); float ybal = yfactor/30./size.height(); float rat; int rDiff, gDiff, bDiff; int rca, gca, bca, rcb, gcb, bcb; QImage image(size, 32); if (size.width() == 0 || size.height() == 0) { -#ifndef NDEBUG - cerr << "WARNING: OImageEffect::unbalancedGradient : invalid image\n"; -#endif + qDebug( "WARNING: OImageEffect::unbalancedGradient : invalid image" ); return image; } register int x, y; unsigned int *scanline; rDiff = (rcb = cb.red()) - (rca = ca.red()); gDiff = (gcb = cb.green()) - (gca = ca.green()); bDiff = (bcb = cb.blue()) - (bca = ca.blue()); if( eff == VerticalGradient || eff == HorizontalGradient){ QColor cRow; uint *p; uint rgbRow; if( eff == VerticalGradient) { for ( y = 0; y < size.height(); y++ ) { dir = _yanti ? y : size.height() - 1 - y; p = (uint *) image.scanLine(dir); rat = 1 - exp( - (float)y * ybal ); cRow.setRgb( rcb - (int) ( rDiff * rat ), gcb - (int) ( gDiff * rat ), bcb - (int) ( bDiff * rat ) ); rgbRow = cRow.rgb(); for( x = 0; x < size.width(); x++ ) { *p = rgbRow; p++; } @@ -544,134 +540,130 @@ QImage OImageEffect::unbalancedGradient(const QSize &size, const QColor &ca, } delete [] xtable[0]; delete [] xtable[1]; delete [] xtable[2]; delete [] ytable[0]; delete [] ytable[1]; delete [] ytable[2]; } return image; } //====================================================================== // // Intensity effects // //====================================================================== /* This builds a 256 byte unsigned char lookup table with all * the possible percent values prior to applying the effect, then uses * integer math for the pixels. For any image larger than 9x9 this will be * less expensive than doing a float operation on the 3 color components of * each pixel. (mosfet) */ QImage& OImageEffect::intensity(QImage &image, float percent) { if (image.width() == 0 || image.height() == 0) { -#ifndef NDEBUG - cerr << "WARNING: OImageEffect::intensity : invalid image\n"; -#endif + qDebug( "WARNING: OImageEffect::intensity : invalid image" ); return image; } int segColors = image.depth() > 8 ? 256 : image.numColors(); unsigned char *segTbl = new unsigned char[segColors]; int pixels = image.depth() > 8 ? image.width()*image.height() : image.numColors(); unsigned int *data = image.depth() > 8 ? (unsigned int *)image.bits() : (unsigned int *)image.colorTable(); bool brighten = (percent >= 0); if(percent < 0) percent = -percent; if(brighten){ // keep overflow check out of loops for(int i=0; i < segColors; ++i){ int tmp = (int)(i*percent); if(tmp > 255) tmp = 255; segTbl[i] = tmp; } } else{ for(int i=0; i < segColors; ++i){ int tmp = (int)(i*percent); if(tmp < 0) tmp = 0; segTbl[i] = tmp; } } if(brighten){ // same here for(int i=0; i < pixels; ++i){ int r = qRed(data[i]); int g = qGreen(data[i]); int b = qBlue(data[i]); int a = qAlpha(data[i]); r = r + segTbl[r] > 255 ? 255 : r + segTbl[r]; g = g + segTbl[g] > 255 ? 255 : g + segTbl[g]; b = b + segTbl[b] > 255 ? 255 : b + segTbl[b]; data[i] = qRgba(r, g, b,a); } } else{ for(int i=0; i < pixels; ++i){ int r = qRed(data[i]); int g = qGreen(data[i]); int b = qBlue(data[i]); int a = qAlpha(data[i]); r = r - segTbl[r] < 0 ? 0 : r - segTbl[r]; g = g - segTbl[g] < 0 ? 0 : g - segTbl[g]; b = b - segTbl[b] < 0 ? 0 : b - segTbl[b]; data[i] = qRgba(r, g, b, a); } } delete [] segTbl; return image; } QImage& OImageEffect::channelIntensity(QImage &image, float percent, RGBComponent channel) { if (image.width() == 0 || image.height() == 0) { -#ifndef NDEBUG - cerr << "WARNING: OImageEffect::channelIntensity : invalid image\n"; -#endif + qDebug( "WARNING: OImageEffect::channelIntensity : invalid image" ); return image; } int segColors = image.depth() > 8 ? 256 : image.numColors(); unsigned char *segTbl = new unsigned char[segColors]; int pixels = image.depth() > 8 ? image.width()*image.height() : image.numColors(); unsigned int *data = image.depth() > 8 ? (unsigned int *)image.bits() : (unsigned int *)image.colorTable(); bool brighten = (percent >= 0); if(percent < 0) percent = -percent; if(brighten){ // keep overflow check out of loops for(int i=0; i < segColors; ++i){ int tmp = (int)(i*percent); if(tmp > 255) tmp = 255; segTbl[i] = tmp; } } else{ for(int i=0; i < segColors; ++i){ int tmp = (int)(i*percent); if(tmp < 0) tmp = 0; segTbl[i] = tmp; } } if(brighten){ // same here if(channel == Red){ // and here ;-) @@ -703,68 +695,66 @@ QImage& OImageEffect::channelIntensity(QImage &image, float percent, int c = qRed(data[i]); c = c - segTbl[c] < 0 ? 0 : c - segTbl[c]; data[i] = qRgba(c, qGreen(data[i]), qBlue(data[i]), qAlpha(data[i])); } } if(channel == Green){ for(int i=0; i < pixels; ++i){ int c = qGreen(data[i]); c = c - segTbl[c] < 0 ? 0 : c - segTbl[c]; data[i] = qRgba(qRed(data[i]), c, qBlue(data[i]), qAlpha(data[i])); } } else{ for(int i=0; i < pixels; ++i){ int c = qBlue(data[i]); c = c - segTbl[c] < 0 ? 0 : c - segTbl[c]; data[i] = qRgba(qRed(data[i]), qGreen(data[i]), c, qAlpha(data[i])); } } } delete [] segTbl; return image; } // Modulate an image with an RBG channel of another image // QImage& OImageEffect::modulate(QImage &image, QImage &modImage, bool reverse, ModulationType type, int factor, RGBComponent channel) { if (image.width() == 0 || image.height() == 0 || modImage.width() == 0 || modImage.height() == 0) { -#ifndef NDEBUG - cerr << "WARNING: OImageEffect::modulate : invalid image\n"; -#endif - return image; + qDebug( "WARNING: OImageEffect::modulate : invalid image" ); + return image; } int r, g, b, h, s, v, a; QColor clr; int mod=0; unsigned int x1, x2, y1, y2; register int x, y; // for image, we handle only depth 32 if (image.depth()<32) image = image.convertDepth(32); // for modImage, we handle depth 8 and 32 if (modImage.depth()<8) modImage = modImage.convertDepth(8); unsigned int *colorTable2 = (modImage.depth()==8) ? modImage.colorTable():0; unsigned int *data1, *data2; unsigned char *data2b; unsigned int color1, color2; x1 = image.width(); y1 = image.height(); x2 = modImage.width(); y2 = modImage.height(); for (y = 0; y < (int)y1; y++) { data1 = (unsigned int *) image.scanLine(y); data2 = (unsigned int *) modImage.scanLine( y%y2 ); data2b = (unsigned char *) modImage.scanLine( y%y2 ); x=0; while(x < (int)x1) { color2 = (colorTable2) ? colorTable2[*data2b] : *data2; if (reverse) { @@ -831,165 +821,157 @@ QImage& OImageEffect::modulate(QImage &image, QImage &modImage, bool reverse, if (s<0) s=0; if (s>255) s=255; } else { // HueShift h += mod; while(h<0) h+=360; h %= 360; } clr.setHsv(h, s, v); a = qAlpha(*data1); *data1 = clr.rgb() | ((uint)(a & 0xff) << 24); } data1++; data2++; data2b++; x++; if ( (x%x2) ==0) { data2 -= x2; data2b -= x2; } } } return image; } //====================================================================== // // Blend effects // //====================================================================== // Nice and fast direct pixel manipulation QImage& OImageEffect::blend(const QColor& clr, QImage& dst, float opacity) { if (dst.width() <= 0 || dst.height() <= 0) - return dst; + return dst; if (opacity < 0.0 || opacity > 1.0) { -#ifndef NDEBUG - cerr << "WARNING: OImageEffect::blend : invalid opacity. Range [0, 1]\n"; -#endif - return dst; + qDebug( "WARNING: OImageEffect::blend : invalid opacity. Range [0, 1] "); + return dst; } int depth = dst.depth(); if (depth != 32) - dst = dst.convertDepth(32); + dst = dst.convertDepth(32); int pixels = dst.width() * dst.height(); int rcol, gcol, bcol; clr.rgb(&rcol, &gcol, &bcol); #ifdef WORDS_BIGENDIAN // ARGB (skip alpha) register unsigned char *data = (unsigned char *)dst.bits() + 1; #else // BGRA register unsigned char *data = (unsigned char *)dst.bits(); #endif for (register int i=0; i<pixels; i++) { #ifdef WORDS_BIGENDIAN *(data++) += (unsigned char)((rcol - *data) * opacity); *(data++) += (unsigned char)((gcol - *data) * opacity); *(data++) += (unsigned char)((bcol - *data) * opacity); #else *(data++) += (unsigned char)((bcol - *data) * opacity); *(data++) += (unsigned char)((gcol - *data) * opacity); *(data++) += (unsigned char)((rcol - *data) * opacity); #endif data++; // skip alpha } return dst; } // Nice and fast direct pixel manipulation QImage& OImageEffect::blend(QImage& src, QImage& dst, float opacity) { if (src.width() <= 0 || src.height() <= 0) - return dst; + return dst; if (dst.width() <= 0 || dst.height() <= 0) - return dst; + return dst; if (src.width() != dst.width() || src.height() != dst.height()) { -#ifndef NDEBUG - cerr << "WARNING: OImageEffect::blend : src and destination images are not the same size\n"; -#endif - return dst; + qDebug( "WARNING: OImageEffect::blend : src and destination images are not the same size" ); + return dst; } if (opacity < 0.0 || opacity > 1.0) { -#ifndef NDEBUG - cerr << "WARNING: OImageEffect::blend : invalid opacity. Range [0, 1]\n"; -#endif - return dst; + qDebug( "WARNING: OImageEffect::blend : invalid opacity. Range [0, 1]" ); + return dst; } if (src.depth() != 32) src = src.convertDepth(32); if (dst.depth() != 32) dst = dst.convertDepth(32); int pixels = src.width() * src.height(); #ifdef WORDS_BIGENDIAN // ARGB (skip alpha) register unsigned char *data1 = (unsigned char *)dst.bits() + 1; register unsigned char *data2 = (unsigned char *)src.bits() + 1; #else // BGRA register unsigned char *data1 = (unsigned char *)dst.bits(); register unsigned char *data2 = (unsigned char *)src.bits(); #endif for (register int i=0; i<pixels; i++) { #ifdef WORDS_BIGENDIAN *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity); *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity); *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity); #else *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity); *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity); *(data1++) += (unsigned char)((*(data2++) - *data1) * opacity); #endif data1++; // skip alpha data2++; } return dst; } QImage& OImageEffect::blend(QImage &image, float initial_intensity, const QColor &bgnd, GradientType eff, bool anti_dir) { if (image.width() == 0 || image.height() == 0 || image.depth()!=32 ) { -#ifndef NDEBUG - cerr << "WARNING: OImageEffect::blend : invalid image\n"; -#endif - return image; + qDebug( "WARNING: OImageEffect::blend : invalid image" ); + return image; } int r_bgnd = bgnd.red(), g_bgnd = bgnd.green(), b_bgnd = bgnd.blue(); int r, g, b; int ind; unsigned int xi, xf, yi, yf; unsigned int a; // check the boundaries of the initial intesity param float unaffected = 1; if (initial_intensity > 1) initial_intensity = 1; if (initial_intensity < -1) initial_intensity = -1; if (initial_intensity < 0) { unaffected = 1. + initial_intensity; initial_intensity = 0; } float intensity = initial_intensity; float var = 1. - initial_intensity; if (anti_dir) { initial_intensity = intensity = 1.; var = -var; } register int x, y; unsigned int *data = (unsigned int *)image.bits(); int image_width = image.width(); //Those can't change @@ -1123,100 +1105,96 @@ QImage& OImageEffect::blend(QImage &image, float initial_intensity, if (intensity < 0) intensity = 0; //SW ind = x + image_width * (image_height - y -1) ; r = qRed (data[ind]) + (int)(intensity * (r_bgnd - qRed (data[ind]))); g = qGreen(data[ind]) + (int)(intensity * (g_bgnd - qGreen(data[ind]))); b = qBlue (data[ind]) + (int)(intensity * (b_bgnd - qBlue (data[ind]))); if (r > 255) r = 255; if (r < 0 ) r = 0; if (g > 255) g = 255; if (g < 0 ) g = 0; if (b > 255) b = 255; if (b < 0 ) b = 0; a = qAlpha(data[ind]); data[ind] = qRgba(r, g, b, a); //SE ind = image_width-x-1 + image_width * (image_height - y - 1) ; r = qRed (data[ind]) + (int)(intensity * (r_bgnd - qRed (data[ind]))); g = qGreen(data[ind]) + (int)(intensity * (g_bgnd - qGreen(data[ind]))); b = qBlue (data[ind]) + (int)(intensity * (b_bgnd - qBlue (data[ind]))); if (r > 255) r = 255; if (r < 0 ) r = 0; if (g > 255) g = 255; if (g < 0 ) g = 0; if (b > 255) b = 255; if (b < 0 ) b = 0; a = qAlpha(data[ind]); data[ind] = qRgba(r, g, b, a); } } } -#ifndef NDEBUG - else cerr << "OImageEffect::blend effect not implemented" << endl; -#endif + else qDebug( "OImageEffect::blend effect not implemented" ); return image; } // Not very efficient as we create a third big image... // QImage& OImageEffect::blend(QImage &image1, QImage &image2, GradientType gt, int xf, int yf) { if (image1.width() == 0 || image1.height() == 0 || image2.width() == 0 || image2.height() == 0) return image1; QImage image3; image3 = OImageEffect::unbalancedGradient(image1.size(), QColor(0,0,0), QColor(255,255,255), gt, xf, yf, 0); return blend(image1,image2,image3, Red); // Channel to use is arbitrary } // Blend image2 into image1, using an RBG channel of blendImage // QImage& OImageEffect::blend(QImage &image1, QImage &image2, QImage &blendImage, RGBComponent channel) { if (image1.width() == 0 || image1.height() == 0 || image2.width() == 0 || image2.height() == 0 || blendImage.width() == 0 || blendImage.height() == 0) { -#ifndef NDEBUG - cerr << "OImageEffect::blend effect invalid image" << endl; -#endif - return image1; + qDebug( "OImageEffect::blend effect invalid image" ); + return image1; } int r, g, b; int ind1, ind2, ind3; unsigned int x1, x2, x3, y1, y2, y3; unsigned int a; register int x, y; // for image1 and image2, we only handle depth 32 if (image1.depth()<32) image1 = image1.convertDepth(32); if (image2.depth()<32) image2 = image2.convertDepth(32); // for blendImage, we handle depth 8 and 32 if (blendImage.depth()<8) blendImage = blendImage.convertDepth(8); unsigned int *colorTable3 = (blendImage.depth()==8) ? blendImage.colorTable():0; unsigned int *data1 = (unsigned int *)image1.bits(); unsigned int *data2 = (unsigned int *)image2.bits(); unsigned int *data3 = (unsigned int *)blendImage.bits(); unsigned char *data3b = (unsigned char *)blendImage.bits(); unsigned int color3; x1 = image1.width(); y1 = image1.height(); x2 = image2.width(); y2 = image2.height(); x3 = blendImage.width(); y3 = blendImage.height(); for (y = 0; y < (int)y1; y++) { ind1 = x1*y; @@ -1255,68 +1233,66 @@ QImage& OImageEffect::blend(QImage &image1, QImage &image2, unsigned int OImageEffect::lHash(unsigned int c) { unsigned char r = qRed(c), g = qGreen(c), b = qBlue(c), a = qAlpha(c); unsigned char nr, ng, nb; nr =(r >> 1) + (r >> 2); nr = nr > r ? 0 : nr; ng =(g >> 1) + (g >> 2); ng = ng > g ? 0 : ng; nb =(b >> 1) + (b >> 2); nb = nb > b ? 0 : nb; return qRgba(nr, ng, nb, a); } // ----------------------------------------------------------------------------- unsigned int OImageEffect::uHash(unsigned int c) { unsigned char r = qRed(c), g = qGreen(c), b = qBlue(c), a = qAlpha(c); unsigned char nr, ng, nb; nr = r + (r >> 3); nr = nr < r ? ~0 : nr; ng = g + (g >> 3); ng = ng < g ? ~0 : ng; nb = b + (b >> 3); nb = nb < b ? ~0 : nb; return qRgba(nr, ng, nb, a); } // ----------------------------------------------------------------------------- QImage& OImageEffect::hash(QImage &image, Lighting lite, unsigned int spacing) { if (image.width() == 0 || image.height() == 0) { -#ifndef NDEBUG - cerr << "OImageEffect::hash effect invalid image" << endl; -#endif - return image; + qDebug( "OImageEffect::hash effect invalid image" ); + return image; } register int x, y; unsigned int *data = (unsigned int *)image.bits(); unsigned int ind; //CT no need to do it if not enough space if ((lite == NorthLite || lite == SouthLite)&& (unsigned)image.height() < 2+spacing) return image; if ((lite == EastLite || lite == WestLite)&& (unsigned)image.height() < 2+spacing) return image; if (lite == NorthLite || lite == SouthLite) { for (y = 0 ; y < image.height(); y = y + 2 + spacing) { for (x = 0; x < image.width(); x++) { ind = x + image.width() * y; data[ind] = lite==NorthLite?uHash(data[ind]):lHash(data[ind]); ind = ind + image.width(); data[ind] = lite==NorthLite?lHash(data[ind]):uHash(data[ind]); } } } else if (lite == EastLite || lite == WestLite) { for (y = 0 ; y < image.height(); y++) { for (x = 0; x < image.width(); x = x + 2 + spacing) { ind = x + image.width() * y; data[ind] = lite==EastLite?uHash(data[ind]):lHash(data[ind]); @@ -1765,68 +1741,66 @@ int OImageEffect::nearestColor( int r, int g, int b, const QColor *palette, int for (int i = 1; i < size; i++ ) { dr = palette[i].red() - r; dg = palette[i].green() - g; db = palette[i].blue() - b; int dist = dr*dr + dg*dg + db*db; if ( dist < minDist ) { minDist = dist; nearest = i; } } return nearest; } bool OImageEffect::blend( const QImage & upper, const QImage & lower, QImage & output ) { if ( upper.width() > lower.width() || upper.height() > lower.height() || upper.depth() != 32 || lower.depth() != 32 ) { -#ifndef NDEBUG - cerr << "OImageEffect::blend : Sizes not correct\n" ; -#endif - return false; + qDebug( "OImageEffect::blend : Sizes not correct" ); + return false; } output = lower.copy(); register uchar *i, *o; register int a; register int col; register int w = upper.width(); int row(upper.height() - 1); do { i = upper.scanLine(row); o = output.scanLine(row); col = w << 2; --col; do { while (!(a = i[col]) && (col != 3)) { --col; --col; --col; --col; } --col; o[col] += ((i[col] - o[col]) * a) >> 8; --col; o[col] += ((i[col] - o[col]) * a) >> 8; --col; o[col] += ((i[col] - o[col]) * a) >> 8; |