ftp.nice.ch/pub/next/unix/graphics/ImageMagick.3.8.6.s.tar.gz#/ImageMagick/magick/gems.c

This is gems.c in view mode; [Download] [Up]

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%                           GGGG  EEEEE  M   M SSSSS                          %
%                          G      E      MM MM SS                             %
%                          G GG   EEE    M M M  SSS                           %
%                          G   G  E      M   M    SS                          %
%                           GGGG  EEEEE  M   M SSSSS                          %
%                                                                             %
%                                                                             %
%                    Graphic Gems - Graphic Support Routines                  %
%                                                                             %
%                                                                             %
%                                                                             %
%                               Software Design                               %
%                                 John Cristy                                 %
%                                 August 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"

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   C o n s t r a s t                                                         %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function Contrast enhances the intensity differences between the lighter
%  and darker elements of the image.
%
%  The format of the ContrastImage routine is:
%
%      Contrast(sign,red,green,blue)
%
%  A description of each parameter follows:
%
%    o sign: A positive value enhances the contrast otherwise it is reduced.
%
%    o red, green, blue: A pointer to a pixel component of type Quantum.
%
%
*/
void Contrast(const int sign,Quantum *red,Quantum *green,Quantum *blue)
{
  double
    brightness,
    hue,
    saturation,
    theta;

  /*
    Enhance contrast: dark color become darker, light color become lighter.
  */
  assert(red != (Quantum *) NULL);
  assert(green != (Quantum *) NULL);
  assert(blue != (Quantum *) NULL);
  TransformHSL(*red,*green,*blue,&hue,&saturation,&brightness);
  theta=(brightness-0.5)*M_PI;
  brightness+=(((((sin(theta)+1.0))*0.5)-brightness)*sign)*0.5;
  if (brightness > 1.0)
    brightness=1.0;
  else
    if (brightness < 0)
      brightness=0.0;
  HSLTransform(hue,saturation,brightness,red,green,blue);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   G e n e r a t e N o i s e                                                 %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function GenerateNoise adds noise to a pixel.
%
%  The format of the GenerateNoise routine is:
%
%      GenerateNoise(pixel,noise_type)
%
%  A description of each parameter follows:
%
%    o pixel: A structure of type Quantum.
%
%    o noise_type:  The type of noise: gaussian, multiplicative gaussian,
%      impulse, laplacian, or poisson.
%
%
*/
Quantum GenerateNoise(Quantum pixel,NoiseType noise_type)
{
#define NoiseEpsilon  1.0e-5
#define NoiseMask  0x7fff
#define SigmaUniform  4.0
#define SigmaGaussian  4.0
#define SigmaImpulse  0.10
#define SigmaLaplacian 10.0
#define SigmaMultiplicativeGaussian  0.5
#define SigmaPoisson  0.05
#define TauGaussian  20.0

  double
    alpha,
    beta,
    sigma,
    value;

  alpha=(double) (rand() & NoiseMask)/NoiseMask;
  if (alpha == 0.0)
    alpha=1.0;
  switch (noise_type)
  {
    case UniformNoise:
    default:
    {
      value=(double) pixel+SigmaUniform*(alpha-0.5);
      break;
    }
    case GaussianNoise:
    {
      double
        tau;

      beta=(double) (rand() & NoiseMask)/NoiseMask;
      sigma=sqrt(-2.0*log(alpha))*cos(2.0*M_PI*beta);
      tau=sqrt(-2.0*log(alpha))*sin(2.0*M_PI*beta);
      value=(double) pixel+
        (sqrt((double) pixel)*SigmaGaussian*sigma)+(TauGaussian*tau);
      break;
    }
    case MultiplicativeGaussianNoise:
    {
      if (alpha <= NoiseEpsilon)
        sigma=MaxRGB;
      else
        sigma=sqrt(-2.0*log(alpha));
      beta=(rand() & NoiseMask)/NoiseMask;
      value=(double) pixel+
        pixel*SigmaMultiplicativeGaussian*sigma*cos(2.0*M_PI*beta);
      break;
    }
    case ImpulseNoise:
    {
      if (alpha < (SigmaImpulse/2.0))
        value=0;
       else
         if (alpha >= (1.0-(SigmaImpulse/2.0)))
           value=MaxRGB;
         else
           value=pixel;
      break;
    }
    case LaplacianNoise:
    {
      if (alpha <= 0.5)
        {
          if (alpha <= NoiseEpsilon)
            value=(double) pixel-MaxRGB;
          else
            value=(double) pixel+SigmaLaplacian*log(2.0*alpha);
          break;
        }
      beta=1.0-alpha;
      if (beta <= (0.5*NoiseEpsilon))
        value=(double) pixel+MaxRGB;
      else
        value=(double) pixel-SigmaLaplacian*log(2.0*beta);
      break;
    }
    case PoissonNoise:
    {
      register int
        i;

      for (i=0; alpha > exp(-SigmaPoisson*pixel); i++)
      {
        beta=(double) (rand() & NoiseMask)/NoiseMask;
        alpha=alpha*beta;
      }
      value=i/SigmaPoisson;
      break;
    }
  }
  if (value < 0.0)
    return(0);
  if (value > MaxRGB)
    return(MaxRGB);
  return((Quantum) (value+0.5));
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   H S L T r a n s f o r m                                                   %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function HSLTransform converts a (hue, saturation, luminosity) to a
%  (red, green, blue) triple.
%
%  The format of the HSLTransformImage routine is:
%
%      HSLTransform(hue,saturation,luminosity,red,green,blue)
%
%  A description of each parameter follows:
%
%    o hue, saturation, luminosity: A double value representing a
%      component of the HSL color space.
%
%    o red, green, blue: A pointer to a pixel component of type Quantum.
%
%
*/
void HSLTransform(double hue,const double saturation, const double luminosity,
  Quantum *red,Quantum *green,Quantum *blue)
{
  double
    b,
    g,
    r,
    v,
    x,
    y,
    z;

  /*
    Convert HSL to RGB colorspace.
  */
  assert(red != (Quantum *) NULL);
  assert(green != (Quantum *) NULL);
  assert(blue != (Quantum *) NULL);
  v=(luminosity <= 0.5) ? (luminosity*(1.0+saturation)) :
    (luminosity+saturation-luminosity*saturation);
  if (v <= 0)
    {
      *red=0;
      *green=0;
      *blue=0;
      return;
    }
  if (hue == 1.0)
    hue=0.0;
  hue*=6.0;
  y=luminosity+luminosity-v;
  x=y+(v-y)*(hue-(int) hue);
  z=v-(v-y)*(hue-(int) hue);
  switch ((int) hue)
  {
    default: r=v; g=x; b=y; break;
    case 0: r=v; g=x; b=y; break;
    case 1: r=z; g=v; b=y; break;
    case 2: r=y; g=v; b=x; break;
    case 3: r=y; g=z; b=v; break;
    case 4: r=x; g=y; b=v; break;
    case 5: r=v; g=y; b=z; break;
  }
  *red=(Quantum) floor((r*(double) MaxRGB)+0.5);
  *green=(Quantum) floor((g*(double) MaxRGB)+0.5);
  *blue=(Quantum) floor((b*(double) MaxRGB)+0.5);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   H u l l                                                                   %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function Hull implements 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.
%
%  The format of the Hull routine is:
%
%      Hull(x_offset,y_offset,polarity,columns,rows,f,g)
%
%  A description of each parameter follows:
%
%    o x_offset, y_offset: An integer value representing the offset of the
%      current pixel within the image.
%
%    o polarity: An integer value declaring the polarity (+,-).
%
%    o columns, rows: Specifies the number of rows and columns in the image.
%
%    o f, g: A pointer to an image pixel and one of it's neighbor.
%
%
*/
void Hull(int x_offset,int y_offset,int polarity,unsigned int columns,
  unsigned int rows,Quantum *f,Quantum *g)
{
  int
    y;

  register int
    x;

  register Quantum
    *p,
    *q,
    *r,
    *s;

  Quantum
    v;

  assert(f != (Quantum *) NULL);
  assert(g != (Quantum *) NULL);
  p=f+(columns+2);
  q=g+(columns+2);
  r=p+(y_offset*((int) 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 > (Quantum) (*r+1))
          v--;
        *q=v;
        p++;
        q++;
        r++;
      }
    p++;
    q++;
    r++;
  }
  p=f+(columns+2);
  q=g+(columns+2);
  r=q+(y_offset*((int) columns+2)+x_offset);
  s=q-(y_offset*((int) columns+2)+x_offset);
  for (y=0; y < rows; y++)
  {
    p++;
    q++;
    r++;
    s++;
    if (polarity > 0)
      for (x=0; x < columns; x++)
      {
        v=(*q);
        if (((Quantum) (*s+1) > v) && (*r > v))
          v++;
        *p=v;
        p++;
        q++;
        r++;
        s++;
      }
    else
      for (x=0; x < columns; x++)
      {
        v=(*q);
        if (((Quantum) (*s+1) < v) && (*r < v))
          v--;
        *p=v;
        p++;
        q++;
        r++;
        s++;
      }
    p++;
    q++;
    r++;
    s++;
  }
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   I n s i d e P r i m i t i v e                                             %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function InsidePrimitive returns True if the (x,y) position is inside the
%  primitive as defined in primitive_info.  Otherwise False is returned.
%
%  The format of the InsidePrimitive routine is:
%
%      status=InsidePrimitive(primitive_info,annotate_info,x,y,image)
%
%  A description of each parameter follows:
%
%    o status:  Function InsidePrimitive returns True if the (x,y) position
%      is inside the primitive as defined in primitive_info.  Otherwise False
%      is returned.
%
%    o primitive_info: Specifies a pointer to a PrimitiveInfo structure.
%
%    o annotate_info: Specifies a pointer to a AnnotateInfo structure.
%
%    o x,y: Integers representing the (x,y) location in the image.
%
%    o image: The address of a structure of type Image.
%
%
*/
unsigned int InsidePrimitive(PrimitiveInfo *primitive_info,
  AnnotateInfo *annotate_info,int x,int y,Image *image)
{
  float
    mid,
    slope,
    trix,
    triy;

  register int
    i;

  register PrimitiveInfo
    *p,
    *q;

  register unsigned int
    inside;

  assert(primitive_info != (PrimitiveInfo *) NULL);
  assert(annotate_info != (AnnotateInfo *) NULL);
  assert(image != (Image *) NULL);
  inside=False;
  mid=annotate_info->linewidth/2.0;
  p=primitive_info;
  while (p->primitive != UndefinedPrimitive)
  {
    q=p+p->coordinates-1;
    switch (p->primitive)
    {
      case PointPrimitive:
      default:
      {
        for ( ; (p < q) && !inside; p++)
          inside=(x == p->x) && (y == p->y);
        break;
      }
      case LinePrimitive:
      {
        for ( ; (p < q) && !inside; p++)
        {
          if (p->x == (p+1)->x)
            inside=(x >= (p->x-mid)) && (x < (p->x+mid)) &&
              (y >= Min(p->y,(p+1)->y)) && (y <= Max(p->y,(p+1)->y));
          else
            if (p->y == (p+1)->y)
              inside=(x >= Min(p->x,(p+1)->x)) && (x <= Max(p->x,(p+1)->x)) &&
                (y >= (p->y-mid)) && (y < (p->y+mid));
            else
              {
                slope=(float) (p->y-(p+1)->y)/(p->x-(p+1)->x);
                trix=(slope*p->x+x/slope+y-p->y)/(slope+1.0/slope);
                triy=slope*(trix-p->x)+p->y;
                inside=(((x-trix)*(x-trix)+(y-triy)*(y-triy)) <= (mid*mid)) &&
                  (trix >= Min(p->x,(p+1)->x)) && (trix <= Max(p->x,(p+1)->x));
              }
          p++;
        }
        break;
      }
      case RectanglePrimitive:
      {
        for ( ; (p < q) && !inside; p++)
        {
          inside=(x >= Min(p->x-mid,(p+1)->x+mid)) &&
            (x < Max(p->x-mid,(p+1)->x+mid)) &&
            (y >= Min(p->y-mid,(p+1)->y+mid)) &&
            (y < Max(p->y-mid,(p+1)->y+mid));
          inside&=!((x >= Min(p->x+mid,(p+1)->x-mid)) &&
            (x < Max(p->x+mid,(p+1)->x-mid)) &&
            (y >= Min(p->y+mid,(p+1)->y-mid)) &&
            (y < Max(p->y+mid,(p+1)->y-mid)));
          p++;
        }
        break;
      }
      case FillRectanglePrimitive:
      {
        for ( ; (p < q) && !inside; p++)
        {
          inside=(x >= Min(p->x,(p+1)->x)) && (x <= Max(p->x,(p+1)->x)) &&
            (y >= Min(p->y,(p+1)->y)) && (y <= Max(p->y,(p+1)->y));
          p++;
        }
        break;
      }
      case EllipsePrimitive:
      {
        for ( ; (p < q) && !inside; p++)
        {
          inside=(((p->y-y)*(p->y-y))+((p->x-x)*(p->x-x))) <=
            (((p->y-(p+1)->y-mid)*(p->y-(p+1)->y-mid))+
            ((p->x-(p+1)->x-mid)*(p->x-(p+1)->x-mid)));
          inside&=!((((p->y-y)*(p->y-y))+((p->x-x)*(p->x-x))) <=
            (((p->y-(p+1)->y+mid)*(p->y-(p+1)->y+mid))+
            ((p->x-(p+1)->x+mid)*(p->x-(p+1)->x+mid))));
          p++;
        }
        break;
      }
      case FillEllipsePrimitive:
      {
        for ( ; (p < q) && !inside; p++)
        {
          inside=((p->y-y)*(p->y-y))+((p->x-x)*(p->x-x)) <=
            ((p->y-(p+1)->y)*(p->y-(p+1)->y))+((p->x-(p+1)->x)*(p->x-(p+1)->x));
          p++;
        }
        break;
      }
      case PolygonPrimitive:
      {
        for ( ; (p < q) && !inside; p++)
        {
          if (p->x == (p+1)->x)
            {
              inside|=(x >= (p->x-mid)) && (x < (p->x+mid)) &&
                (y >= Min(p->y,(p+1)->y)) && (y <= Max(p->y,(p+1)->y));
              continue;
            }
          if (p->y == (p+1)->y)
            {
              inside|=(x >= Min(p->x,(p+1)->x)) && (x <= Max(p->x,(p+1)->x)) &&
                (y >= (p->y-mid)) && (y < (p->y+mid));
              continue;
            }
          slope=(float) (p->y-(p+1)->y)/(p->x-(p+1)->x);
          trix=(slope*p->x+x/slope+y-p->y)/(slope+1.0/slope);
          triy=slope*(trix-p->x)+p->y;
          inside|=(((x-trix)*(x-trix)+(y-triy)*(y-triy)) <= (mid*mid)) &&
            (trix >= Min(p->x,(p+1)->x)) && (trix <= Max(p->x,(p+1)->x));
        }
        while (p <= q)
          p++;
        if (inside)
          break;
        p--;
        q=primitive_info;
        if (p->x == q->x)
          inside=(x >= (p->x-mid)) && (x < (p->x+mid)) &&
            (y >= Min(p->y,q->y)) && (y <= Max(p->y,q->y));
        else
          if (p->y == q->y)
            inside=(x >= Min(p->x,q->x)) && (x <= Max(p->x,q->x)) &&
              (y >= (p->y-mid)) && (y < (p->y+mid));
          else
            {
              slope=(float) (p->y-q->y)/(p->x-q->x);
              trix=(slope*p->x+x/slope+y-p->y)/(slope+1.0/slope);
              triy=slope*(trix-p->x)+p->y;
              inside=(((x-trix)*(x-trix)+(y-triy)*(y-triy)) <= (mid*mid)) &&
                (trix >= Min(p->x,q->x)) && (trix <= Max(p->x,q->x));
            }
        p++;
        break;
      }
      case FillPolygonPrimitive:
      {
        int
          crossing,
          crossings;

        crossings=0;
        if ((q->y >= y) != (p->y >= y))
          {
            crossing=q->x >= x;
            if (crossing != (p->x >= x))
              crossings+=(q->x-(q->y-y)*(p->x-q->x)/(p->y-q->y)) >= x;
            else
              if (crossing)
                crossings++;
          }
        for (p++; p <= q; p++)
        {
          if ((p-1)->y >= y)
            {
              while ((p <= q) && (p->y >= y))
                p++;
              if (p > q)
                break;
              crossing=(p-1)->x >= x;
              if (crossing != (p->x >= x))
                crossings+=
                  ((p-1)->x-((p-1)->y-y)*(p->x-(p-1)->x)/(p->y-(p-1)->y)) >= x;
              else
                if (crossing)
                  crossings++;
              continue;
            }
         while ((p <= q) && (p->y < y))
           p++;
         if (p > q)
           break;
         crossing=(p-1)->x >= x;
         if (crossing != (p->x >= x))
           crossings+=
             ((p-1)->x-((p-1)->y-y)*(p->x-(p-1)->x)/(p->y-(p-1)->y)) >= x;
         else
           if (crossing)
             crossings++;
        }
        inside=crossings & 0x01;
        break;
      }
      case ColorPrimitive:
      {
        for ( ; (p <= q) && !inside; p++)
          switch (p->method)
          {
            case PointMethod:
            default:
            {
              if ((p->x != x) || (p->y != y))
                break;
              inside=True;
              break;
            }
            case ReplaceMethod:
            {
              RunlengthPacket
                color;

              static RunlengthPacket
                target;

              if ((x == 0) && (y == 0))
                target=image->pixels[p->y*image->columns+p->x];
              color=image->pixels[y*image->columns+x];
              inside=ColorMatch(color,target,0);
              break;
            }
            case FloodfillMethod:
            {
              ColorPacket
                color;

              XColor
                pen_color;

              if ((p->x != x) || (p->y != y))
                break;
              (void) XQueryColorDatabase(annotate_info->pen,&pen_color);
              color.red=XDownScale(pen_color.red);
              color.green=XDownScale(pen_color.green);
              color.blue=XDownScale(pen_color.blue);
              ColorFloodfillImage(image,x,y,&color,0);
              break;
            }
            case ResetMethod:
            {
              inside=True;
              break;
            }
          }
        break;
      }
      case MattePrimitive:
      {
        if (!image->matte)
          {
            /*
              Initialize matte image.
            */
            image->matte=True;
            for (i=0; i < image->packets; i++)
              image->pixels[i].index=Opaque;
          }
        for ( ; p <= q; p++)
          switch (p->method)
          {
            case PointMethod:
            default:
            {
              if ((p->x != x) || (p->y != y))
                break;
              image->pixels[y*image->columns+x].index=Transparent;
              break;
            }
            case ReplaceMethod:
            {
              RunlengthPacket
                color;

              static RunlengthPacket
                target;

              if ((x == 0) && (y == 0))
                target=image->pixels[p->y*image->columns+p->x];
              color=image->pixels[y*image->columns+x];
              if (ColorMatch(color,target,0))
                image->pixels[y*image->columns+x].index=Transparent;
              break;
            }
            case FloodfillMethod:
            {
              if ((p->x != x) || (p->y != y))
                break;
              MatteFloodfillImage(image,x,y,Transparent,0);
              break;
            }
            case ResetMethod:
            {
              image->pixels[y*image->columns+x].index=Transparent;
              break;
            }
          }
        break;
      }
      case TextPrimitive:
      case ImagePrimitive:
      {
        register char
          *r;

        for ( ; p <= q; p++)
        {
          if ((p->x != x) || (p->y != y))
            continue;
          r=p->text;
          if (*r == '"')
            {
              p->text++;
              for (r++; (*r != '"') && (*r != '\0'); r++);
            }
          else
            if (*r == '\'')
              {
                p->text++;
                for (r++; (*r != '\'') && (*r != '\0'); r++);
              }
            else
              for (r++; (*r != ' ') && (*r != '\0'); r++);
          (void) strncpy(annotate_info->text,p->text,r-p->text);
          annotate_info->text[r-p->text]='\0';
          if (p->primitive == TextPrimitive)
            {
              (void) sprintf(annotate_info->geometry,"%+d%+d",p->x,p->y);
              AnnotateImage(image,annotate_info);
            }
          else
            {
              Image
                *composite_image;

              ImageInfo
                composite_info;

              GetImageInfo(&composite_info);
              (void) strcpy(composite_info.filename,annotate_info->text);
              composite_image=ReadImage(&composite_info);
              if (composite_image != (Image *) NULL)
                {
                  CompositeImage(image,ReplaceCompositeOp,composite_image,
                    p->x,p->y);
                  DestroyImage(composite_image);
                }
            }
        }
        break;
      }
    }
    if (inside)
      return(True);
  }
  return(inside);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   I n t e r p o l a t e                                                     %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function Interpolate applies bi-linear interpolation between a pixel and
%  it's neighbors.
%
%  The format of the Interpolate routine is:
%
%      Interpolate(image,pixel,x,y)
%
%  A description of each parameter follows:
%
%    o image: The address of a structure of type Image.
%
%    o pixel: A pointer to a RunlengthPacket representing the current pixel.
%
%    o x,y: A double representing the current (x,y) position of the pixel.
%
%
*/
RunlengthPacket Interpolate(Image *image,RunlengthPacket *pixel,double x,
  double y)
{
  register RunlengthPacket
    *p,
    *q,
    *r,
    *s;

  RunlengthPacket
    interpolated_pixel;

  assert(image != (Image *) NULL);
  assert(pixel != (RunlengthPacket *) NULL);
  if ((x < 0) || (x >= image->columns) || (y < 0) || (y >= image->rows))
    return(*pixel);
  if (!UncompressImage(image))
    return(*pixel);
  p=image->pixels+(int) y*image->columns+(int) x;
  q=p+1;
  if (q > (image->pixels+image->packets-1))
    q=p;
  r=p+image->columns;
  if (r > (image->pixels+image->packets-1))
    r=p;
  s=q+image->columns;
  if (s > (image->pixels+image->packets-1))
    s=q;
  x=fmod(x,1.0);
  y=fmod(y,1.0);
  interpolated_pixel.red=(Quantum)
    ((1.0-y)*((1.0-x)*p->red+x*q->red)+y*((1.0-x)*r->red+x*s->red));
  interpolated_pixel.green=(Quantum)
    ((1.0-y)*((1.0-x)*p->green+x*q->green)+y*((1.0-x)*r->green+x*s->green));
  interpolated_pixel.blue=(Quantum)
    ((1.0-y)*((1.0-x)*p->blue+x*q->blue)+y*((1.0-x)*r->blue+x*s->blue));
  interpolated_pixel.index=(unsigned short)
    ((1.0-y)*((1.0-x)*p->index+x*q->index)+y*((1.0-x)*r->index+x*s->index));
  interpolated_pixel.length=p->length;
  return(interpolated_pixel);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   M o d u l a t e                                                           %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function Modulate modulates the hue, saturation, and brightness of an
%  image.
%
%  The format of the ModulateImage routine is:
%
%      Modulate(percent_hue,percent_saturation,percent_luminosity,red,green,
%        blue)
%
%  A description of each parameter follows:
%
%    o percent_hue, percent_saturation, percent_luminosity: A double value
%      representing the percent change in a component of the HSL color space.
%
%    o red, green, blue: A pointer to a pixel component of type Quantum.
%
%
*/
void Modulate(double percent_hue,double percent_saturation,
  double percent_brightness,Quantum *red,Quantum *green,Quantum *blue)
{
  double
    brightness,
    hue,
    saturation;

  /*
    Increase or decrease color brightness, saturation, or hue.
  */
  assert(red != (Quantum *) NULL);
  assert(green != (Quantum *) NULL);
  assert(blue != (Quantum *) NULL);
  TransformHSL(*red,*green,*blue,&hue,&saturation,&brightness);
  brightness+=percent_brightness/100.0;
  if (brightness < 0.0)
    brightness=0.0;
  else
    if (brightness > 1.0)
      brightness=1.0;
  saturation+=percent_saturation/100.0;
  if (saturation < 0.0)
    saturation=0.0;
  else
    if (saturation > 1.0)
      saturation=1.0;
  if (hue != -1.0)
    {
      hue+=percent_hue/100.0;
      if (hue < 0.0)
        hue+=1.0;
      else
        if (hue > 1.0)
          hue-=1.0;
    }
  HSLTransform(hue,saturation,brightness,red,green,blue);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   T r a n s f o r m H S L                                                   %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function TransformHSL converts a (red, green, blue) to a (hue, saturation,
%  luminosity) triple.
%
%  The format of the TransformHSL routine is:
%
%      TransformHSL(red,green,blue,hue,saturation,luminosity)
%
%  A description of each parameter follows:
%
%    o red, green, blue: A Quantum value representing the red, green, and
%      blue component of a pixel..
%
%    o hue, saturation, luminosity: A pointer to a double value representing a
%      component of the HSL color space.
%
%
*/
void TransformHSL(const Quantum red,const Quantum green,const Quantum blue,
  double *hue,double *saturation,double *luminosity)
{
  double
    b,
    g,
    max,
    min,
    r;

  /*
    Convert RGB to HSL colorspace.
  */
  assert(hue != (double *) NULL);
  assert(saturation != (double *) NULL);
  assert(luminosity != (double *) NULL);
  *hue=1.0;
  *saturation=0.0;
  r=(double) red/(double) MaxRGB;
  g=(double) green/(double) MaxRGB;
  b=(double) blue/(double) MaxRGB;
  max=Max(r,Max(g,b));
  min=Min(r,Min(g,b));
  *luminosity=(min+max)/2.0;
  if (*luminosity <= 0.0)
    return;
  *saturation=max-min;
  if (*saturation <= 0.0)
    return;
  *saturation/=(*luminosity <= 0.5) ? (min+max) : (2.0-max-min) ;
  if (r == max)
    *hue=(g == min ? 5.0+(max-b)/(max-min) : 1.0-(max-g)/(max-min));
  else
    if (g == max)
      *hue=(b == min ? 1.0+(max-r)/(max-min) : 3.0-(max-b)/(max-min));
    else
      *hue=(r == min ? 3.0+(max-g)/(max-min) : 5.0-(max-r)/(max-min));
  *hue/=6.0;
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   U p s a m p l e                                                           %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function Upsample
%
%  The format of the UpSample routine is:
%
%      Upsample(width,height,scaled_width,pixels)
%
%  A description of each parameter follows:
%
%    o width,height:  Unsigned values representinf the width and height of
%      the image pixel array.
%
%    o scaled_width:  Specifies the final width of the upsampled pixel array.
%
%    o pixels:  An unsigned char containing the pixel data.  On output the
%      upsampled pixels are returned here.
%
%
*/
void Upsample(unsigned int width,unsigned int height,
  unsigned int scaled_width,unsigned char *pixels)
{
  register int
    x,
    y;

  register unsigned char
    *p,
    *q,
    *r;

  /*
    Create a new image that is a integral size greater than an existing one.
  */
  assert(pixels != (unsigned char *) NULL);
  for (y=0; y < height; y++)
  {
    p=pixels+(height-1-y)*scaled_width+(width-1);
    q=pixels+((height-1-y) << 1)*scaled_width+((width-1) << 1);
    *q=(*p);
    *(q+1)=(*(p));
    for (x=1; x < width; x++)
    {
      p--;
      q-=2;
      *q=(*p);
      *(q+1)=(((int) *p)+((int) *(p+1))+1) >> 1;
    }
  }
  for (y=0; y < (height-1); y++)
  {
    p=pixels+(y << 1)*scaled_width;
    q=p+scaled_width;
    r=q+scaled_width;
    for (x=0; x < (width-1); x++)
    {
      *q=(((int) *p)+((int) *r)+1) >> 1;
      *(q+1)=(((int) *p)+((int) *(p+2))+((int) *r)+((int) *(r+2))+2) >> 2;
      q+=2;
      p+=2;
      r+=2;
    }
    *q++=(((int) *p++)+((int) *r++)+1) >> 1;
    *q++=(((int) *p++)+((int) *r++)+1) >> 1;
  }
  p=pixels+(2*height-2)*scaled_width;
  q=pixels+(2*height-1)*scaled_width;
  for (x=0; x < width; x++)
  {
    *q++=(*p++);
    *q++=(*p++);
  }
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.