This is effects.c in view mode; [Download] [Up]
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% EEEEE FFFFF FFFFF EEEEE CCCC TTTTT SSSSS %
% E F F E C T SS %
% EEE FFF FFF EEE C T SSS %
% E F F E C T SS %
% EEEEE F F EEEEE CCCC T SSSSS %
% %
% %
% ImageMagick Image Effects Routines %
% %
% %
% %
% Software Design %
% John Cristy %
% October 1996 %
% %
% %
% Copyright 1997 E. I. du Pont de Nemours and Company %
% %
% Permission to use, copy, modify, distribute, and sell this software and %
% its documentation for any purpose is hereby granted without fee, %
% provided that the above Copyright notice appear in all copies and that %
% both that Copyright notice and this permission notice appear in %
% supporting documentation, and that the name of E. I. du Pont de Nemours %
% and Company not be used in advertising or publicity pertaining to %
% distribution of the software without specific, written prior %
% permission. E. I. du Pont de Nemours and Company makes no representations %
% about the suitability of this software for any purpose. It is provided %
% "as is" without express or implied warranty. %
% %
% E. I. du Pont de Nemours and Company disclaims all warranties with regard %
% to this software, including all implied warranties of merchantability %
% and fitness, in no event shall E. I. du Pont de Nemours and Company be %
% liable for any special, indirect or consequential damages or any %
% damages whatsoever resulting from loss of use, data or profits, whether %
% in an action of contract, negligence or other tortious action, arising %
% out of or in connection with the use or performance of this software. %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%
%
*/
/*
Include declarations.
*/
#include "magick.h"
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% A d d N o i s e I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function AddNoiseImage creates a new image that is a copy of an existing
% one with noise added. It allocates the memory necessary for the new Image
% structure and returns a pointer to the new image.
%
% The format of the AddNoiseImage routine is:
%
% noisy_image=AddNoiseImage(image,noise_type)
%
% A description of each parameter follows:
%
% o noisy_image: Function AddNoiseImage returns a pointer to the image after
% the noise is minified. A null image is returned if there is a memory
% shortage.
%
% o image: The address of a structure of type Image; returned from
% ReadImage.
%
% o noise_type: The type of noise: gaussian, multiplicative gaussian,
% impulse, laplacian, or poisson.
%
%
*/
Image *AddNoiseImage(Image *image,NoiseType noise_type)
{
#define AddNoiseImageText " Adding noise to the image... "
Image
*noisy_image;
register RunlengthPacket
*p,
*q;
register unsigned int
x;
unsigned int
y;
/*
Initialize noisy image attributes.
*/
assert(image != (Image *) NULL);
srand(time(0));
noisy_image=CloneImage(image,image->columns,image->rows,False);
if (noisy_image == (Image *) NULL)
{
Warning("Unable to reduce noise","Memory allocation failed");
return((Image *) NULL);
}
noisy_image->class=DirectClass;
/*
Add noise in each row.
*/
p=image->pixels;
image->runlength=p->length+1;
q=noisy_image->pixels;
for (y=0; y < image->rows; y++)
{
for (x=0; x < image->columns; x++)
{
if (image->runlength != 0)
image->runlength--;
else
{
p++;
image->runlength=p->length;
}
q->red=GenerateNoise(p->red,noise_type);
q->green=GenerateNoise(p->green,noise_type);
q->blue=GenerateNoise(p->blue,noise_type);
q->length=0;
q++;
}
ProgressMonitor(AddNoiseImageText,y,image->rows);
}
return(noisy_image);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% B l u r I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function BlurImage creates a new image that is a copy of an existing
% one with the pixels blurred. It allocates the memory necessary for the
% new Image structure and returns a pointer to the new image.
%
% BlurImage convolves the pixel neighborhood with this blurring mask:
%
% 1 2 1
% 2 W 2
% 1 2 1
%
% The scan only processes pixels that have a full set of neighbors. Pixels
% in the top, bottom, left, and right pairs of rows and columns are omitted
% from the scan.
%
% The format of the BlurImage routine is:
%
% blurred_image=BlurImage(image,factor)
%
% A description of each parameter follows:
%
% o blurred_image: Function BlurImage returns a pointer to the image
% after it is blurred. A null image is returned if there is a memory
% shortage.
%
% o image: The address of a structure of type Image; returned from
% ReadImage.
%
% o factor: An double value reflecting the percent weight to give to the
% center pixel of the neighborhood.
%
%
*/
Image *BlurImage(Image *image,double factor)
{
#define Blur(weight) \
total_red+=(weight)*(int) (s->red); \
total_green+=(weight)*(int) (s->green); \
total_blue+=(weight)*(int) (s->blue); \
s++;
#define BlurImageText " Blurring image... "
Image
*blurred_image;
long
total_blue,
total_green,
total_red,
weight;
register RunlengthPacket
*p,
*q,
*s,
*s0,
*s1,
*s2;
register unsigned int
x;
RunlengthPacket
*scanline;
unsigned int
quantum,
y;
assert(image != (Image *) NULL);
if ((image->columns < 3) || (image->rows < 3))
{
Warning("Unable to blur image","image size must exceed 3x3");
return((Image *) NULL);
}
/*
Initialize blurred image attributes.
*/
blurred_image=CloneImage(image,image->columns,image->rows,False);
if (blurred_image == (Image *) NULL)
{
Warning("Unable to blur image","Memory allocation failed");
return((Image *) NULL);
}
blurred_image->class=DirectClass;
/*
Allocate scan line buffer for 3 rows of the image.
*/
scanline=(RunlengthPacket *) malloc(3*image->columns*sizeof(RunlengthPacket));
if (scanline == (RunlengthPacket *) NULL)
{
Warning("Unable to blur image","Memory allocation failed");
DestroyImage(blurred_image);
return((Image *) NULL);
}
/*
Read the first two rows of the image.
*/
p=image->pixels;
image->runlength=p->length+1;
s=scanline;
for (x=0; x < (image->columns << 1); x++)
{
if (image->runlength != 0)
image->runlength--;
else
{
p++;
image->runlength=p->length;
}
*s=(*p);
s++;
}
/*
Dump first scanline of pixels.
*/
q=blurred_image->pixels;
s1=scanline;
for (x=0; x < image->columns; x++)
{
*q=(*s1++);
q->length=0;
q++;
}
/*
Blur each row.
*/
weight=(long) ((100.0-factor)/2);
quantum=(unsigned int) Max(weight+12,1);
for (y=1; y < (image->rows-1); y++)
{
/*
Initialize sliding window pointers.
*/
s0=scanline+image->columns*((y-1) % 3);
s1=scanline+image->columns*(y % 3);
s2=scanline+image->columns*((y+1) % 3);
/*
Read another scan line.
*/
s=s2;
for (x=0; x < image->columns; x++)
{
if (image->runlength != 0)
image->runlength--;
else
{
p++;
image->runlength=p->length;
}
*s=(*p);
s++;
}
/*
Blur this row of pixels.
*/
*q=(*s1);
q->length=0;
q++;
for (x=1; x < (image->columns-1); x++)
{
/*
Compute weighted average of target pixel color components.
*/
total_red=0;
total_green=0;
total_blue=0;
s=s0;
Blur(1); Blur(2); Blur(1);
s=s1;
Blur(2); Blur(weight); Blur(2);
s=s2;
Blur(1); Blur(2); Blur(1);
q->red=(Quantum) ((total_red+(quantum >> 1))/quantum);
q->green=(Quantum) ((total_green+(quantum >> 1))/quantum);
q->blue=(Quantum) ((total_blue+(quantum >> 1))/quantum);
q->index=s1->index;
q->length=0;
q++;
s0++;
s1++;
s2++;
}
/*
Transfer last pixel of the scanline.
*/
*q=(*s1);
q->length=0;
q++;
ProgressMonitor(BlurImageText,y,image->rows);
}
/*
Dump last scanline of pixels.
*/
s1=scanline+image->columns*(y % 3);
for (x=0; x < image->columns; x++)
{
*q=(*s1++);
q->length=0;
q++;
}
free((char *) scanline);
return(blurred_image);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% D e s p e c k l e I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function DespeckleImage creates a new image that is a copy of an existing
% one with the speckle noise minified. It uses the eight hull algorithm
% described in Applied Optics, Vol. 24, No. 10, 15 May 1985, "Geometric filter
% for Speckle Reduction", by Thomas R Crimmins. Each pixel in the image is
% replaced by one of its eight of its surrounding pixels using a polarity and
% negative hull function. DespeckleImage allocates the memory necessary for
% the new Image structure and returns a pointer to the new image.
%
% The format of the DespeckleImage routine is:
%
% despeckled_image=DespeckleImage(image)
%
% A description of each parameter follows:
%
% o despeckled_image: Function DespeckleImage returns a pointer to the image
% after it is despeckled. A null image is returned if there is a memory
% shortage.
%
% o image: The address of a structure of type Image; returned from
% ReadImage.
%
%
*/
Image *DespeckleImage(Image *image)
{
#define DespeckleImageText " Despeckling image... "
Image
*despeckled_image;
int
x;
Quantum
*blue_channel,
*buffer,
*green_channel,
*matte_channel,
*red_channel;
register int
i,
j;
register RunlengthPacket
*p,
*q;
static int
X[4]= {0, 1, 1,-1},
Y[4]= {1, 0, 1, 1};
unsigned int
packets;
/*
Allocate despeckled image.
*/
assert(image != (Image *) NULL);
despeckled_image=CloneImage(image,image->columns,image->rows,False);
if (despeckled_image == (Image *) NULL)
{
Warning("Unable to despeckle image","Memory allocation failed");
return((Image *) NULL);
}
despeckled_image->class=DirectClass;
/*
Allocate image buffers.
*/
packets=(image->columns+2)*(image->rows+2);
red_channel=(Quantum *) malloc(packets*sizeof(Quantum));
green_channel=(Quantum *) malloc(packets*sizeof(Quantum));
blue_channel=(Quantum *) malloc(packets*sizeof(Quantum));
matte_channel=(Quantum *) malloc(packets*sizeof(Quantum));
buffer=(Quantum *) malloc(packets*sizeof(Quantum));
if ((red_channel == (Quantum *) NULL) ||
(green_channel == (Quantum *) NULL) ||
(blue_channel == (Quantum *) NULL) ||
(matte_channel == (Quantum *) NULL) ||
(buffer == (Quantum *) NULL) || !UncompressImage(image))
{
Warning("Unable to despeckle image","Memory allocation failed");
DestroyImage(despeckled_image);
return((Image *) NULL);
}
/*
Zero image buffers.
*/
for (i=0; i < packets; i++)
{
red_channel[i]=0;
green_channel[i]=0;
blue_channel[i]=0;
matte_channel[i]=0;
buffer[i]=0;
}
/*
Copy image pixels to color component buffers
*/
x=image->columns+2;
p=image->pixels;
for (j=0; j < image->rows; j++)
{
x++;
for (i=0; i < image->columns; i++)
{
red_channel[x]=p->red;
green_channel[x]=p->green;
blue_channel[x]=p->blue;
matte_channel[x]=p->index;
x++;
p++;
}
x++;
}
/*
Reduce speckle in red channel.
*/
for (i=0; i < 4; i++)
{
ProgressMonitor(DespeckleImageText,i,12);
Hull(X[i],Y[i],1,image->columns,image->rows,red_channel,buffer);
Hull(-X[i],-Y[i],1,image->columns,image->rows,red_channel,buffer);
Hull(-X[i],-Y[i],-1,image->columns,image->rows,red_channel,buffer);
Hull(X[i],Y[i],-1,image->columns,image->rows,red_channel,buffer);
}
/*
Reduce speckle in green channel.
*/
for (i=0; i < packets; i++)
buffer[i]=0;
for (i=0; i < 4; i++)
{
ProgressMonitor(DespeckleImageText,i+4,12);
Hull(X[i],Y[i],1,image->columns,image->rows,green_channel,buffer);
Hull(-X[i],-Y[i],1,image->columns,image->rows,green_channel,buffer);
Hull(-X[i],-Y[i],-1,image->columns,image->rows,green_channel,buffer);
Hull(X[i],Y[i],-1,image->columns,image->rows,green_channel,buffer);
}
/*
Reduce speckle in blue channel.
*/
for (i=0; i < packets; i++)
buffer[i]=0;
for (i=0; i < 4; i++)
{
ProgressMonitor(DespeckleImageText,i+8,12);
Hull(X[i],Y[i],1,image->columns,image->rows,blue_channel,buffer);
Hull(-X[i],-Y[i],1,image->columns,image->rows,blue_channel,buffer);
Hull(-X[i],-Y[i],-1,image->columns,image->rows,blue_channel,buffer);
Hull(X[i],Y[i],-1,image->columns,image->rows,blue_channel,buffer);
}
/*
Copy color component buffers to despeckled image.
*/
x=image->columns+2;
q=despeckled_image->pixels;
for (j=0; j < image->rows; j++)
{
x++;
for (i=0; i < image->columns; i++)
{
q->red=red_channel[x];
q->green=green_channel[x];
q->blue=blue_channel[x];
q->index=matte_channel[x];
q->length=0;
q++;
x++;
}
x++;
}
/*
Free memory.
*/
free((char *) buffer);
free((char *) blue_channel);
free((char *) green_channel);
free((char *) red_channel);
return(despeckled_image);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% E d g e I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function EdgeImage creates a new image that is a copy of an existing
% one with the edges highlighted. It allocates the memory necessary for the
% new Image structure and returns a pointer to the new image.
%
% EdgeImage convolves the pixel neighborhood with this edge detection mask:
%
% -1 0 -1
% 0 W 0
% -1 0 -1
%
% The scan only processes pixels that have a full set of neighbors. Pixels
% in the top, bottom, left, and right pairs of rows and columns are omitted
% from the scan.
%
% The format of the EdgeImage routine is:
%
% edged_image=EdgeImage(image,factor)
%
% A description of each parameter follows:
%
% o edged_image: Function EdgeImage returns a pointer to the image
% after it is edged. A null image is returned if there is a memory
% shortage.
%
% o image: The address of a structure of type Image; returned from
% ReadImage.
%
% o factor: An double value reflecting the percent weight to give to the
% center pixel of the neighborhood.
%
%
*/
Image *EdgeImage(Image *image,double factor)
{
#define Edge(weight) \
total_red+=(long) ((weight)*(int) (s->red)); \
total_green+=(long) ((weight)*(int) (s->green)); \
total_blue+=(long) ((weight)*(int) (s->blue)); \
total_index+=(long) ((weight)*(int) (s->index)); \
s++;
#define EdgeImageText " Detecting image edges... "
double
weight;
Image
*edged_image;
long
total_blue,
total_green,
total_index,
total_red;
register RunlengthPacket
*p,
*q,
*s,
*s0,
*s1,
*s2;
register unsigned int
x;
RunlengthPacket
*scanline;
unsigned int
y;
assert(image != (Image *) NULL);
if ((image->columns < 3) || (image->rows < 3))
{
Warning("Unable to detect edges","image size must exceed 3x3");
return((Image *) NULL);
}
/*
Initialize edged image attributes.
*/
edged_image=CloneImage(image,image->columns,image->rows,False);
if (edged_image == (Image *) NULL)
{
Warning("Unable to detect edges","Memory allocation failed");
return((Image *) NULL);
}
edged_image->class=DirectClass;
/*
Allocate scan line buffer for 3 rows of the image.
*/
scanline=(RunlengthPacket *) malloc(3*image->columns*sizeof(RunlengthPacket));
if (scanline == (RunlengthPacket *) NULL)
{
Warning("Unable to detect edges","Memory allocation failed");
DestroyImage(edged_image);
return((Image *) NULL);
}
/*
Read the first two rows of the image.
*/
p=image->pixels;
image->runlength=p->length+1;
s=scanline;
for (x=0; x < (image->columns << 1); x++)
{
if (image->runlength != 0)
image->runlength--;
else
{
p++;
image->runlength=p->length;
}
*s=(*p);
s++;
}
/*
Dump first scanline of pixels.
*/
q=edged_image->pixels;
for (x=0; x < image->columns; x++)
{
q->red=0;
q->green=0;
q->blue=0;
q->index=0;
q->length=0;
q++;
}
/*
Edge detect each row.
*/
weight=((100.0-factor)/20)+1.5;
for (y=1; y < (image->rows-1); y++)
{
/*
Initialize sliding window pointers.
*/
s0=scanline+image->columns*((y-1) % 3);
s1=scanline+image->columns*(y % 3);
s2=scanline+image->columns*((y+1) % 3);
/*
Read another scan line.
*/
s=s2;
for (x=0; x < image->columns; x++)
{
if (image->runlength != 0)
image->runlength--;
else
{
p++;
image->runlength=p->length;
}
*s=(*p);
s++;
}
/*
Edge detect this row of pixels.
*/
*q++=(*(q-1));
for (x=1; x < (image->columns-1); x++)
{
/*
Compute weighted average of target pixel color components.
*/
total_red=0;
total_green=0;
total_blue=0;
total_index=0;
s=s1+1;
s=s0;
Edge(-weight/4); Edge( 0); Edge(-weight/4);
s=s1;
Edge( 0); Edge(weight); Edge( 0);
s=s2;
Edge(-weight/4); Edge( 0); Edge(-weight/4);
q->red=(Quantum)
((total_red < 0) ? 0 : (total_red > MaxRGB) ? MaxRGB : total_red);
q->green=(Quantum)
((total_green < 0) ? 0 : (total_green > MaxRGB) ? MaxRGB : total_green);
q->blue=(Quantum)
((total_blue < 0) ? 0 : (total_blue > MaxRGB) ? MaxRGB : total_blue);
q->index=(unsigned short) ((total_index < Transparent) ? Transparent :
(total_index > Opaque) ? Opaque : total_index);
q->length=0;
q++;
s0++;
s1++;
s2++;
}
*q++=(*(q-1));
ProgressMonitor(EdgeImageText,y,image->rows-1);
}
/*
Dump last scanline of pixels.
*/
for (x=0; x < image->columns; x++)
{
q->red=0;
q->green=0;
q->blue=0;
q->index=0;
q->length=0;
q->length=0;
q++;
}
free((char *) scanline);
/*
Normalize image.
*/
NormalizeImage(edged_image);
return(edged_image);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% E m b o s s I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function EmbossImage creates a new image that is a copy of an existing
% one with the edge highlighted. It allocates the memory necessary for the
% new Image structure and returns a pointer to the new image.
%
% EmbossImage convolves the pixel neighborhood with this edge detection mask:
%
% -1 -2 0
% -2 0 2
% 0 2 1
%
% The scan only processes pixels that have a full set of neighbors. Pixels
% in the top, bottom, left, and right pairs of rows and columns are omitted
% from the scan.
%
% The format of the EmbossImage routine is:
%
% embossed_image=EmbossImage(image)
%
% A description of each parameter follows:
%
% o embossed_image: Function EmbossImage returns a pointer to the image
% after it is embossed. A null image is returned if there is a memory
% shortage.
%
% o image: The address of a structure of type Image; returned from
% ReadImage.
%
%
*/
Image *EmbossImage(Image *image)
{
#define EmbossImageText " Embossing image... "
#define Emboss(weight) \
total_red+=(weight)*(int) (s->red); \
total_green+=(weight)*(int) (s->green); \
total_blue+=(weight)*(int) (s->blue); \
s++;
Image
*embossed_image;
long
total_blue,
total_green,
total_red;
register RunlengthPacket
*p,
*q,
*s,
*s0,
*s1,
*s2;
register unsigned int
x;
RunlengthPacket
*scanline;
unsigned int
y;
assert(image != (Image *) NULL);
if ((image->columns < 3) || (image->rows < 3))
{
Warning("Unable to emboss image","image size must exceed 3x3");
return((Image *) NULL);
}
/*
Initialize embossed image attributes.
*/
embossed_image=CloneImage(image,image->columns,image->rows,False);
if (embossed_image == (Image *) NULL)
{
Warning("Unable to enhance image","Memory allocation failed");
return((Image *) NULL);
}
embossed_image->class=DirectClass;
/*
Allocate scan line buffer for 3 rows of the image.
*/
scanline=(RunlengthPacket *) malloc(3*image->columns*sizeof(RunlengthPacket));
if (scanline == (RunlengthPacket *) NULL)
{
Warning("Unable to enhance image","Memory allocation failed");
DestroyImage(embossed_image);
return((Image *) NULL);
}
/*
Read the first two rows of the image.
*/
p=image->pixels;
image->runlength=p->length+1;
s=scanline;
for (x=0; x < (image->columns << 1); x++)
{
if (image->runlength != 0)
image->runlength--;
else
{
p++;
image->runlength=p->length;
}
*s=(*p);
s++;
}
/*
Dump first scanline of pixels.
*/
q=embossed_image->pixels;
for (x=0; x < image->columns; x++)
{
q->red=0;
q->green=0;
q->blue=0;
q->index=0;
q->length=0;
q++;
}
/*
Emboss each row.
*/
for (y=1; y < (image->rows-1); y++)
{
/*
Initialize sliding window pointers.
*/
s0=scanline+image->columns*((y-1) % 3);
s1=scanline+image->columns*(y % 3);
s2=scanline+image->columns*((y+1) % 3);
/*
Read another scan line.
*/
s=s2;
for (x=0; x < image->columns; x++)
{
if (image->runlength != 0)
image->runlength--;
else
{
p++;
image->runlength=p->length;
}
*s=(*p);
s++;
}
/*
Emboss this row of pixels.
*/
*q++=(*(q-1));
for (x=1; x < (image->columns-1); x++)
{
/*
Compute weighted average of target pixel color components.
*/
total_red=0;
total_green=0;
total_blue=0;
s=s1+1;
s=s0;
Emboss(-1); Emboss(-2); Emboss( 0);
s=s1;
Emboss(-2); Emboss( 0); Emboss( 2);
s=s2;
Emboss( 0); Emboss( 2); Emboss( 1);
total_red+=(MaxRGB+1) >> 1;
q->red=(Quantum)
((total_red < 0) ? 0 : (total_red > MaxRGB) ? MaxRGB : total_red);
total_green+=(MaxRGB+1) >> 1;
q->green=(Quantum)
((total_green < 0) ? 0 : (total_green > MaxRGB) ? MaxRGB : total_green);
total_blue+=(MaxRGB+1) >> 1;
q->blue=(Quantum)
((total_blue < 0) ? 0 : (total_blue > MaxRGB) ? MaxRGB : total_blue);
q->index=s1->index;
q->length=0;
q++;
s0++;
s1++;
s2++;
}
*q++=(*(q-1));
ProgressMonitor(EmbossImageText,y,image->rows-1);
}
/*
Dump last scanline of pixels.
*/
for (x=0; x < image->columns; x++)
{
q->red=0;
q->green=0;
q->blue=0;
q->index=0;
q->length=0;
q++;
}
free((char *) scanline);
/*
Convert image to grayscale and normalize.
*/
embossed_image->class=DirectClass;
(void) IsGrayImage(embossed_image);
NormalizeImage(embossed_image);
return(embossed_image);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% E n h a n c e I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function EnhanceImage creates a new image that is a copy of an existing
% one with the noise minified. It allocates the memory necessary for the new
% Image structure and returns a pointer to the new image.
%
% EnhanceImage does a weighted average of pixels in a 5x5 cell around each
% target pixel. Only pixels in the 5x5 cell that are within a RGB distance
% threshold of the target pixel are averaged.
%
% Weights assume that the importance of neighboring pixels is negately
% proportional to the square of their distance from the target pixel.
%
% The scan only processes pixels that have a full set of neighbors. Pixels
% in the top, bottom, left, and right pairs of rows and columns are omitted
% from the scan.
%
% The format of the EnhanceImage routine is:
%
% enhanced_image=EnhanceImage(image)
%
% A description of each parameter follows:
%
% o enhanced_image: Function EnhanceImage returns a pointer to the image
% after it is enhanced. A null image is returned if there is a memory
% shortage.
%
% o image: The address of a structure of type Image; returned from
% ReadImage.
%
%
*/
Image *EnhanceImage(Image *image)
{
#define Enhance(weight) \
distance=(int) s->red-(int) red; \
distance_squared=squares[distance]; \
distance=(int) s->green-(int) green; \
distance_squared+=squares[distance]; \
distance=(int) s->blue-(int) blue; \
distance_squared+=squares[distance]; \
if (distance_squared < Threshold) \
{ \
total_red+=(weight)*(s->red); \
total_green+=(weight)*(s->green); \
total_blue+=(weight)*(s->blue); \
total_weight+=(weight); \
} \
s++;
#define EnhanceImageText " Enhancing image... "
#define Threshold 2500
double
distance_squared;
Image
*enhanced_image;
int
distance,
i;
Quantum
blue,
green,
red;
register RunlengthPacket
*p,
*q,
*s,
*s0,
*s1,
*s2,
*s3,
*s4;
register unsigned int
*squares;
RunlengthPacket
*scanline;
unsigned int
x,
y;
unsigned long
total_blue,
total_green,
total_red,
total_weight;
assert(image != (Image *) NULL);
if ((image->columns < 5) || (image->rows < 5))
{
Warning("Unable to enhance image","image size must exceed 4x4");
return((Image *) NULL);
}
/*
Initialize enhanced image attributes.
*/
enhanced_image=CloneImage(image,image->columns,image->rows,False);
if (enhanced_image == (Image *) NULL)
{
Warning("Unable to enhance image","Memory allocation failed");
return((Image *) NULL);
}
enhanced_image->class=DirectClass;
/*
Allocate scan line buffer for 5 rows of the image.
*/
scanline=(RunlengthPacket *) malloc(5*image->columns*sizeof(RunlengthPacket));
squares=(unsigned int *) malloc((MaxRGB+MaxRGB+1)*sizeof(unsigned int));
if ((scanline == (RunlengthPacket *) NULL) ||
(squares == (unsigned int *) NULL))
{
Warning("Unable to enhance image","Memory allocation failed");
DestroyImage(enhanced_image);
return((Image *) NULL);
}
squares+=MaxRGB;
for (i=(-MaxRGB); i <= MaxRGB; i++)
squares[i]=i*i;
/*
Read the first 4 rows of the image.
*/
p=image->pixels;
image->runlength=p->length+1;
s=scanline;
for (x=0; x < (image->columns*4); x++)
{
if (image->runlength != 0)
image->runlength--;
else
{
p++;
image->runlength=p->length;
}
*s=(*p);
s++;
}
/*
Dump first 2 scanlines of image.
*/
q=enhanced_image->pixels;
s=scanline;
for (x=0; x < (image->columns << 1); x++)
{
*q=(*s);
q->length=0;
q++;
s++;
}
/*
Enhance each row.
*/
for (y=2; y < (image->rows-2); y++)
{
/*
Initialize sliding window pointers.
*/
s0=scanline+image->columns*((y-2) % 5);
s1=scanline+image->columns*((y-1) % 5);
s2=scanline+image->columns*(y % 5);
s3=scanline+image->columns*((y+1) % 5);
s4=scanline+image->columns*((y+2) % 5);
/*
Read another scan line.
*/
s=s4;
for (x=0; x < image->columns; x++)
{
if (image->runlength != 0)
image->runlength--;
else
{
p++;
image->runlength=p->length;
}
*s=(*p);
s++;
}
/*
Transfer first 2 pixels of the scanline.
*/
s=s2;
for (x=0; x < 2; x++)
{
*q=(*s);
q->length=0;
q++;
s++;
}
for (x=2; x < (image->columns-2); x++)
{
/*
Compute weighted average of target pixel color components.
*/
total_red=0;
total_green=0;
total_blue=0;
total_weight=0;
s=s2+2;
red=s->red;
green=s->green;
blue=s->blue;
s=s0;
Enhance(5); Enhance(8); Enhance(10); Enhance(8); Enhance(5);
s=s1;
Enhance(8); Enhance(20); Enhance(40); Enhance(20); Enhance(8);
s=s2;
Enhance(10); Enhance(40); Enhance(80); Enhance(40); Enhance(10);
s=s3;
Enhance(8); Enhance(20); Enhance(40); Enhance(20); Enhance(8);
s=s4;
Enhance(5); Enhance(8); Enhance(10); Enhance(8); Enhance(5);
q->red=(Quantum) ((total_red+(total_weight >> 1)-1)/total_weight);
q->green= (Quantum) ((total_green+(total_weight >> 1)-1)/total_weight);
q->blue=(Quantum) ((total_blue+(total_weight >> 1)-1)/total_weight);
q->index=s2->index;
q->length=0;
q++;
s0++;
s1++;
s2++;
s3++;
s4++;
}
/*
Transfer last 2 pixels of the scanline.
*/
s=s2;
for (x=0; x < 2; x++)
{
*q=(*s);
q->length=0;
q++;
s++;
}
ProgressMonitor(EnhanceImageText,y,image->rows-2);
}
/*
Dump last 2 scanlines of pixels.
*/
s=scanline+image->columns*(y % 5);
for (x=0; x < (image->columns << 1); x++)
{
*q=(*s);
q->length=0;
q++;
s++;
}
squares-=MaxRGB;
free((char *) squares);
free((char *) scanline);
return(enhanced_image);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% I m p l o d e I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function ImplodeImage creates a new image that is a copy of an existing
% one with the image pixels "imploded" by the specified percentage. It
% allocates the memory necessary for the new Image structure and returns a
% pointer to the new image.
%
% The format of the ImplodeImage routine is:
%
% imploded_image=ImplodeImage(image,factor)
%
% A description of each parameter follows:
%
% o imploded_image: Function ImplodeImage returns a pointer to the image
% after it is imploded. A null image is returned if there is a memory
% shortage.
%
% o image: The address of a structure of type Image; returned from
% ReadImage.
%
% o factor: An double value that defines the extent of the implosion.
%
%
*/
Image *ImplodeImage(Image *image,double factor)
{
#define ImplodeImageText " Imploding image... "
double
amount,
distance,
radius,
x_center,
x_distance,
x_scale,
y_center,
y_distance,
y_scale;
Image
*imploded_image;
register RunlengthPacket
*p,
*q;
register unsigned int
x;
unsigned int
y;
assert(image != (Image *) NULL);
if (!UncompressImage(image))
return((Image *) NULL);
/*
Initialize imploded image attributes.
*/
imploded_image=CloneImage(image,image->columns,image->rows,False);
if (imploded_image == (Image *) NULL)
{
Warning("Unable to implode image","Memory allocation failed");
return((Image *) NULL);
}
imploded_image->class=DirectClass;
/*
Compute scaling factor.
*/
x_scale=1.0;
y_scale=1.0;
x_center=(double) image->columns/2.0;
y_center=(double) image->rows/2.0;
radius=x_center;
if (image->columns > image->rows)
y_scale=image->columns/image->rows;
else
if (image->columns < image->rows)
{
x_scale=image->rows/image->columns;
radius=y_center;
}
amount=factor/10.0;
if (amount >= 0)
amount/=10.0;
/*
Implode each row.
*/
p=image->pixels;
q=imploded_image->pixels;
for (y=0; y < image->rows; y++)
{
for (x=0; x < image->columns; x++)
{
/*
Determine if the pixel is within an ellipse.
*/
x_distance=x_scale*((double) x-x_center);
y_distance=y_scale*((double) y-y_center);
distance=x_distance*x_distance+y_distance*y_distance;
if (distance >= radius*radius)
*q=(*p);
else
{
/*
Implode the pixel.
*/
factor=pow(sin(M_PI*0.5*sqrt(distance)/radius),-amount);
*q=Interpolate(image,p,factor*x_distance/x_scale+x_center,
factor*y_distance/y_scale+y_center);
}
p++;
q++;
}
ProgressMonitor(ImplodeImageText,y,image->rows);
}
return(imploded_image);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% O i l P a i n t I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function OilPaintImage creates a new image that is a copy of an existing
% one with each pixel component replaced with the color of greatest frequency
% in a circular neighborhood.
%
% The format of the OilPaintImage routine is:
%
% painted_image=OilPaintImage(image,radius)
%
% A description of each parameter follows:
%
% o painted_image: Function OilPaintImage returns a pointer to the image
% after it is `painted'. A null image is returned if there is a memory
% shortage.
%
% o image: The address of a structure of type Image; returned from
% ReadImage.
%
% o radius: An unsigned int that is the radius of the circular
% neighborhood.
%
%
*/
Image *OilPaintImage(Image *image,const unsigned int radius)
{
#define OilPaintImageText " Oil painting image... "
Image
*painted_image;
int
count,
k;
register int
i,
j;
register RunlengthPacket
*p,
*q,
*s;
register unsigned int
x;
unsigned int
*histogram,
y;
assert(image != (Image *) NULL);
if ((image->columns < (radius << 1)) || (image->rows < (radius << 1)))
{
Warning("Unable to oil paint","the image size must exceed mask radius");
return((Image *) NULL);
}
if (!UncompressImage(image))
return((Image *) NULL);
/*
Initialize painted image attributes.
*/
painted_image=CloneImage(image,image->columns,image->rows,False);
if (painted_image == (Image *) NULL)
{
Warning("Unable to oil paint","Memory allocation failed");
return((Image *) NULL);
}
/*
Allocate histogram and scanline.
*/
histogram=(unsigned int *) malloc((MaxRGB+1)*sizeof(unsigned int));
if (histogram == (unsigned int *) NULL)
{
Warning("Unable to oil paint","Memory allocation failed");
DestroyImage(painted_image);
return((Image *) NULL);
}
/*
Paint each row of the image.
*/
p=image->pixels;
q=painted_image->pixels;
for (y=0; y < image->rows; y++)
{
for (x=0; x < image->columns; x++)
{
if ((y < radius) || (y >= (image->rows-radius)) ||
(x < radius) || (x >= (image->columns-radius)))
{
*q++=(*p++);
continue;
}
/*
Determine most frequent color.
*/
count=0;
for (i=0; i < (MaxRGB+1); i++)
histogram[i]=0;
for (i=0; i < radius; i++)
{
s=p-(radius-i)*image->columns-1-i;
for (j=0; j < (i+i+1); j++)
{
k=Intensity(*s);
histogram[k]++;
if (histogram[k] > count)
{
*q=(*s);
count=histogram[k];
}
s++;
}
s=p+(radius-i)*image->columns-1-i;
for (j=0; j < (i+i+1); j++)
{
k=Intensity(*s);
histogram[k]++;
if (histogram[k] > count)
{
*q=(*s);
count=histogram[k];
}
s++;
}
}
s=p-radius;
for (j=0; j < (radius+radius+1); j++)
{
k=Intensity(*s);
histogram[k]++;
if (histogram[k] > count)
{
*q=(*s);
count=histogram[k];
}
s++;
}
q++;
p++;
}
ProgressMonitor(OilPaintImageText,y,image->rows);
}
free((char *) histogram);
return(painted_image);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% P l a s m a I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function PlasmaImage initializes an image with plasma fractal values. The
% image must be initialized with a base color and the random number generator
% seeded before this routine is called.
%
% The format of the PlasmaImage routine is:
%
% status=PlasmaImage(image,segment_info,attenuate,depth)
%
% A description of each parameter follows:
%
% o status: Function PlasmaImage returns True when the fractal process
% is complete. Otherwise False is returned.
%
% o image: The address of a structure of type Image; returned from
% ReadImage.
%
% o segment_info: specifies a structure of type SegmentInfo that defines
% the boundaries of the area where the plasma fractals are applied.
%
% o attenuate: specifies the plasma attentuation factor.
%
% o depth: this integer values define the plasma recursion depth.
%
%
*/
static Quantum PlasmaPixel(Quantum pixel,double noise)
{
double
value;
value=(double) pixel+(noise/2.0)-((int) noise ? (rand() % (int) noise) : 0.0);
if (value < 0.0)
return(0);
if (value > MaxRGB)
return(MaxRGB);
return((Quantum) (value+0.5));
}
unsigned int PlasmaImage(Image *image,SegmentInfo *segment_info,int attenuate,
int depth)
{
double
plasma;
int
x_mid,
y_mid;
register RunlengthPacket
*p,
*q,
*r;
assert(image != (Image *) NULL);
if (image->packets != (image->columns*image->rows))
if (!UncompressImage(image))
return(True);
if (depth != 0)
{
SegmentInfo
local_info;
/*
Divide the area into quadrants and recurse.
*/
depth--;
attenuate++;
x_mid=(segment_info->x1+segment_info->x2) >> 1;
y_mid=(segment_info->y1+segment_info->y2) >> 1;
local_info=(*segment_info);
local_info.x2=x_mid;
local_info.y2=y_mid;
(void) PlasmaImage(image,&local_info,attenuate,depth);
local_info=(*segment_info);
local_info.y1=y_mid;
local_info.x2=x_mid;
(void) PlasmaImage(image,&local_info,attenuate,depth);
local_info=(*segment_info);
local_info.x1=x_mid;
local_info.y2=y_mid;
(void) PlasmaImage(image,&local_info,attenuate,depth);
local_info=(*segment_info);
local_info.x1=x_mid;
local_info.y1=y_mid;
return(PlasmaImage(image,&local_info,attenuate,depth));
}
x_mid=(segment_info->x1+segment_info->x2)/2;
y_mid=(segment_info->y1+segment_info->y2)/2;
if ((segment_info->x1 == x_mid) && (segment_info->x2 == x_mid) &&
(segment_info->y1 == y_mid) && (segment_info->y2 == y_mid))
return(False);
/*
Average pixels and apply plasma.
*/
plasma=(MaxRGB+1)/(2.0*(float) attenuate);
if ((segment_info->x1 != x_mid) || (segment_info->x2 != x_mid))
{
/*
Left pixel.
*/
p=PixelOffset(segment_info->x1,segment_info->y1);
q=PixelOffset(segment_info->x1,segment_info->y2);
r=PixelOffset(segment_info->x1,y_mid);
r->red=PlasmaPixel((p->red+q->red)/2,plasma);
r->green=PlasmaPixel((p->green+q->green)/2,plasma);
r->blue=PlasmaPixel((p->blue+q->blue)/2,plasma);
if (segment_info->x1 != segment_info->x2)
{
/*
Right pixel.
*/
p=PixelOffset(segment_info->x2,segment_info->y1);
q=PixelOffset(segment_info->x2,segment_info->y2);
r=PixelOffset(segment_info->x2,y_mid);
r->red=PlasmaPixel((p->red+q->red)/2,plasma);
r->green=PlasmaPixel((p->green+q->green)/2,plasma);
r->blue=PlasmaPixel((p->blue+q->blue)/2,plasma);
}
}
if ((segment_info->y1 != y_mid) || (segment_info->y2 != y_mid))
{
if ((segment_info->x1 != x_mid) || (segment_info->y2 != y_mid))
{
/*
Bottom pixel.
*/
p=PixelOffset(segment_info->x1,segment_info->y2);
q=PixelOffset(segment_info->x2,segment_info->y2);
r=PixelOffset(x_mid,segment_info->y2);
r->red=PlasmaPixel((p->red+q->red)/2,plasma);
r->green=PlasmaPixel((p->green+q->green)/2,plasma);
r->blue=PlasmaPixel((p->blue+q->blue)/2,plasma);
}
if (segment_info->y1 != segment_info->y2)
{
/*
Top pixel.
*/
p=PixelOffset(segment_info->x1,segment_info->y1);
q=PixelOffset(segment_info->x2,segment_info->y1);
r=PixelOffset(x_mid,segment_info->y1);
r->red=PlasmaPixel((p->red+q->red)/2,plasma);
r->green=PlasmaPixel((p->green+q->green)/2,plasma);
r->blue=PlasmaPixel((p->blue+q->blue)/2,plasma);
}
}
if ((segment_info->x1 != segment_info->x2) ||
(segment_info->y1 != segment_info->y2))
{
/*
Middle pixel.
*/
p=PixelOffset(segment_info->x1,segment_info->y1);
q=PixelOffset(segment_info->x2,segment_info->y2);
r=PixelOffset(x_mid,y_mid);
r->red=PlasmaPixel((p->red+q->red)/2,plasma);
r->green=PlasmaPixel((p->green+q->green)/2,plasma);
r->blue=PlasmaPixel((p->blue+q->blue)/2,plasma);
p=PixelOffset(segment_info->x1,segment_info->y2);
q=PixelOffset(segment_info->x2,segment_info->y1);
r->red=PlasmaPixel((p->red+q->red)/2,plasma);
r->green=PlasmaPixel((p->green+q->green)/2,plasma);
r->blue=PlasmaPixel((p->blue+q->blue)/2,plasma);
}
if (((segment_info->x2-segment_info->x1) < 3) &&
((segment_info->y2-segment_info->y1) < 3))
return(True);
return(False);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% R a i s e I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function RaiseImage lightens and darkens the edges of an image to give a
% 3-D raised or lower effect.
%
% The format of the RaiseImage routine is:
%
% RaiseImage(image,raise_info,raised)
%
% A description of each parameter follows:
%
% o image: The address of a structure of type Image.
%
% o raise_info: Specifies a pointer to a XRectangle which defines the
% raised region.
%
% o raised: A value other than zero causes the image to have a 3-D raised
% effect, otherwise it has a lowered effect.
%
%
*/
void RaiseImage(Image *image,RectangleInfo *raise_info,const int raised)
{
#define AccentuateFactor UpScale(135)
#define HighlightFactor UpScale(190)
#define ShadowFactor UpScale(190)
#define RaiseImageText " Raising image... "
#define TroughFactor UpScale(135)
Quantum
foreground,
background;
register int
x,
y;
register RunlengthPacket
*p;
unsigned int
height;
assert(image != (Image *) NULL);
assert(raise_info != (RectangleInfo *) NULL);
if ((image->columns < (raise_info->width << 1)) &&
(image->rows < (raise_info->height << 1)))
{
Warning("Unable to raise image","image size must exceed bevel width");
return;
}
if (!UncompressImage(image))
return;
foreground=MaxRGB;
background=0;
if (!raised)
{
foreground=0;
background=MaxRGB;
}
image->class=DirectClass;
p=image->pixels;
for (y=0; y < raise_info->height; y++)
{
for (x=0; x < y; x++)
{
p->red=(unsigned int) (p->red*HighlightFactor+foreground*
(MaxRGB-HighlightFactor))/MaxRGB;
p->green=(unsigned int) (p->green*HighlightFactor+foreground*
(MaxRGB-HighlightFactor))/MaxRGB;
p->blue=(unsigned int) (p->blue*HighlightFactor+foreground*
(MaxRGB-HighlightFactor))/MaxRGB;
p++;
}
for (x=0; x < (int) (image->columns-(y << 1)); x++)
{
p->red=(unsigned int) (p->red*AccentuateFactor+foreground*
(MaxRGB-AccentuateFactor))/MaxRGB;
p->green=(unsigned int) (p->green*AccentuateFactor+foreground*
(MaxRGB-AccentuateFactor))/MaxRGB;
p->blue=(unsigned int) (p->blue*AccentuateFactor+foreground*
(MaxRGB-AccentuateFactor))/MaxRGB;
p++;
}
for (x=0; x < y; x++)
{
p->red=(unsigned int)
(p->red*ShadowFactor+background*(MaxRGB-ShadowFactor))/MaxRGB;
p->green=(unsigned int)
(p->green*ShadowFactor+background*(MaxRGB-ShadowFactor))/MaxRGB;
p->blue=(unsigned int)
(p->blue*ShadowFactor+background*(MaxRGB-ShadowFactor))/MaxRGB;
p++;
}
}
height=image->rows-(raise_info->height << 1);
for (y=0; y < height; y++)
{
for (x=0; x < raise_info->width; x++)
{
p->red=(unsigned int) (p->red*HighlightFactor+foreground*
(MaxRGB-HighlightFactor))/MaxRGB;
p->green=(unsigned int) (p->green*HighlightFactor+foreground*
(MaxRGB-HighlightFactor))/MaxRGB;
p->blue=(unsigned int) (p->blue*HighlightFactor+foreground*
(MaxRGB-HighlightFactor))/MaxRGB;
p++;
}
for (x=0; x < (int) (image->columns-(raise_info->width << 1)); x++)
p++;
for (x=0; x < raise_info->width; x++)
{
p->red=(unsigned int)
(p->red*ShadowFactor+background*(MaxRGB-ShadowFactor))/MaxRGB;
p->green=(unsigned int)
(p->green*ShadowFactor+background*(MaxRGB-ShadowFactor))/MaxRGB;
p->blue=(unsigned int)
(p->blue*ShadowFactor+background*(MaxRGB-ShadowFactor))/MaxRGB;
p++;
}
ProgressMonitor(RaiseImageText,y,height);
}
for (y=0; y < raise_info->height; y++)
{
for (x=0; x < (int) (raise_info->width-y); x++)
{
p->red=(unsigned int) (p->red*HighlightFactor+foreground*
(MaxRGB-HighlightFactor))/MaxRGB;
p->green=(unsigned int) (p->green*HighlightFactor+foreground*
(MaxRGB-HighlightFactor))/MaxRGB;
p->blue=(unsigned int) (p->blue*HighlightFactor+foreground*
(MaxRGB-HighlightFactor))/MaxRGB;
p++;
}
for (x=0; x < (int) (image->columns-((raise_info->width-y) << 1)); x++)
{
p->red=(unsigned int)
(p->red*TroughFactor+background*(MaxRGB-TroughFactor))/MaxRGB;
p->green=(unsigned int)
(p->green*TroughFactor+background*(MaxRGB-TroughFactor))/MaxRGB;
p->blue=(unsigned int)
(p->blue*TroughFactor+background*(MaxRGB-TroughFactor))/MaxRGB;
p++;
}
for (x=0; x < (int) (raise_info->width-y); x++)
{
p->red=(unsigned int)
(p->red*ShadowFactor+background*(MaxRGB-ShadowFactor))/MaxRGB;
p->green=(unsigned int)
(p->green*ShadowFactor+background*(MaxRGB-ShadowFactor))/MaxRGB;
p->blue=(unsigned int)
(p->blue*ShadowFactor+background*(MaxRGB-ShadowFactor))/MaxRGB;
p++;
}
}
return;
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% R e d u c e N o i s e I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function ReduceNoiseImage creates a new image that is a copy of an existing
% one with the noise minified with a noise peak elimination filter. It
% allocates the memory necessary for the new Image structure and returns a
% pointer to the new image.
%
% The principal function of noise peak elimination filter is to smooth the
% objects within an image without losing edge information and without
% creating undesired structures. The central idea of the algorithm is to
% replace a pixel with its next neighbor in value within a 3 x 3 window,
% if this pixel has been found to be noise. A pixel is defined as noise
% if and only if this pixel is a maximum or minimum within the 3 x 3
% window.
%
% The format of the ReduceNoiseImage routine is:
%
% noisy_image=ReduceNoiseImage(image)
%
% A description of each parameter follows:
%
% o noisy_image: Function ReduceNoiseImage returns a pointer to the image
% after the noise is minified. A null image is returned if there is a
% memory shortage.
%
% o image: The address of a structure of type Image; returned from
% ReadImage.
%
%
*/
static int ReduceNoiseCompare(const void *x,const void *y)
{
ColorPacket
*color_1,
*color_2;
color_1=(ColorPacket *) x;
color_2=(ColorPacket *) y;
return((int) Intensity(*color_1)-(int) Intensity(*color_2));
}
Image *ReduceNoiseImage(Image *image)
{
#define ReduceNoiseImageText " Reducing the image noise... "
Image
*noisy_image;
int
i;
register RunlengthPacket
*p,
*q,
*s,
*s0,
*s1,
*s2;
register unsigned int
x;
RunlengthPacket
pixel,
*scanline,
window[9];
unsigned int
y;
assert(image != (Image *) NULL);
if ((image->columns < 3) || (image->rows < 3))
{
Warning("Unable to reduce noise","the image size must exceed 2x2");
return((Image *) NULL);
}
/*
Initialize noisy image attributes.
*/
noisy_image=CloneImage(image,image->columns,image->rows,False);
if (noisy_image == (Image *) NULL)
{
Warning("Unable to reduce noise","Memory allocation failed");
return((Image *) NULL);
}
/*
Allocate scanline buffer for 3 rows of the image.
*/
scanline=(RunlengthPacket *) malloc(3*image->columns*sizeof(RunlengthPacket));
if (scanline == (RunlengthPacket *) NULL)
{
Warning("Unable to reduce noise","Memory allocation failed");
DestroyImage(noisy_image);
return((Image *) NULL);
}
/*
Preload the first 2 rows of the image.
*/
p=image->pixels;
image->runlength=p->length+1;
s=scanline;
for (x=0; x < (image->columns << 1); x++)
{
if (image->runlength != 0)
image->runlength--;
else
{
p++;
image->runlength=p->length;
}
*s=(*p);
s++;
}
/*
Dump first scanline of image.
*/
q=noisy_image->pixels;
s=scanline;
for (x=0; x < image->columns; x++)
{
*q=(*s);
q->length=0;
q++;
s++;
}
/*
Reduce noise in each row.
*/
for (y=1; y < (image->rows-1); y++)
{
/*
Initialize sliding window pointers.
*/
s0=scanline+image->columns*((y-1) % 3);
s1=scanline+image->columns*(y % 3);
s2=scanline+image->columns*((y+1) % 3);
/*
Read another scan line.
*/
s=s2;
for (x=0; x < image->columns; x++)
{
if (image->runlength != 0)
image->runlength--;
else
{
p++;
image->runlength=p->length;
}
*s=(*p);
s++;
}
/*
Transfer first pixel of the scanline.
*/
s=s1;
*q=(*s);
q->length=0;
q++;
for (x=1; x < (image->columns-1); x++)
{
/*
Sort window pixels by increasing intensity.
*/
s=s0;
window[0]=(*s++);
window[1]=(*s++);
window[2]=(*s++);
s=s1;
window[3]=(*s++);
window[4]=(*s++);
window[5]=(*s++);
s=s2;
window[6]=(*s++);
window[7]=(*s++);
window[8]=(*s++);
pixel=window[4];
qsort((void *) window,9,sizeof(RunlengthPacket),
(int (*)(const void *, const void *)) ReduceNoiseCompare);
if (Intensity(pixel) == Intensity(window[0]))
{
/*
Pixel is minimum noise; replace with next neighbor in value.
*/
for (i=1; i < 8; i++)
if (Intensity(window[i]) != Intensity(window[0]))
break;
pixel=window[i];
}
else
if (Intensity(pixel) == Intensity(window[8]))
{
/*
Pixel is maximum noise; replace with next neighbor in value.
*/
for (i=7; i > 0; i--)
if (Intensity(window[i]) != Intensity(window[8]))
break;
pixel=window[i];
}
*q=pixel;
q->length=0;
q++;
s0++;
s1++;
s2++;
}
/*
Transfer last pixel of the scanline.
*/
s=s1;
*q=(*s);
q->length=0;
q++;
ProgressMonitor(ReduceNoiseImageText,y,image->rows-1);
}
/*
Dump last scanline of pixels.
*/
s=scanline+image->columns*(y % 3);
for (x=0; x < image->columns; x++)
{
*q=(*s);
q->length=0;
q++;
s++;
}
free((char *) scanline);
return(noisy_image);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% S h a d e I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function ShadeImage creates a new image that is a copy of an existing
% one with the image pixels shaded using a distance light source. It
% allocates the memory necessary for the new Image structure and returns a
% pointer to the new image.
%
% The format of the ShadeImage routine is:
%
% shaded_image=ShadeImage(image,color_shading,azimuth,elevation)
%
% A description of each parameter follows:
%
% o shaded_image: Function ShadeImage returns a pointer to the image
% after it is shaded. A null image is returned if there is a memory
% shortage.
%
% o image: The address of a structure of type Image; returned from
% ReadImage.
%
% o color_shading: A value other than zero shades the red, green, and blue
% components of the image.
%
% o azimuth, elevation: A double value that indicates the light source
% direction.
%
%
*/
Image *ShadeImage(Image *image,unsigned int color_shading,double azimuth,
double elevation)
{
#define ShadeImageText " Shading image... "
typedef struct _VectorPacket
{
long
x,
y,
z;
} VectorPacket;
double
distance,
normal_distance;
Image
*shaded_image;
int
y;
long
shade;
register int
i,
x;
register RunlengthPacket
*p,
*q,
*s0,
*s1,
*s2;
VectorPacket
light,
normal;
assert(image != (Image *) NULL);
if (!UncompressImage(image))
return((Image *) NULL);
/*
Initialize shaded image attributes.
*/
shaded_image=CloneImage(image,image->columns,image->rows,False);
if (shaded_image == (Image *) NULL)
{
Warning("Unable to shade image","Memory allocation failed");
return((Image *) NULL);
}
shaded_image->class=DirectClass;
if (!color_shading)
{
/*
Initialize shaded image colormap.
*/
shaded_image->class=PseudoClass;
shaded_image->colors=MaxRGB+1;
if (shaded_image->colormap != (ColorPacket *) NULL)
free((char *) shaded_image->colormap);
shaded_image->colormap=(ColorPacket *)
malloc(shaded_image->colors*sizeof(ColorPacket));
if (shaded_image->colormap == (ColorPacket *) NULL)
{
Warning("Unable to shade image","Memory allocation failed");
DestroyImage(shaded_image);
return((Image *) NULL);
}
for (i=0; i < shaded_image->colors; i++)
{
shaded_image->colormap[i].red=(Quantum) i;
shaded_image->colormap[i].green=(Quantum) i;
shaded_image->colormap[i].blue=(Quantum) i;
}
}
/*
Compute the light vector.
*/
azimuth=DegreesToRadians(azimuth);
elevation=DegreesToRadians(elevation);
light.x=(long) (MaxRGB*cos(azimuth)*cos(elevation));
light.y=(long) (MaxRGB*sin(azimuth)*cos(elevation));
light.z=(long) (MaxRGB*sin(elevation));
normal.z=(long) ((6.0*MaxRGB)/3.0); /* constant Z of surface normal */
/*
Shade image.
*/
p=image->pixels;
q=shaded_image->pixels;
for (y=0; y < image->rows; y++)
{
for (x=0; x < image->columns; x++)
{
s0=p-image->columns;
s1=p;
s2=p+image->columns;
while (s0 <= image->pixels)
{
s0+=image->columns;
s1+=image->columns;
s2+=image->columns;
}
while (s2 >= (image->pixels+image->packets-1))
{
s0-=image->columns;
s1-=image->columns;
s2-=image->columns;
}
/*
Determine the surface normal and compute shading.
*/
normal.x=(long) (Intensity(*(s0-1))+Intensity(*(s1-1))+
Intensity(*(s2-1))-Intensity(*(s0+1))-Intensity(*(s1+1))-
Intensity(*(s2+1)));
normal.y=(long) (Intensity(*(s2-1))+Intensity(*s2)+Intensity(*(s2+1))-
Intensity(*(s0-1))-Intensity(*s0)-Intensity(*(s0+1)));
if ((normal.x == 0) && (normal.y == 0))
shade=(Quantum) light.z;
else
{
shade=0;
distance=(double)
(normal.x*light.x+normal.y*light.y+normal.z*light.z);
if (distance > 0)
{
normal_distance=(double)
(normal.x*normal.x+normal.y*normal.y+normal.z*normal.z);
shade=(long) (distance/sqrt(normal_distance));
}
}
if (color_shading)
{
q->red=(Quantum) (((long) p->red*shade) >> QuantumDepth);
q->green=(Quantum) (((long) p->green*shade) >> QuantumDepth);
q->blue=(Quantum) (((long) p->blue*shade) >> QuantumDepth);
}
q->index=p->index;
if (!color_shading)
q->index=(unsigned short) shade;
q->length=0;
p++;
q++;
}
ProgressMonitor(ShadeImageText,y,image->rows);
}
if (!color_shading)
SyncImage(shaded_image);
return(shaded_image);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% S h a r p e n I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function SharpenImage creates a new image that is a copy of an existing
% one with the pixels sharpened. It allocates the memory necessary for the
% new Image structure and returns a pointer to the new image.
%
% SharpenImage convolves the pixel neighborhood with this sharpening mask:
%
% -1 -2 -1
% -2 W -2
% -1 -2 -1
%
% The scan only processes pixels that have a full set of neighbors. Pixels
% in the top, bottom, left, and right pairs of rows and columns are omitted
% from the scan.
%
% The format of the SharpenImage routine is:
%
% sharpened_image=SharpenImage(image,factor)
%
% A description of each parameter follows:
%
% o sharpened_image: Function SharpenImage returns a pointer to the image
% after it is sharpened. A null image is returned if there is a memory
% shortage.
%
% o image: The address of a structure of type Image; returned from
% ReadImage.
%
% o factor: An double value reflecting the percent weight to give to the
% center pixel of the neighborhood.
%
%
*/
Image *SharpenImage(Image *image,double factor)
{
#define Sharpen(weight) \
total_red+=(weight)*(int) (s->red); \
total_green+=(weight)*(int) (s->green); \
total_blue+=(weight)*(int) (s->blue); \
total_index+=(weight)*(int) (s->index); \
s++;
#define SharpenImageText " Sharpening image... "
Image
*sharpened_image;
long
total_blue,
total_green,
total_index,
total_red,
weight;
register RunlengthPacket
*p,
*q,
*s,
*s0,
*s1,
*s2;
register unsigned int
x;
RunlengthPacket
*scanline;
unsigned int
quantum,
y;
assert(image != (Image *) NULL);
if ((image->columns < 3) || (image->rows < 3))
{
Warning("Unable to sharpen image","image size must exceed 3x3");
return((Image *) NULL);
}
/*
Initialize sharpened image attributes.
*/
sharpened_image=CloneImage(image,image->columns,image->rows,False);
if (sharpened_image == (Image *) NULL)
{
Warning("Unable to enhance image","Memory allocation failed");
return((Image *) NULL);
}
sharpened_image->class=DirectClass;
/*
Allocate scan line buffer for 3 rows of the image.
*/
scanline=(RunlengthPacket *)
malloc(3*(image->columns+1)*sizeof(RunlengthPacket));
if (scanline == (RunlengthPacket *) NULL)
{
Warning("Unable to enhance image","Memory allocation failed");
DestroyImage(sharpened_image);
return((Image *) NULL);
}
/*
Read the first two rows of the image.
*/
p=image->pixels;
image->runlength=p->length+1;
for (x=0; x < (3*(image->columns+1)); x++)
scanline[x]=(*p);
s=scanline;
for (x=0; x < (image->columns << 1); x++)
{
if (image->runlength != 0)
image->runlength--;
else
{
p++;
image->runlength=p->length;
}
*s=(*p);
s++;
}
/*
Dump first scanline of image.
*/
q=sharpened_image->pixels;
s=scanline;
for (x=0; x < image->columns; x++)
{
*q=(*s++);
q->length=0;
q++;
}
/*
Convolve each row.
*/
weight=(long) ((100.0-factor)/2+13);
quantum=(unsigned int) Max(weight-12,1);
for (y=1; y < (image->rows-1); y++)
{
/*
Initialize sliding window pointers.
*/
s0=scanline+image->columns*((y-1) % 3);
s1=scanline+image->columns*(y % 3);
s2=scanline+image->columns*((y+1) % 3);
/*
Read another scan line.
*/
s=s2;
for (x=0; x < image->columns; x++)
{
if (image->runlength != 0)
image->runlength--;
else
{
p++;
image->runlength=p->length;
}
*s=(*p);
s++;
}
/*
Transfer first pixel of the scanline.
*/
*q=(*s1);
q->length=0;
q++;
for (x=1; x < (image->columns-1); x++)
{
/*
Compute weighted average of target pixel color components.
*/
total_red=0;
total_green=0;
total_blue=0;
total_index=0;
s=s0;
Sharpen(-1); Sharpen(-2); Sharpen(-1);
s=s1;
Sharpen(-2); Sharpen(weight); Sharpen(-2);
s=s2;
Sharpen(-1); Sharpen(-2); Sharpen(-1);
if (total_red < 0)
q->red=0;
else
if (total_red > (MaxRGB*quantum))
q->red=MaxRGB;
else
q->red=(Quantum) ((total_red+(quantum >> 1))/quantum);
if (total_green < 0)
q->green=0;
else
if (total_green > (MaxRGB*quantum))
q->green=MaxRGB;
else
q->green=(Quantum) ((total_green+(quantum >> 1))/quantum);
if (total_blue < 0)
q->blue=0;
else
if (total_blue > (MaxRGB*quantum))
q->blue=MaxRGB;
else
q->blue=(Quantum) ((total_blue+(quantum >> 1))/quantum);
if (total_index < 0)
q->index=0;
else
if (total_index > (MaxRGB*quantum))
q->index=MaxRGB;
else
q->index=(unsigned short) ((total_index+(quantum >> 1))/quantum);
q->length=0;
q++;
s0++;
s1++;
s2++;
}
/*
Transfer last pixel of the scanline.
*/
s1++;
*q=(*s1);
q->length=0;
q++;
ProgressMonitor(SharpenImageText,y,image->rows-1);
}
/*
Dump last scanline of pixels.
*/
s=scanline+image->columns*(y % 3);
for (x=0; x < image->columns; x++)
{
*q=(*s++);
q->length=0;
q++;
}
free((char *) scanline);
return(sharpened_image);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% S o l a r i z e I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function SolarizeImage produces a 'solarization' effect seen when exposing
% a photographic film to light during the development process.
%
% The format of the SolarizeImage routine is:
%
% SolarizeImage(image,factor)
%
% A description of each parameter follows:
%
% o image: The address of a structure of type Image; returned from
% ReadImage.
%
% o factor: An double value that defines the extent of the solarization.
%
%
*/
void SolarizeImage(Image *image,const double factor)
{
#define SolarizeImageText " Solarizing the image colors... "
register int
i;
register RunlengthPacket
*p;
unsigned int
threshold;
assert(image != (Image *) NULL);
threshold=(unsigned int) (factor*(MaxRGB+1)/100.0);
switch (image->class)
{
case DirectClass:
default:
{
/*
Solarize DirectClass packets.
*/
p=image->pixels;
for (i=0; i < image->packets; i++)
{
p->red=p->red > threshold ? MaxRGB-p->red : p->red;
p->green=p->green > threshold ? MaxRGB-p->green : p->green;
p->blue=p->blue > threshold ? MaxRGB-p->blue : p->blue;
p++;
if (QuantumTick(i,image))
ProgressMonitor(SolarizeImageText,i,image->packets);
}
break;
}
case PseudoClass:
{
/*
Solarize PseudoClass packets.
*/
for (i=0; i < image->colors; i++)
{
image->colormap[i].red=image->colormap[i].red > threshold ?
MaxRGB-image->colormap[i].red : image->colormap[i].red;
image->colormap[i].green=image->colormap[i].green > threshold ?
MaxRGB-image->colormap[i].green : image->colormap[i].green;
image->colormap[i].blue=image->colormap[i].blue > threshold ?
MaxRGB-image->colormap[i].blue : image->colormap[i].blue;
}
SyncImage(image);
break;
}
}
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% S p r e a d I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function SpreadImage creates a new image that is a copy of an existing
% one with the image pixels randomly displaced. It allocates the memory
% necessary for the new Image structure and returns a pointer to the new
% image.
%
% The format of the SpreadImage routine is:
%
% spread_image=SpreadImage(image,amount)
%
% A description of each parameter follows:
%
% o spread_image: Function SpreadImage returns a pointer to the image
% after it is spread. A null image is returned if there is a memory
% shortage.
%
% o image: The address of a structure of type Image; returned from
% ReadImage.
%
% o amount: An unsigned value constraining the "vicintity" for choosing
% a random pixel to swap.
%
%
*/
Image *SpreadImage(Image *image,unsigned int amount)
{
#define SpreadImageText " Spreading image... "
Image
*spread_image;
int
quantum;
long
x_distance,
y_distance;
register RunlengthPacket
*p,
*q;
register unsigned int
x;
unsigned int
y;
assert(image != (Image *) NULL);
if ((image->columns < 3) || (image->rows < 3))
{
Warning("Unable to spread image","image size must exceed 3x3");
return((Image *) NULL);
}
if (!UncompressImage(image))
return((Image *) NULL);
/*
Initialize spread image attributes.
*/
spread_image=CloneImage(image,image->columns,image->rows,True);
if (spread_image == (Image *) NULL)
{
Warning("Unable to enhance image","Memory allocation failed");
return((Image *) NULL);
}
spread_image->class=DirectClass;
/*
Convolve each row.
*/
srand(time((time_t *) NULL));
amount++;
quantum=amount >> 1;
q=spread_image->pixels;
for (y=0; y < image->rows; y++)
{
for (x=0; x < image->columns; x++)
{
x_distance=(rand() & amount)-quantum;
y_distance=(rand() & amount)-quantum;
p=image->pixels+(y+y_distance)*image->columns+(x+x_distance);
if ((p > image->pixels) && (p < (image->pixels+image->packets)))
*q=(*p);
q++;
}
ProgressMonitor(SpreadImageText,y,image->rows);
}
return(spread_image);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% S w i r l I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function SwirlImage creates a new image that is a copy of an existing
% one with the image pixels "swirled" at a specified angle. It allocates the
% memory necessary for the new Image structure and returns a pointer to the
% new image.
%
% The format of the SwirlImage routine is:
%
% swirled_image=SwirlImage(image,degrees)
%
% A description of each parameter follows:
%
% o swirled_image: Function SwirlImage returns a pointer to the image
% after it is swirled. A null image is returned if there is a memory
% shortage.
%
% o image: The address of a structure of type Image; returned from
% ReadImage.
%
% o degrees: An double value that defines the tightness of the swirling.
%
%
*/
Image *SwirlImage(Image *image,double degrees)
{
#define SwirlImageText " Swirling image... "
double
cosine,
distance,
factor,
radius,
sine,
x_center,
x_distance,
x_scale,
y_center,
y_distance,
y_scale;
Image
*swirled_image;
register RunlengthPacket
*p,
*q;
register unsigned int
x;
unsigned int
y;
assert(image != (Image *) NULL);
if (!UncompressImage(image))
return((Image *) NULL);
/*
Initialize swirled image attributes.
*/
swirled_image=CloneImage(image,image->columns,image->rows,False);
if (swirled_image == (Image *) NULL)
{
Warning("Unable to swirl image","Memory allocation failed");
return((Image *) NULL);
}
swirled_image->class=DirectClass;
/*
Compute scaling factor.
*/
x_center=(double) image->columns/2.0;
y_center=(double) image->rows/2.0;
radius=Max(x_center,y_center);
x_scale=1.0;
y_scale=1.0;
if (image->columns > image->rows)
y_scale=image->columns/image->rows;
else
if (image->columns < image->rows)
x_scale=image->rows/image->columns;
degrees=DegreesToRadians(degrees);
/*
Swirl each row.
*/
p=image->pixels;
q=swirled_image->pixels;
for (y=0; y < image->rows; y++)
{
for (x=0; x < image->columns; x++)
{
/*
Determine if the pixel is within an ellipse.
*/
x_distance=x_scale*((double) x-x_center);
y_distance=y_scale*((double) y-y_center);
distance=x_distance*x_distance+y_distance*y_distance;
if (distance >= (radius*radius))
*q=(*p);
else
{
/*
Swirl the pixel.
*/
factor=1.0-sqrt(distance)/radius;
factor*=factor;
sine=sin(degrees*factor);
cosine=cos(degrees*factor);
*q=Interpolate(image,p,
(cosine*x_distance-sine*y_distance)/x_scale+x_center,
(sine*x_distance+cosine*y_distance)/y_scale+y_center);
}
p++;
q++;
}
ProgressMonitor(SwirlImageText,y,image->rows);
}
return(swirled_image);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% W a v e I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function WaveImage creates a new image that is a copy of an existing
% one with the image pixels altered along a sine wave. It allocates the
% memory necessary for the new Image structure and returns a pointer to
% the new image.
%
% The format of the WaveImage routine is:
%
% waved_image=WaveImage(image,amplitude,frequency)
%
% A description of each parameter follows:
%
% o shaded_image: Function WaveImage returns a pointer to the image
% after it is shaded. A null image is returned if there is a memory
% shortage.
%
% o image: The address of a structure of type Image; returned from
% ReadImage.
%
% o amplitude, frequency: A double value that indicates the amplitude
% and wavelength of the sine wave.
%
%
*/
Image *WaveImage(Image *image,double amplitude,double wavelength)
{
#define WaveImageText " Waving image... "
Image
*waved_image;
int
*sine_map,
y;
register int
i,
x;
register RunlengthPacket
*p,
*q;
assert(image != (Image *) NULL);
if (!UncompressImage(image))
return((Image *) NULL);
/*
Initialize waved image attributes.
*/
waved_image=CloneImage(image,image->columns,image->rows+
(int) (2*AbsoluteValue(amplitude)),False);
if (waved_image == (Image *) NULL)
{
Warning("Unable to wave image","Memory allocation failed");
return((Image *) NULL);
}
waved_image->class=DirectClass;
p= waved_image->pixels;
for (i=0; i < waved_image->packets; i++)
{
p->red=image->background_color.red;
p->green=image->background_color.green;
p->blue=image->background_color.blue;
p->index=image->background_color.index;
p->length=0;
p++;
}
/*
Allocate sine map.
*/
sine_map=(int *) malloc(image->columns*sizeof(int));
if (sine_map == (int *) NULL)
{
Warning("Unable to wave image","Memory allocation failed");
DestroyImage(waved_image);
return((Image *) NULL);
}
for (x=0; x < image->columns; x++)
sine_map[x]=(int) (amplitude*sin(((double) x)/wavelength));
/*
Wave image.
*/
amplitude=AbsoluteValue(amplitude);
q=waved_image->pixels;
for (y=0; y < waved_image->rows; y++)
{
for (x=0; x < waved_image->columns; x++)
{
i=(int) (y-amplitude-sine_map[x]);
p=image->pixels+(i*image->columns+x);
if ((i >= 0) && (i < image->rows))
*q=Interpolate(image,p,x,i);
q++;
}
ProgressMonitor(WaveImageText,y,image->rows);
}
free((char *) sine_map);
return(waved_image);
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.