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.cpp5
1 files changed, 4 insertions, 1 deletions
diff --git a/libopie2/opieui/oimageeffect.cpp b/libopie2/opieui/oimageeffect.cpp
index be47eb2..93719bc 100644
--- a/libopie2/opieui/oimageeffect.cpp
+++ b/libopie2/opieui/oimageeffect.cpp
@@ -1670,770 +1670,773 @@ QImage& OImageEffect::dither(QImage &img, const QColor *palette, int size)
int *berr2 = berr1 + img.width();
for ( int j = 0; j < img.height(); j++ )
{
uint *ip = (uint * )img.scanLine( j );
uchar *dp = dImage.scanLine( j );
for ( i = 0; i < img.width(); i++ )
{
rerr1[i] = rerr2[i] + qRed( *ip );
rerr2[i] = 0;
gerr1[i] = gerr2[i] + qGreen( *ip );
gerr2[i] = 0;
berr1[i] = berr2[i] + qBlue( *ip );
berr2[i] = 0;
ip++;
}
*dp++ = nearestColor( rerr1[0], gerr1[0], berr1[0], palette, size );
for ( i = 1; i < img.width()-1; i++ )
{
int indx = nearestColor( rerr1[i], gerr1[i], berr1[i], palette, size );
*dp = indx;
int rerr = rerr1[i];
rerr -= palette[indx].red();
int gerr = gerr1[i];
gerr -= palette[indx].green();
int berr = berr1[i];
berr -= palette[indx].blue();
// diffuse red error
rerr1[ i+1 ] += ( rerr * 7 ) >> 4;
rerr2[ i-1 ] += ( rerr * 3 ) >> 4;
rerr2[ i ] += ( rerr * 5 ) >> 4;
rerr2[ i+1 ] += ( rerr ) >> 4;
// diffuse green error
gerr1[ i+1 ] += ( gerr * 7 ) >> 4;
gerr2[ i-1 ] += ( gerr * 3 ) >> 4;
gerr2[ i ] += ( gerr * 5 ) >> 4;
gerr2[ i+1 ] += ( gerr ) >> 4;
// diffuse red error
berr1[ i+1 ] += ( berr * 7 ) >> 4;
berr2[ i-1 ] += ( berr * 3 ) >> 4;
berr2[ i ] += ( berr * 5 ) >> 4;
berr2[ i+1 ] += ( berr ) >> 4;
dp++;
}
*dp = nearestColor( rerr1[i], gerr1[i], berr1[i], palette, size );
}
delete [] rerr1;
delete [] gerr1;
delete [] berr1;
img = dImage;
return img;
}
int OImageEffect::nearestColor( int r, int g, int b, const QColor *palette, int size )
{
if (palette == 0)
return 0;
int dr = palette[0].red() - r;
int dg = palette[0].green() - g;
int db = palette[0].blue() - b;
int minDist = dr*dr + dg*dg + db*db;
int nearest = 0;
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
)
{
odebug << "OImageEffect::blend : Sizes not correct" << oendl;
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;
} while (col--);
} while (row--);
return true;
}
#if 0
// Not yet...
bool OImageEffect::blend(
const QImage & upper,
const QImage & lower,
QImage & output,
const QRect & destRect
)
{
output = lower.copy();
return output;
}
#endif
bool OImageEffect::blend(
int &x, int &y,
const QImage & upper,
const QImage & lower,
QImage & output
)
{
int cx=0, cy=0, cw=upper.width(), ch=upper.height();
if ( upper.width() + x > lower.width() ||
upper.height() + y > lower.height() ||
x < 0 || y < 0 ||
upper.depth() != 32 || lower.depth() != 32 )
{
if ( x > lower.width() || y > lower.height() ) return false;
if ( upper.width()<=0 || upper.height() <= 0 ) return false;
if ( lower.width()<=0 || lower.height() <= 0 ) return false;
if (x<0) {cx=-x; cw+=x; x=0; };
if (cw + x > lower.width()) { cw=lower.width()-x; };
if (y<0) {cy=-y; ch+=y; y=0; };
if (ch + y > lower.height()) { ch=lower.height()-y; };
if ( cx >= upper.width() || cy >= upper.height() ) return true;
if ( cw <= 0 || ch <= 0 ) return true;
}
output.create(cw,ch,32);
// output.setAlphaBuffer(true); // I should do some benchmarks to see if
// this is worth the effort
register QRgb *i, *o, *b;
register int a;
register int j,k;
for (j=0; j<ch; j++)
{
b=reinterpret_cast<QRgb *>(&lower.scanLine(y+j) [ (x+cw) << 2 ]);
i=reinterpret_cast<QRgb *>(&upper.scanLine(cy+j)[ (cx+cw) << 2 ]);
o=reinterpret_cast<QRgb *>(&output.scanLine(j) [ cw << 2 ]);
k=cw-1;
--b; --i; --o;
do
{
while ( !(a=qAlpha(*i)) && k>0 )
{
i--;
// *o=0;
*o=*b;
--o; --b;
k--;
};
// *o=0xFF;
*o = qRgb(qRed(*b) + (((qRed(*i) - qRed(*b)) * a) >> 8),
qGreen(*b) + (((qGreen(*i) - qGreen(*b)) * a) >> 8),
qBlue(*b) + (((qBlue(*i) - qBlue(*b)) * a) >> 8));
--i; --o; --b;
} while (k--);
}
return true;
}
bool OImageEffect::blendOnLower(
int x, int y,
const QImage & upper,
const QImage & lower
)
{
int cx=0, cy=0, cw=upper.width(), ch=upper.height();
if ( upper.depth() != 32 || lower.depth() != 32 ) return false;
if ( x + cw > lower.width() ||
y + ch > lower.height() ||
x < 0 || y < 0 )
{
if ( x > lower.width() || y > lower.height() ) return true;
if ( upper.width()<=0 || upper.height() <= 0 ) return true;
if ( lower.width()<=0 || lower.height() <= 0 ) return true;
if (x<0) {cx=-x; cw+=x; x=0; };
if (cw + x > lower.width()) { cw=lower.width()-x; };
if (y<0) {cy=-y; ch+=y; y=0; };
if (ch + y > lower.height()) { ch=lower.height()-y; };
if ( cx >= upper.width() || cy >= upper.height() ) return true;
if ( cw <= 0 || ch <= 0 ) return true;
}
register uchar *i, *b;
register int a;
register int k;
for (int j=0; j<ch; j++)
{
b=&lower.scanLine(y+j) [ (x+cw) << 2 ];
i=&upper.scanLine(cy+j)[ (cx+cw) << 2 ];
k=cw-1;
--b; --i;
do
{
#ifndef WORDS_BIGENDIAN
while ( !(a=*i) && k>0 )
#else
while ( !(a=*(i-3)) && k>0 )
#endif
{
i-=4; b-=4; k--;
};
#ifndef WORDS_BIGENDIAN
--i; --b;
*b += ( ((*i - *b) * a) >> 8 );
--i; --b;
*b += ( ((*i - *b) * a) >> 8 );
--i; --b;
*b += ( ((*i - *b) * a) >> 8 );
--i; --b;
#else
*b += ( ((*i - *b) * a) >> 8 );
--i; --b;
*b += ( ((*i - *b) * a) >> 8 );
--i; --b;
*b += ( ((*i - *b) * a) >> 8 );
i -= 2; b -= 2;
#endif
} while (k--);
}
return true;
}
// For selected icons
QImage& OImageEffect::selectedImage( QImage &img, const QColor &col )
{
return blend( col, img, 0.5);
}
//
// ===================================================================
// Effects originally ported from ImageMagick for PixiePlus, plus a few
// new ones. (mosfet 12/29/01)
// ===================================================================
//
void OImageEffect::normalize(QImage &img)
{
int *histogram, threshold_intensity, intense;
int x, y, i;
unsigned int gray_value;
unsigned int *normalize_map;
unsigned int high, low;
// allocate histogram and normalize map
histogram = (int *)calloc(MaxRGB+1, sizeof(int));
normalize_map = (unsigned int *)malloc((MaxRGB+1)*sizeof(unsigned int));
if(!normalize_map || !histogram){
owarn << "Unable to allocate normalize histogram and map" << oendl;
free(normalize_map);
free(histogram);
return;
}
// form histogram
if(img.depth() > 8){ // DirectClass
unsigned int *data;
for(y=0; y < img.height(); ++y){
data = (unsigned int *)img.scanLine(y);
for(x=0; x < img.width(); ++x){
gray_value = intensityValue(data[x]);
histogram[gray_value]++;
}
}
}
else{ // PsudeoClass
unsigned char *data;
unsigned int *cTable = img.colorTable();
for(y=0; y < img.height(); ++y){
data = (unsigned char *)img.scanLine(y);
for(x=0; x < img.width(); ++x){
gray_value = intensityValue(*(cTable+data[x]));
histogram[gray_value]++;
}
}
}
// find histogram boundaries by locating the 1 percent levels
threshold_intensity = (img.width()*img.height())/100;
intense = 0;
for(low=0; low < MaxRGB; ++low){
intense+=histogram[low];
if(intense > threshold_intensity)
break;
}
intense=0;
for(high=MaxRGB; high != 0; --high){
intense+=histogram[high];
if(intense > threshold_intensity)
break;
}
if (low == high){
// Unreasonable contrast; use zero threshold to determine boundaries.
threshold_intensity=0;
intense=0;
for(low=0; low < MaxRGB; ++low){
intense+=histogram[low];
if(intense > threshold_intensity)
break;
}
intense=0;
for(high=MaxRGB; high != 0; --high)
{
intense+=histogram[high];
if(intense > threshold_intensity)
break;
}
- if(low == high)
+ if(low == high) {
+ free(histogram);
+ free(normalize_map);
return; // zero span bound
+ }
}
// Stretch the histogram to create the normalized image mapping.
for(i=0; i <= MaxRGB; i++){
if (i < (int) low)
normalize_map[i]=0;
else{
if(i > (int) high)
normalize_map[i]=MaxRGB;
else
normalize_map[i]=(MaxRGB-1)*(i-low)/(high-low);
}
}
// Normalize
if(img.depth() > 8){ // DirectClass
unsigned int *data;
for(y=0; y < img.height(); ++y){
data = (unsigned int *)img.scanLine(y);
for(x=0; x < img.width(); ++x){
data[x] = qRgba(normalize_map[qRed(data[x])],
normalize_map[qGreen(data[x])],
normalize_map[qBlue(data[x])],
qAlpha(data[x]));
}
}
}
else{ // PsudeoClass
int colors = img.numColors();
unsigned int *cTable = img.colorTable();
for(i=0; i < colors; ++i){
cTable[i] = qRgba(normalize_map[qRed(cTable[i])],
normalize_map[qGreen(cTable[i])],
normalize_map[qBlue(cTable[i])],
qAlpha(cTable[i]));
}
}
free(histogram);
free(normalize_map);
}
void OImageEffect::equalize(QImage &img)
{
int *histogram, *map, *equalize_map;
int x, y, i, j;
unsigned int high, low;
// allocate histogram and maps
histogram = (int *)calloc(MaxRGB+1, sizeof(int));
map = (int *)malloc((MaxRGB+1)*sizeof(unsigned int));
equalize_map = (int *)malloc((MaxRGB+1)*sizeof(unsigned int));
if(!histogram || !map || !equalize_map){
owarn << "Unable to allocate equalize histogram and maps" << oendl;
free(histogram);
free(map);
free(equalize_map);
return;
}
// form histogram
if(img.depth() > 8){ // DirectClass
unsigned int *data;
for(y=0; y < img.height(); ++y){
data = (unsigned int *)img.scanLine(y);
for(x=0; x < img.width(); ++x){
histogram[intensityValue(data[x])]++;
}
}
}
else{ // PsudeoClass
unsigned char *data;
unsigned int *cTable = img.colorTable();
for(y=0; y < img.height(); ++y){
data = (unsigned char *)img.scanLine(y);
for(x=0; x < img.width(); ++x){
histogram[intensityValue(*(cTable+data[x]))]++;
}
}
}
// integrate the histogram to get the equalization map.
j=0;
for(i=0; i <= MaxRGB; i++){
j+=histogram[i];
map[i]=j;
}
free(histogram);
if(map[MaxRGB] == 0){
free(equalize_map);
free(map);
return;
}
// equalize
low=map[0];
high=map[MaxRGB];
for(i=0; i <= MaxRGB; i++)
equalize_map[i]=(unsigned int)
((((double) (map[i]-low))*MaxRGB)/QMAX(high-low,1));
free(map);
// stretch the histogram
if(img.depth() > 8){ // DirectClass
unsigned int *data;
for(y=0; y < img.height(); ++y){
data = (unsigned int *)img.scanLine(y);
for(x=0; x < img.width(); ++x){
data[x] = qRgba(equalize_map[qRed(data[x])],
equalize_map[qGreen(data[x])],
equalize_map[qBlue(data[x])],
qAlpha(data[x]));
}
}
}
else{ // PsudeoClass
int colors = img.numColors();
unsigned int *cTable = img.colorTable();
for(i=0; i < colors; ++i){
cTable[i] = qRgba(equalize_map[qRed(cTable[i])],
equalize_map[qGreen(cTable[i])],
equalize_map[qBlue(cTable[i])],
qAlpha(cTable[i]));
}
}
free(equalize_map);
}
QImage OImageEffect::sample(QImage &src, int w, int h)
{
if(w == src.width() && h == src.height())
return(src);
double *x_offset, *y_offset;
int j, k, y;
register int x;
QImage dest(w, h, src.depth());
x_offset = (double *)malloc(w*sizeof(double));
y_offset = (double *)malloc(h*sizeof(double));
if(!x_offset || !y_offset){
owarn << "Unable to allocate pixels buffer" << oendl;
free(x_offset);
free(y_offset);
return(src);
}
// init pixel offsets
for(x=0; x < w; ++x)
x_offset[x] = x*src.width()/((double)w);
for(y=0; y < h; ++y)
y_offset[y] = y*src.height()/((double)h);
// sample each row
if(src.depth() > 8){ // DirectClass source image
unsigned int *srcData, *destData;
unsigned int *pixels;
pixels = (unsigned int *)malloc(src.width()*sizeof(unsigned int));
if(!pixels){
owarn << "Unable to allocate pixels buffer" << oendl;
free(pixels);
free(x_offset);
free(y_offset);
return(src);
}
j = (-1);
for(y=0; y < h; ++y){
destData = (unsigned int *)dest.scanLine(y);
if(j != y_offset[y]){
// read a scan line
j = (int)(y_offset[y]);
srcData = (unsigned int *)src.scanLine(j);
(void)memcpy(pixels, srcData, src.width()*sizeof(unsigned int));
}
// sample each column
for(x=0; x < w; ++x){
k = (int)(x_offset[x]);
destData[x] = pixels[k];
}
}
free(pixels);
}
else{ // PsudeoClass source image
unsigned char *srcData, *destData;
unsigned char *pixels;
pixels = (unsigned char *)malloc(src.width()*sizeof(unsigned char));
if(!pixels){
owarn << "Unable to allocate pixels buffer" << oendl;
free(pixels);
free(x_offset);
free(y_offset);
return(src);
}
// copy colortable
dest.setNumColors(src.numColors());
(void)memcpy(dest.colorTable(), src.colorTable(),
src.numColors()*sizeof(unsigned int));
// sample image
j = (-1);
for(y=0; y < h; ++y){
destData = (unsigned char *)dest.scanLine(y);
if(j != y_offset[y]){
// read a scan line
j = (int)(y_offset[y]);
srcData = (unsigned char *)src.scanLine(j);
(void)memcpy(pixels, srcData, src.width()*sizeof(unsigned char));
}
// sample each column
for(x=0; x < w; ++x){
k = (int)(x_offset[x]);
destData[x] = pixels[k];
}
}
free(pixels);
}
free(x_offset);
free(y_offset);
return(dest);
}
void OImageEffect::threshold(QImage &img, unsigned int threshold)
{
int i, count;
unsigned int *data;
if(img.depth() > 8){ // DirectClass
count = img.width()*img.height();
data = (unsigned int *)img.bits();
}
else{ // PsudeoClass
count = img.numColors();
data = (unsigned int *)img.colorTable();
}
for(i=0; i < count; ++i)
data[i] = intensityValue(data[i]) < threshold ? Qt::black.rgb() : Qt::white.rgb();
}
QImage OImageEffect::charcoal(QImage &src, double factor)
{
QImage dest(src);
dest.detach();
toGray(dest);
dest = edge(dest, factor);
dest = blur(dest, factor);
normalize(dest);
dest.invertPixels(false);
return(dest);
}
void OImageEffect::hull(const int x_offset, const int y_offset,
const int polarity, const int columns,
const int rows,
unsigned int *f, unsigned int *g)
{
int x, y;
unsigned int *p, *q, *r, *s;
unsigned int v;
if(f == NULL || g == NULL)
return;
p=f+(columns+2);
q=g+(columns+2);
r=p+(y_offset*(columns+2)+x_offset);
for (y=0; y < rows; y++){
p++;
q++;
r++;
if(polarity > 0)
for (x=0; x < columns; x++){
v=(*p);
if (*r > v)
v++;
*q=v;
p++;
q++;
r++;
}
else
for(x=0; x < columns; x++){
v=(*p);
if (v > (unsigned int) (*r+1))
v--;
*q=v;
p++;
q++;
r++;
}
p++;
q++;
r++;
}
p=f+(columns+2);
q=g+(columns+2);
r=q+(y_offset*(columns+2)+x_offset);
s=q-(y_offset*(columns+2)+x_offset);
for(y=0; y < rows; y++){
p++;
q++;
r++;
s++;
if(polarity > 0)
for(x=0; x < (int) columns; x++){
v=(*q);
if (((unsigned int) (*s+1) > v) && (*r > v))
v++;
*p=v;
p++;
q++;
r++;
s++;
}
else
for (x=0; x < columns; x++){
v=(*q);
if (((unsigned int) (*s+1) < v) && (*r < v))
v--;
*p=v;
p++;
q++;
r++;
s++;
}
p++;
q++;
r++;
s++;
}
}
QImage OImageEffect::despeckle(QImage &src)
{
int i, j, x, y;
unsigned int *blue_channel, *red_channel, *green_channel, *buffer,
*alpha_channel;
int packets;
static const int
X[4]= {0, 1, 1,-1},
Y[4]= {1, 0, 1, 1};
unsigned int *destData;
QImage dest(src.width(), src.height(), 32);
packets = (src.width()+2)*(src.height()+2);
red_channel = (unsigned int *)calloc(packets, sizeof(unsigned int));
green_channel = (unsigned int *)calloc(packets, sizeof(unsigned int));
blue_channel = (unsigned int *)calloc(packets, sizeof(unsigned int));
alpha_channel = (unsigned int *)calloc(packets, sizeof(unsigned int));
buffer = (unsigned int *)calloc(packets, sizeof(unsigned int));
if(!red_channel || ! green_channel || ! blue_channel || ! alpha_channel ||
!buffer){
free(red_channel);
free(green_channel);
free(blue_channel);
free(alpha_channel);
free(buffer);
return(src);
}
// copy image pixels to color component buffers
j = src.width()+2;
if(src.depth() > 8){ // DirectClass source image
unsigned int *srcData;
for(y=0; y < src.height(); ++y){
srcData = (unsigned int *)src.scanLine(y);
++j;
for(x=0; x < src.width(); ++x){
red_channel[j] = qRed(srcData[x]);
green_channel[j] = qGreen(srcData[x]);
blue_channel[j] = qBlue(srcData[x]);
alpha_channel[j] = qAlpha(srcData[x]);
++j;
}
++j;
}
}
else{ // PsudeoClass source image
unsigned char *srcData;
unsigned int *cTable = src.colorTable();
unsigned int pixel;
for(y=0; y < src.height(); ++y){
srcData = (unsigned char *)src.scanLine(y);
++j;
for(x=0; x < src.width(); ++x){
pixel = *(cTable+srcData[x]);
red_channel[j] = qRed(pixel);
green_channel[j] = qGreen(pixel);