summaryrefslogtreecommitdiff
path: root/libopie2/opieui/oimageeffect.cpp
Side-by-side diff
Diffstat (limited to 'libopie2/opieui/oimageeffect.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--libopie2/opieui/oimageeffect.cpp7
1 files changed, 6 insertions, 1 deletions
diff --git a/libopie2/opieui/oimageeffect.cpp b/libopie2/opieui/oimageeffect.cpp
index 9a58bb9..be47eb2 100644
--- a/libopie2/opieui/oimageeffect.cpp
+++ b/libopie2/opieui/oimageeffect.cpp
@@ -1,235 +1,239 @@
/* This file is part of the KDE libraries
Copyright (C) 1998, 1999, 2001, 2002 Daniel M. Duley <mosfet@kde.org>
(C) 1998, 1999 Christian Tibirna <ctibirna@total.net>
(C) 1998, 1999 Dirk A. Mueller <mueller@kde.org>
(C) 2000 Josef Weidendorfer <weidendo@in.tum.de>
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.
*/
// $Id$
#include <math.h>
#include <qimage.h>
#include <stdlib.h>
#include <opie2/oimageeffect.h>
#include <opie2/odebug.h>
#define MaxRGB 255L
#define DegreesToRadians(x) ((x)*M_PI/180.0)
using namespace std;
+using namespace Opie::Core;
+
+namespace Opie {
+namespace Ui {
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) {
odebug << "WARNING: OImageEffect::gradient: invalid image" << oendl;
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) );
for( x = 0; x < size.width(); x++ ) {
*p = rgb;
p++;
}
}
}
else { // must be HorizontalGradient
unsigned int *o_src = (unsigned int *)image.scanLine(0);
unsigned int *src = o_src;
int rcdelta = ((1<<16) / size.width()) * rDiff;
int gcdelta = ((1<<16) / size.width()) * gDiff;
int bcdelta = ((1<<16) / size.width()) * bDiff;
for( x = 0; x < size.width(); x++) {
rl += rcdelta;
gl += gcdelta;
bl += bcdelta;
*src++ = qRgb( (rl>>16), (gl>>16), (bl>>16));
}
src = o_src;
// Believe it or not, manually copying in a for loop is faster
// than calling memcpy for each scanline (on the order of ms...).
// I think this is due to the function call overhead (mosfet).
for (y = 1; y < size.height(); ++y) {
p = (unsigned int *)image.scanLine(y);
src = o_src;
for(x=0; x < size.width(); ++x)
*p++ = *src++;
}
}
}
else {
float rfd, gfd, bfd;
float rd = rca, gd = gca, bd = bca;
unsigned char *xtable[3];
unsigned char *ytable[3];
unsigned int w = size.width(), h = size.height();
xtable[0] = new unsigned char[w];
xtable[1] = new unsigned char[w];
xtable[2] = new unsigned char[w];
ytable[0] = new unsigned char[h];
ytable[1] = new unsigned char[h];
ytable[2] = new unsigned char[h];
w*=2, h*=2;
if ( eff == DiagonalGradient || eff == CrossDiagonalGradient) {
// Diagonal dgradient code inspired by BlackBox (mosfet)
// BlackBox dgradient is (C) Brad Hughes, <bhughes@tcac.net> and
// Mike Cole <mike@mydot.com>.
rfd = (float)rDiff/w;
gfd = (float)gDiff/w;
bfd = (float)bDiff/w;
int dir;
for (x = 0; x < size.width(); x++, rd+=rfd, gd+=gfd, bd+=bfd) {
dir = eff == DiagonalGradient? x : size.width() - x - 1;
xtable[0][dir] = (unsigned char) rd;
xtable[1][dir] = (unsigned char) gd;
xtable[2][dir] = (unsigned char) bd;
}
rfd = (float)rDiff/h;
gfd = (float)gDiff/h;
bfd = (float)bDiff/h;
rd = gd = bd = 0;
for (y = 0; y < size.height(); y++, rd+=rfd, gd+=gfd, bd+=bfd) {
ytable[0][y] = (unsigned char) rd;
ytable[1][y] = (unsigned char) gd;
ytable[2][y] = (unsigned char) bd;
}
for (y = 0; y < size.height(); y++) {
unsigned int *scanline = (unsigned int *)image.scanLine(y);
for (x = 0; x < size.width(); x++) {
scanline[x] = qRgb(xtable[0][x] + ytable[0][y],
xtable[1][x] + ytable[1][y],
xtable[2][x] + ytable[2][y]);
}
}
}
else if (eff == RectangleGradient ||
eff == PyramidGradient ||
eff == PipeCrossGradient ||
eff == EllipticGradient)
{
int rSign = rDiff>0? 1: -1;
int gSign = gDiff>0? 1: -1;
int bSign = bDiff>0? 1: -1;
rfd = (float)rDiff / size.width();
gfd = (float)gDiff / size.width();
bfd = (float)bDiff / size.width();
rd = (float)rDiff/2;
gd = (float)gDiff/2;
bd = (float)bDiff/2;
for (x = 0; x < size.width(); x++, rd-=rfd, gd-=gfd, bd-=bfd)
{
xtable[0][x] = (unsigned char) abs((int)rd);
xtable[1][x] = (unsigned char) abs((int)gd);
xtable[2][x] = (unsigned char) abs((int)bd);
}
rfd = (float)rDiff/size.height();
gfd = (float)gDiff/size.height();
bfd = (float)bDiff/size.height();
rd = (float)rDiff/2;
gd = (float)gDiff/2;
bd = (float)bDiff/2;
for (y = 0; y < size.height(); y++, rd-=rfd, gd-=gfd, bd-=bfd)
{
ytable[0][y] = (unsigned char) abs((int)rd);
ytable[1][y] = (unsigned char) abs((int)gd);
ytable[2][y] = (unsigned char) abs((int)bd);
}
unsigned int rgb;
int h = (size.height()+1)>>1;
for (y = 0; y < h; y++) {
@@ -3576,193 +3580,194 @@ QImage OImageEffect::shade(QImage &src, bool color_shading, double azimuth,
// shade this row of pixels.
s0 = p;
s1 = (unsigned char *) src.scanLine(scanLineIdx+1);
s2 = (unsigned char *) src.scanLine(scanLineIdx+2);
*q++=(*(cTable+(*s1)));
++p;
++s0;
++s1;
++s2;
for(x=1; x < src.width()-1; ++x){
// determine the surface normal and compute shading.
normal.x=intensityValue(*(cTable+(*(s0-1))))+intensityValue(*(cTable+(*(s1-1))))+intensityValue(*(cTable+(*(s2-1))))-
(double) intensityValue(*(cTable+(*(s0+1))))-(double) intensityValue(*(cTable+(*(s1+1))))-
(double) intensityValue(*(cTable+(*(s2+1))));
normal.y=intensityValue(*(cTable+(*(s2-1))))+intensityValue(*(cTable+(*s2)))+intensityValue(*(cTable+(*(s2+1))))-
(double) intensityValue(*(cTable+(*(s0-1))))-(double) intensityValue(*(cTable+(*s0)))-
(double) intensityValue(*(cTable+(*(s0+1))));
if((normal.x == 0) && (normal.y == 0))
shade=light.z;
else{
shade=0.0;
distance=normal.x*light.x+normal.y*light.y+normal.z*light.z;
if (distance > 0.0){
normal_distance=
normal.x*normal.x+normal.y*normal.y+normal.z*normal.z;
if(fabs(normal_distance) > 0.0000001)
shade=distance/sqrt(normal_distance);
}
}
if(!color_shading){
*q = qRgba((unsigned char)(shade),
(unsigned char)(shade),
(unsigned char)(shade),
qAlpha(*(cTable+(*s1))));
}
else{
*q = qRgba((unsigned char)((shade*qRed(*(cTable+(*s1))))/(MaxRGB+1)),
(unsigned char)((shade*qGreen(*(cTable+(*s1))))/(MaxRGB+1)),
(unsigned char)((shade*qBlue(*(cTable+(*s1))))/(MaxRGB+1)),
qAlpha(*s1));
}
++s0;
++s1;
++s2;
q++;
}
*q++=(*(cTable+(*s1)));
}
}
return(dest);
}
QImage OImageEffect::blur(QImage &src, double factor)
{
#define Blur(weight) \
total_red+=(weight)*qRed(*s); \
total_green+=(weight)*qGreen(*s); \
total_blue+=(weight)*qBlue(*s); \
total_opacity+=(weight)*qAlpha(*s); \
s++;
#define Blur256(weight) \
total_red+=(weight)*qRed(*(cTable+(*s))); \
total_green+=(weight)*qGreen(*(cTable+(*s))); \
total_blue+=(weight)*qBlue(*(cTable+(*s))); \
total_opacity+=(weight)*qAlpha(*(cTable+(*s))); \
s++;
if(src.width() < 3 || src.height() < 3)
return(src);
double quantum, total_blue, total_green, total_opacity, total_red, weight;
int x, y;
unsigned int *q;
QImage dest(src.width(), src.height(), 32);
weight=((100.0-factor)/2)+1;
quantum = QMAX(weight+12.0, 1.0);
if(src.depth() > 8){ // DirectClass source image
unsigned int *p, *s;
for(y=0; y < src.height(); ++y){
p = (unsigned int *)src.scanLine(QMIN(QMAX(y-1,0),src.height()-3));
q = (unsigned int *)dest.scanLine(y);
// blur this row of pixels.
*q++=(*(p+src.width()));
for(x=1; x < src.width()-1; ++x){
// compute weighted average of target pixel color components.
total_red=0.0;
total_green=0.0;
total_blue=0.0;
total_opacity=0.0;
s=p;
Blur(1); Blur(2); Blur(1);
s=p+src.width();
Blur(2); Blur(weight); Blur(2);
s=p+2*src.width();
Blur(1); Blur(2); Blur(1);
*q = qRgba((unsigned char)((total_red+(quantum/2))/quantum),
(unsigned char)((total_green+(quantum/2))/quantum),
(unsigned char)((total_blue+(quantum/2))/quantum),
(unsigned char)((total_opacity+(quantum/2))/quantum));
p++;
q++;
}
p++;
*q++=(*p);
}
}
else{ // PsudeoClass source image
unsigned char *p, *p2, *p3, *s;
unsigned int *cTable = src.colorTable();
int scanLineIdx;
for(y=0; y < src.height(); ++y){
scanLineIdx = QMIN(QMAX(y-1,0),src.height()-3);
p = (unsigned char *)src.scanLine(scanLineIdx);
p2 = (unsigned char *)src.scanLine(scanLineIdx+1);
p3 = (unsigned char *)src.scanLine(scanLineIdx+2);
q = (unsigned int *)dest.scanLine(y);
// blur this row of pixels.
*q++=(*(cTable+(*p2)));
for(x=1; x < src.width()-1; ++x){
// compute weighted average of target pixel color components.
total_red=0.0;
total_green=0.0;
total_blue=0.0;
total_opacity=0.0;
s=p;
Blur256(1); Blur256(2); Blur256(1);
s=p2;
Blur256(2); Blur256(weight); Blur256(2);
s=p3;
Blur256(1); Blur256(2); Blur256(1);
*q = qRgba((unsigned char)((total_red+(quantum/2))/quantum),
(unsigned char)((total_green+(quantum/2))/quantum),
(unsigned char)((total_blue+(quantum/2))/quantum),
(unsigned char)((total_opacity+(quantum/2))/quantum));
p++;
p2++;
p3++;
q++;
}
p++;
*q++=(*(cTable+(*p)));
}
}
return(dest);
}
// High quality, expensive HSV contrast. You can do a faster one by just
// taking a grayscale threshold (ie: 128) and incrementing RGB color
// channels above it and decrementing those below it, but this gives much
// better results. (mosfet 12/28/01)
void OImageEffect::contrastHSV(QImage &img, bool sharpen)
{
int i, sign;
unsigned int *data;
int count;
double brightness, scale, theta;
QColor c;
int h, s, v;
sign = sharpen ? 1 : -1;
scale=0.5000000000000001;
if(img.depth() > 8){
count = img.width()*img.height();
data = (unsigned int *)img.bits();
}
else{
count = img.numColors();
data = (unsigned int *)img.colorTable();
}
for(i=0; i < count; ++i){
c.setRgb(data[i]);
c.hsv(&h, &s, &v);
brightness = v/255.0;
theta=(brightness-0.5)*M_PI;
brightness+=scale*(((scale*((sin(theta)+1.0)))-brightness)*sign);
if (brightness > 1.0)
brightness=1.0;
else
if (brightness < 0)
brightness=0.0;
v = (int)(brightness*255);
c.setHsv(h, s, v);
data[i] = qRgba(c.red(), c.green(), c.blue(), qAlpha(data[i]));
}
}
-
+}
+}