v13i020: ImageMagick - Graphics display programs, Part04/21

cristy at dupont.com cristy at dupont.com
Wed May 22 18:57:29 AEST 1991


Submitted-by: cristy at dupont.com
Posting-number: Volume 13, Issue 20
Archive-name: imagemagic/part04

#!/bin/sh
# this is img.04 (part 4 of ImageMagick)
# do not concatenate these parts, unpack them in order with /bin/sh
# file ImageMagick/image.c continued
#
if test ! -r _shar_seq_.tmp; then
	echo 'Please unpack part 1 first!'
	exit 1
fi
(read Scheck
 if test "$Scheck" != 4; then
	echo Please unpack part "$Scheck" next!
	exit 1
 else
	exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
	echo 'x - still skipping ImageMagick/image.c'
else
echo 'x - continuing file ImageMagick/image.c'
sed 's/^X//' << 'SHAR_EOF' >> 'ImageMagick/image.c' &&
%                                                                             %
%                                                                             %
%                                                                             %
%   D e s t r o y I m a g e                                                   %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function DestroyImage deallocates memory associated with an image.
%
%  The format of the DestroyImage routine is:
%
%      DestroyImage(image)
%
%  A description of each parameter follows:
%
%    o image: The address of a structure of type Image.
%
%
*/
void DestroyImage(image)
Image
X  *image;
{
X  /*
X    Deallocate the image colormap.
X  */
X  if (image->colormap != (ColorPacket *) NULL)
X    (void) free((char *) image->colormap);
X  /*
X    Deallocate the image pixels.
X  */
X  if (image->pixels != (RunlengthPacket *) NULL)
X    (void) free((char *) image->pixels);
X  /*
X    Deallocate the image comments.
X  */
X  if (image->comments != (char *) NULL)
X    (void) free((char *) image->comments);
X  /*
X    Deallocate the image structure.
X  */
X  (void) free((char *) image);
}
X
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%     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 reduced.  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 inversely
%  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
X  *image;
{
#define Esum(weight) \
X  red_distance=s->red-red; \
X  green_distance=s->green-green; \
X  blue_distance=s->blue-blue; \
X  distance=red_distance*red_distance+green_distance*green_distance+ \
X    blue_distance*blue_distance; \
X  if (distance < Threshold) \
X    { \
X      total_red+=weight*(s->red); \
X      total_green+=weight*(s->green); \
X      total_blue+=weight*(s->blue); \
X      total_weight+=weight; \
X    } \
X  s++;
#define Threshold  2500
X
X  ColorPacket
X    *scanline;
X
X  Image
X    *enhanced_image;
X
X  int
X    blue_distance,
X    green_distance,
X    red_distance;
X
X  register ColorPacket
X    *s,
X    *s0,
X    *s1,
X    *s2,
X    *s3,
X    *s4;
X
X  register RunlengthPacket
X    *p,
X    *q;
X
X  register unsigned int
X    x;
X
X  unsigned char
X    blue,
X    green,
X    red;
X
X  unsigned int
X    y;
X
X  unsigned long
X    distance,
X    total_blue,
X    total_green,
X    total_red,
X    total_weight;
X
X  if ((image->columns < 5) || (image->rows < 5))
X    {
X      Warning("unable to enhance image","image size must exceed 4x4");
X      return((Image *) NULL);
X    }
X  /*
X    Initialize enhanced image attributes.
X  */
X  enhanced_image=CopyImage(image,image->columns,image->rows);
X  if (enhanced_image == (Image *) NULL)
X    {
X      Warning("unable to enhance image","memory allocation failed");
X      return((Image *) NULL);
X    }
X  enhanced_image->class=DirectClass;
X  /*
X    Allocate scan line buffer for 5 rows of the image.
X  */
X  scanline=(ColorPacket *) malloc(5*image->columns*sizeof(ColorPacket));
X  if (scanline == (ColorPacket *) NULL)
X    {
X      Warning("unable to enhance image","memory allocation failed");
X      DestroyImage(enhanced_image);
X      return((Image *) NULL);
X    }
X  /*
X    Read the first 4 rows of the image.
X  */
X  p=image->pixels;
X  image->runlength=p->length+1;
X  s=scanline;
X  for (x=0; x < (image->columns*4); x++)
X  {
X    if (image->runlength > 0)
X      image->runlength--;
X    else
X      {
X        p++;
X        image->runlength=p->length;
X      }
X    s->red=p->red;
X    s->green=p->green;
X    s->blue=p->blue;
X    s->index=p->index;
X    s++;
X  }
X  /*
X    Dump first 2 scanlines of image.
X  */
X  enhanced_image->packets=0;
X  q=enhanced_image->pixels;
X  q->length=MaxRunlength;
X  s=scanline;
X  for (x=0; x < (2*image->columns); x++)
X  {
X    if ((s->red == q->red) && (s->green == q->green) && (s->blue == q->blue) &&
X        (q->length < MaxRunlength))
X      q->length++;
X    else
X      {
X        if (enhanced_image->packets > 0)
X          q++;
X        enhanced_image->packets++;
X        q->red=s->red;
X        q->green=s->green;
X        q->blue=s->blue;
X        q->index=s->index;
X        q->length=0;
X      }
X    s++;
X  }
X  /*
X    Enhance each row.
X  */
X  for (y=2; y < (image->rows-2); y++)
X  {
X    /*
X      Initialize sliding window pointers.
X    */
X    s0=scanline+image->columns*((y-2) % 5);
X    s1=scanline+image->columns*((y-1) % 5);
X    s2=scanline+image->columns*(y % 5);
X    s3=scanline+image->columns*((y+1) % 5);
X    s4=scanline+image->columns*((y+2) % 5);
X    /*
X      Read another scan line.
X    */
X    s=s4;
X    for (x=0; x < image->columns; x++)
X    {
X      if (image->runlength > 0)
X        image->runlength--;
X      else
X        {
X          p++;
X          image->runlength=p->length;
X        }
X      s->red=p->red;
X      s->green=p->green;
X      s->blue=p->blue;
X      s->index=p->index;
X      s++;
X    }
X    /*
X      Transfer first 2 pixels of the scanline.
X    */
X    s=s2;
X    for (x=0; x < 2; x++)
X    {
X      if ((s->red == q->red) && (s->green == q->green) && 
X          (s->blue == q->blue) && (q->length < MaxRunlength))
X        q->length++;
X      else
X        {
X          if (enhanced_image->packets > 0)
X            q++;
X          enhanced_image->packets++;
X          q->red=0;
X          q->green=0;
X          q->blue=0;
X          q->index=0;
X          q->length=0;
X        }
X      s++;
X    }
X    for (x=2; x < (image->columns-2); x++)
X    {
X      /*
X        Compute weighted average of target pixel color components.
X      */
X      total_red=0;
X      total_green=0;
X      total_blue=0;
X      total_weight=0;
X      s=s2+2;
X      red=s->red;
X      green=s->green;
X      blue=s->blue;
X      s=s0;
X      Esum(5);  Esum(8);  Esum(10); Esum(8);  Esum(5);
X      s=s1;
X      Esum(8);  Esum(20); Esum(40); Esum(20); Esum(8);
X      s=s2;
X      Esum(10); Esum(40); Esum(80); Esum(40); Esum(10);
X      s=s3;
X      Esum(8);  Esum(20); Esum(40); Esum(20); Esum(8);
X      s=s4;
X      Esum(5);  Esum(8);  Esum(10); Esum(8);  Esum(5);
X      red=(unsigned char) ((total_red+(total_weight >> 1)-1)/total_weight);
X      green=(unsigned char) ((total_green+(total_weight >> 1)-1)/total_weight);
X      blue=(unsigned char) ((total_blue+(total_weight >> 1)-1)/total_weight);
X      if ((red == q->red) && (green == q->green) && (blue == q->blue) &&
X          (q->length < MaxRunlength))
X        q->length++;
X      else
X        {
X          if (enhanced_image->packets > 0)
X            q++;
X          enhanced_image->packets++;
X          q->red=red;
X          q->green=green;
X          q->blue=blue;
X          q->index=0;
X          q->length=0;
X        }
X      s0++;
X      s1++;
X      s2++;
X      s3++;
X      s4++;
X    }
X    /*
X      Transfer last 2 pixels of the scanline.
X    */
X    s=s2;
X    for (x=0; x < 2; x++)
X    {
X      if ((s->red == q->red) && (s->green == q->green) && 
X          (s->blue == q->blue) && (q->length < MaxRunlength))
X        q->length++;
X      else
X        {
X          if (enhanced_image->packets > 0)
X            q++;
X          enhanced_image->packets++;
X          q->red=s->red;
X          q->green=s->green;
X          q->blue=s->blue;
X          q->index=s->index;
X          q->length=0;
X        }
X      s++;
X    }
X  }
X  /*
X    Dump last 2 scanlines of pixels.
X  */
X  s=scanline+image->columns*(y % 3);
X  for (x=0; x < (2*image->columns); x++)
X  {
X    if ((s->red == q->red) && (s->green == q->green) && 
X        (s->blue == q->blue) && (q->length < MaxRunlength))
X      q->length++;
X    else
X      {
X        if (enhanced_image->packets > 0)
X          q++;
X        enhanced_image->packets++;
X        q->red=s->red;
X        q->green=s->green;
X        q->blue=s->blue;
X        q->index=s->index;
X        q->length=0;
X      }
X    s++;
X  }
X  (void) free((char *) scanline);
X  enhanced_image->pixels=(RunlengthPacket *) realloc((char *)
X    enhanced_image->pixels,enhanced_image->packets*sizeof(RunlengthPacket));
X  return(enhanced_image);
}
X
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%     G a m m a I m a g e                                                     %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Procedure GammaImage converts the reference image to gamma corrected colors.
%
%  The format of the GammaImage routine is:
%
%      GammaImage(image,gamma)
%
%  A description of each parameter follows:
%
%    o image: The address of a structure of type Image;  returned from
%      ReadImage.
%
%    o gamma: A double precision value indicating the level of gamma
%      correction.
%
%
*/
void GammaImage(image,gamma)
Image
X  *image;
X
double
X  gamma;
{
X  register int
X    i;
X
X  register RunlengthPacket
X    *p;
X
X  unsigned char
X    gamma_map[MaxRgb+1];
X
X  /*
X    Initialize gamma table.
X  */
X  for (i=0; i <= MaxRgb; i++)
X    gamma_map[i]=(unsigned char)
X      ((pow((double) i/MaxRgb,1.0/gamma)*MaxRgb)+0.5);
X  switch (image->class)
X  {
X    case DirectClass:
X    {
X      /*
X        Gamma-correct DirectClass image.
X      */
X      p=image->pixels;
X      for (i=0; i < image->packets; i++)
X      {
X        p->red=gamma_map[p->red];
X        p->green=gamma_map[p->green];
X        p->blue=gamma_map[p->blue];
X        p++;
X      }
X      break;
X    }
X    case PseudoClass:
X    {
X      register unsigned short
X        index;
X
X      /*
X        Gamma-correct PseudoClass image.
X      */
X      for (i=0; i < image->colors; i++)
X      {
X        image->colormap[i].red=gamma_map[image->colormap[i].red];
X        image->colormap[i].green=gamma_map[image->colormap[i].green];
X        image->colormap[i].blue=gamma_map[image->colormap[i].blue];
X      }
X      p=image->pixels;
X      for (i=0; i < image->packets; i++)
X      {
X        index=p->index;
X        p->red=image->colormap[index].red;
X        p->green=image->colormap[index].green;
X        p->blue=image->colormap[index].blue;
X        p++;
X      }
X      break;
X    }
X  }
}
X
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%     G r a y I m a g e                                                       %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Procedure GrayImage converts the reference image to gray scale colors.
%
%  The format of the GrayImage routine is:
%
%      GrayImage(image)
%
%  A description of each parameter follows:
%
%    o image: The address of a structure of type Image;  returned from
%      ReadImage.
%
%
*/
void GrayImage(image)
Image
X  *image;
{
X  register int
X    i;
X
X  register RunlengthPacket
X    *p;
X
X  register unsigned char
X    gray_value;
X
X  switch (image->class)
X  {
X    case DirectClass:
X    {
X      /*
X        Convert DirectClass packets to grayscale.
X      */
X      p=image->pixels;
X      for (i=0; i < image->packets; i++)
X      {
X        gray_value=Intensity(*p);
X        p->red=gray_value;
X        p->green=gray_value;
X        p->blue=gray_value;
X        p++;
X      }
X      break;
X    }
X    case PseudoClass:
X    {
X      register unsigned short
X        index;
X
X      /*
X        Convert PseudoClass packets to grayscale.
X      */
X      for (i=0; i < image->colors; i++)
X      {
X        gray_value=Intensity(image->colormap[i]);
X        image->colormap[i].red=gray_value;
X        image->colormap[i].green=gray_value;
X        image->colormap[i].blue=gray_value;
X      }
X      p=image->pixels;
X      for (i=0; i < image->packets; i++)
X      {
X        index=p->index;
X        p->red=image->colormap[index].red;
X        p->green=image->colormap[index].green;
X        p->blue=image->colormap[index].blue;
X        p++;
X      }
X      break;
X    }
X  }
}
X
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%     I n v e r s e I m a g e                                                 %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Procedure InverseImage inverses the colors in the reference image.
%
%  The format of the InverseImage routine is:
%
%      InverseImage(image)
%
%  A description of each parameter follows:
%
%    o image: The address of a structure of type Image;  returned from
%      ReadImage.
%
%
*/
void InverseImage(image)
Image
X  *image;
{
X  register int
X    i;
X
X  register RunlengthPacket
X    *p;
X
X  switch (image->class)
X  {
X    case DirectClass:
X    {
X      /*
X        Inverse DirectClass packets.
X      */
X      p=image->pixels;
X      for (i=0; i < image->packets; i++)
X      {
X        p->red=(~p->red);
X        p->green=(~p->green);
X        p->blue=(~p->blue);
X        p++;
X      }
X      break;
X    }
X    case PseudoClass:
X    {
X      register unsigned short
X        index;
X
X      /*
X        Inverse PseudoClass packets.
X      */
X      for (i=0; i < image->colors; i++)
X      {
X        image->colormap[i].red=(~image->colormap[i].red);
X        image->colormap[i].green=(~image->colormap[i].green);
X        image->colormap[i].blue=(~image->colormap[i].blue);
X      }
X      p=image->pixels;
X      for (i=0; i < image->packets; i++)
X      {
X        index=p->index;
X        p->red=image->colormap[index].red;
X        p->green=image->colormap[index].green;
X        p->blue=image->colormap[index].blue;
X        p++;
X      }
X      break;
X    }
X  }
}
X
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   L i n e a r C o l o r m a p                                               %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function LinearColormap sorts the colormap of a PseudoClass image by
%  linearly increasing intensity.
%
%  The format of the LinearColormap routine is:
%
%      LinearColormap(image)
%
%  A description of each parameter follows:
%
%    o image: A pointer to a Image structure.
%
%
*/
static int LinearCompare(color_1,color_2)
register ColorPacket
X  *color_1,
X  *color_2;
{
X  return((int) Intensity(*color_1)-(int) Intensity(*color_2));
}
X
void LinearColormap(image)
Image
X  *image;
{
X  register int
X    i;
X
X  register RunlengthPacket
X    *p;
X
X  register unsigned short
X    index;
X
X  unsigned int
X    *pixels;
X
X  if (image->class == DirectClass)
X    return;
X  /*
X    Allocate memory for pixel indexes.
X  */
X  pixels=(unsigned int *) malloc(image->colors*sizeof(unsigned int));
X  if (pixels == (unsigned int *) NULL)
X    {
X      Warning("unable to sort colormap","memory allocation failed");
X      return;
X    }
X  /*
X    Assign index values to colormap entries.
X  */
X  for (i=0; i < image->colors; i++)
X    image->colormap[i].index=i;
X  /*
X    Sort image colormap by increasing intensity.
X  */
X  qsort((char *) image->colormap,(int) image->colors,sizeof(ColorPacket),
X    LinearCompare);
X  /*
X    Update image colormap indexes to sorted colormap order.
X  */
X  for (i=0; i < image->colors; i++)
X    pixels[image->colormap[i].index]=i;
X  p=image->pixels;
X  for (i=0; i < image->packets; i++)
X  {
X    index=pixels[p->index];
X    p->red=image->colormap[index].red;
X    p->green=image->colormap[index].green;
X    p->blue=image->colormap[index].blue;
X    p->index=index;
X    p++;
X  }
X  (void) free((char *) pixels);
}
X
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%     N o i s y I m a g e                                                     %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function NoisyImage creates a new image that is a copy of an existing
%  one with the noise reduced 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 NoisyImage routine is:
%
%      noisy_image=NoisyImage(image)
%
%  A description of each parameter follows:
%
%    o noisy_image: Function NoisyImage returns a pointer to the image after
%      the noise is reduced.  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 NoisyCompare(color_1,color_2)
register ColorPacket
X  *color_1,
X  *color_2;
{
X  return((int) Intensity(*color_1)-(int) Intensity(*color_2));
}
X
Image *NoisyImage(image)
Image
X  *image;
{
X  ColorPacket
X    pixel,
X    *scanline,
X    window[9];
X
X  Image
X    *noisy_image;
X
X  int
X    i;
X
X  register ColorPacket
X    *s,
X    *s0,
X    *s1,
X    *s2;
X
X  register RunlengthPacket
X    *p,
X    *q;
X
X  register unsigned int
X    x;
X
X  unsigned int
X    y;
X
X  if ((image->columns < 3) || (image->rows < 3))
X    {
X      Warning("unable to reduce noise","the image size must exceed 2x2");
X      return((Image *) NULL);
X    }
X  /*
X    Initialize noisy image attributes.
X  */
X  noisy_image=CopyImage(image,image->columns,image->rows);
X  if (noisy_image == (Image *) NULL)
X    {
X      Warning("unable to reduce noise","memory allocation failed");
X      return((Image *) NULL);
X    }
X  /*
X    Allocate scanline buffer for 3 rows of the image.
X  */
X  scanline=(ColorPacket *) malloc(3*image->columns*sizeof(ColorPacket));
X  if (scanline == (ColorPacket *) NULL)
X    {
X      Warning("unable to reduce noise","memory allocation failed");
X      DestroyImage(noisy_image);
X      return((Image *) NULL);
X    }
X  /*
X    Preload the first 2 rows of the image.
X  */
X  p=image->pixels;
X  image->runlength=p->length+1;
X  s=scanline;
X  for (x=0; x < (2*image->columns); x++)
X  {
X    if (image->runlength > 0)
X      image->runlength--;
X    else
X      {
X        p++;
X        image->runlength=p->length;
X      }
X    s->red=p->red;
X    s->green=p->green;
X    s->blue=p->blue;
X    s->index=p->index;
X    s++;
X  }
X  /*
X    Dump first scanline of image.
X  */
X  noisy_image->packets=0;
X  q=noisy_image->pixels;
X  q->length=MaxRunlength;
X  s=scanline;
X  for (x=0; x < image->columns; x++)
X  {
X    if ((s->red == q->red) && (s->green == q->green) && (s->blue == q->blue) &&
X        (q->length < MaxRunlength))
X      q->length++;
X    else
X      {
X        if (noisy_image->packets > 0)
X          q++;
X        noisy_image->packets++;
X        q->red=s->red;
X        q->green=s->green;
X        q->blue=s->blue;
X        q->index=s->index;
X        q->length=0;
X      }
X    s++;
X  }
X  /*
X    Reduce noise in each row.
X  */
X  for (y=1; y < (image->rows-1); y++)
X  {
X    /*
X      Initialize sliding window pointers.
X    */
X    s0=scanline+image->columns*((y-1) % 3);
X    s1=scanline+image->columns*(y % 3);
X    s2=scanline+image->columns*((y+1) % 3);
X    /*
X      Read another scan line.
X    */
X    s=s2;
X    for (x=0; x < image->columns; x++)
X    {
X      if (image->runlength > 0)
X        image->runlength--;
X      else
X        {
X          p++;
X          image->runlength=p->length;
X        }
X      s->red=p->red;
X      s->green=p->green;
X      s->blue=p->blue;
X      s->index=p->index;
X      s++;
X    }
X    /*
X      Transfer first pixel of the scanline.
X    */
X    s=s1;
X    if ((s->red == q->red) && (s->green == q->green) &&
X        (s->blue == q->blue) && (q->length < MaxRunlength))
X      q->length++;
X    else
X      {
X        if (noisy_image->packets > 0)
X          q++;
X        noisy_image->packets++;
X        q->red=s->red;
X        q->green=s->green;
X        q->blue=s->blue;
X        q->index=s->index;
X        q->length=0;
X      }
X    for (x=1; x < (image->columns-1); x++)
X    {
X      /*
X        Sort window pixels by increasing intensity.
X      */
X      s=s0;
X      window[0]=(*s++);
X      window[1]=(*s++);
X      window[2]=(*s++);
X      s=s1;
X      window[3]=(*s++);
X      window[4]=(*s++);
X      window[5]=(*s++);
X      s=s2;
X      window[6]=(*s++);
X      window[7]=(*s++);
X      window[8]=(*s++);
X      qsort((char *) window,9,sizeof(ColorPacket),NoisyCompare);
X      pixel=(*(s1+1));
X      if (Intensity(pixel) == Intensity(window[0]))
X        {
X          /*
X            Pixel is minimum noise; replace with next neighbor in value.
X          */
X          for (i=1; i < 8; i++)
X            if (Intensity(window[i]) != Intensity(window[0]))
X              break;
X          pixel=window[i];
X        }
X      else
X        if (Intensity(pixel) == Intensity(window[8]))
X          {
X            /*
X              Pixel is maximum noise; replace with next neighbor in value.
X            */
X            for (i=7; i > 0; i--)
X              if (Intensity(window[i]) != Intensity(window[8]))
X                break;
X            pixel=window[i];
X          }
X      if ((pixel.red == q->red) && (pixel.green == q->green) &&
X          (pixel.blue == q->blue) && (q->length < MaxRunlength))
X        q->length++;
X      else
X        {
X          if (noisy_image->packets > 0)
X            q++;
X          noisy_image->packets++;
X          q->red=pixel.red;
X          q->green=pixel.green;
X          q->blue=pixel.blue;
X          q->index=pixel.index;
X          q->length=0;
X        }
X      s0++;
X      s1++;
X      s2++;
X    }
X    /*
X      Transfer last pixel of the scanline.
X    */
X    s=s1;
X    if ((s->red == q->red) && (s->green == q->green) &&
X        (s->blue == q->blue) && (q->length < MaxRunlength))
X      q->length++;
X    else
X      {
X        if (noisy_image->packets > 0)
X          q++;
X        noisy_image->packets++;
X        q->red=s->red;
X        q->green=s->green;
X        q->blue=s->blue;
X        q->index=s->index;
X        q->length=0;
X      }
X  }
X  /*
X    Dump last scanline of pixels.
X  */
X  s=scanline+image->columns*(y % 3);
X  for (x=0; x < image->columns; x++)
X  {
X    if ((s->red == q->red) && (s->green == q->green) && (s->blue == q->blue) &&
X        (q->length < MaxRunlength))
X      q->length++;
X    else
X      {
X        if (noisy_image->packets > 0)
X          q++;
X        noisy_image->packets++;
X        q->red=s->red;
X        q->green=s->green;
X        q->blue=s->blue;
X        q->index=s->index;
X        q->length=0;
X      }
X    s++;
X  }
X  (void) free((char *) scanline);
X  noisy_image->pixels=(RunlengthPacket *) realloc((char *)
X    noisy_image->pixels,noisy_image->packets*sizeof(RunlengthPacket));
X  return(noisy_image);
}
X
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%     N o r m a l i z e I m a g e                                             %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Procedure NormalizeImage normalizes the pixel values to span the full
%  range of color values.
%
%  The format of the NormalizeImage routine is:
%
%      NormalizeImage(image)
%
%  A description of each parameter follows:
%
%    o image: The address of a structure of type Image;  returned from
%      ReadImage.
%
%
*/
void NormalizeImage(image)
Image
X  *image;
{
X  double
X    factor;
X
X  register int
X    i;
X
X  register int
X    max_intensity,
X    min_intensity,
X    intensity;
X
X  register RunlengthPacket
X    *p;
X
X  unsigned char
X    normalize_map[MaxRgb+1];
X
X  switch (image->class)
X  {
X    case DirectClass:
X    {
X      /*
X        Determine min and max intensity.
X      */
X      p=image->pixels;
X      min_intensity=p->red;
X      max_intensity=p->red;
X      for (i=0; i < image->packets; i++)
X      {
X        if (p->red < min_intensity)
X          min_intensity=p->red;
X        else
X          if (p->red > max_intensity)
X            max_intensity=p->red;
X        if (p->green < min_intensity)
X          min_intensity=p->green;
X        else
X          if (p->green > max_intensity)
X            max_intensity=p->green;
X        if (p->blue < min_intensity)
X          min_intensity=p->blue;
X        else
X          if (p->blue > max_intensity)
X            max_intensity=p->blue;
X        p++;
X      }
X      if ((min_intensity == 0) && (max_intensity == MaxRgb))
X        break;
X      /*
X        Initialize normalize table.
X      */
X      factor=(double) MaxRgb/(double) (max_intensity-min_intensity);
X      for (i=min_intensity; i <= max_intensity; i++)
X      {
X        intensity=(i-min_intensity)*factor;
X        if (intensity < 0)
X          intensity=0;
X        else
X          if (intensity > MaxRgb)
X            intensity=MaxRgb;
X        normalize_map[i]=(unsigned char) intensity;
X      }
X      /*
X        Normalize DirectClass image.
X      */
X      p=image->pixels;
X      for (i=0; i < image->packets; i++)
X      {
X        p->red=normalize_map[p->red];
X        p->green=normalize_map[p->green];
X        p->blue=normalize_map[p->blue];
X        p++;
X      }
X      break;
X    }
X    case PseudoClass:
X    {
X      register unsigned short
X        index;
X
X      /*
X        Determine min and max intensity.
X      */
X      min_intensity=image->colormap[0].red;
X      max_intensity=image->colormap[0].red;
X      for (i=0; i < image->colors; i++)
X      {
X        if (image->colormap[i].red < min_intensity)
X          min_intensity=image->colormap[i].red;
X        else
X          if (image->colormap[i].red > max_intensity)
X            max_intensity=image->colormap[i].red;
X        if (image->colormap[i].green < min_intensity)
X          min_intensity=image->colormap[i].green;
X        else
X          if (image->colormap[i].green > max_intensity)
X            max_intensity=image->colormap[i].green;
X        if (image->colormap[i].blue < min_intensity)
X          min_intensity=image->colormap[i].blue;
X        else
X          if (image->colormap[i].blue > max_intensity)
X            max_intensity=image->colormap[i].blue;
X      }
X      if ((min_intensity == 0) && (max_intensity == MaxRgb))
X        break;
X      /*
X        Initialize normalize table.
X      */
X      factor=(double) MaxRgb/(double) (max_intensity-min_intensity);
X      for (i=min_intensity; i <= max_intensity; i++)
X      {
X        intensity=(i-min_intensity)*factor;
X        if (intensity < 0)
X          intensity=0;
X        else
X          if (intensity > MaxRgb)
X            intensity=MaxRgb;
X        normalize_map[i]=(unsigned char) intensity;
X      }
X      /*
X        Normalize PseudoClass image.
X      */
X      for (i=0; i < image->colors; i++)
X      {
X        image->colormap[i].red=normalize_map[image->colormap[i].red];
X        image->colormap[i].green=normalize_map[image->colormap[i].green];
X        image->colormap[i].blue=normalize_map[image->colormap[i].blue];
X      }
X      p=image->pixels;
X      for (i=0; i < image->packets; i++)
X      {
X        index=p->index;
X        p->red=image->colormap[index].red;
X        p->green=image->colormap[index].green;
X        p->blue=image->colormap[index].blue;
X        p++;
X      }
X      break;
X    }
X  }
}
X
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   P r i n t I m a g e                                                       %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function PrintImage translates a MIFF image to encapsulated Postscript for
%  printing.  If the supplied geometry is null, the image is centered on the
%  Postscript page.  Otherwise, the image is positioned as specified by the
%  geometry.
%
%  The format of the PrintImage routine is:
%
%      status=PrintImage(image,geometry)
%
%  A description of each parameter follows:
%
%    o status: Function PrintImage return True if the image is printed.
%      False is returned if the image file cannot be opened for printing.
%
%    o image: The address of a structure of type Image;  returned from
%      ReadImage.
%
%    o geometry: A pointer to a standard window geometry string.
%
%
*/
unsigned int PrintImage(image,geometry)
Image
X  *image;
X
char
X  *geometry;
{
#define PageBottomMargin 92
#define PageLeftMargin 16
#define PageWidth  612
#define PageHeight 792
X
X  static char
X    *Postscript[]=
X    {
X      "%",
X      "% Display a color image.  The image is displayed in color on",
X      "% Postscript viewers or printers that support color, otherwise",
X      "% it is displayed as grayscale.",
X      "%",
X      "/buffer 512 string def",
X      "/byte 1 string def",
X      "/color_packet 3 string def",
X      "/compression 1 string def",
X      "/gray_packet 1 string def",
X      "/pixels 768 string def",
X      "",
X      "/DirectClassPacket",
X      "{",
X      "  %",
X      "  % Get a DirectClass packet.",
X      "  %",
X      "  % Parameters: ",
X      "  %   red.",
X      "  %   green.",
X      "  %   blue.",
X      "  %   length: number of pixels minus one of this color (optional).",
X      "  %",
X      "  currentfile color_packet readhexstring pop pop",
X      "  compression 0 gt",
X      "  {",
X      "    /number_pixels 3 def",
X      "  }",
X      "  {",
X      "    currentfile byte readhexstring pop 0 get",
X      "    /number_pixels exch 1 add 3 mul def",
X      "  } ifelse",
X      "  0 3 number_pixels 1 sub",
X      "  {",
X      "    pixels exch color_packet putinterval",
X      "  } for",
X      "  pixels 0 number_pixels getinterval",
X      "} bind def",
X      "",
X      "/DirectClassImage",
X      "{",
X      "  %",
X      "  % Display a DirectClass image.",
X      "  %",
X      "  systemdict /colorimage known",
X      "  {",
X      "    columns rows 8",
X      "    [",
X      "      columns 0 0",
X      "      rows neg 0 rows",
X      "    ]",
X      "    { DirectClassPacket } false 3 colorimage",
X      "  }",
X      "  {",
X      "    %",
X      "    % No colorimage operator;  convert to grayscale.",
X      "    %",
X      "    columns rows 8",
X      "    [",
X      "      columns 0 0",
X      "      rows neg 0 rows",
X      "    ]",
X      "    { GrayDirectClassPacket } image",
X      "  } ifelse",
X      "} bind def",
X      "",
X      "/GrayDirectClassPacket",
X      "{",
X      "  %",
X      "  % Get a DirectClass packet;  convert to grayscale.",
X      "  %",
X      "  % Parameters: ",
X      "  %   red",
X      "  %   green",
X      "  %   blue",
X      "  %   length: number of pixels minus one of this color (optional).",
X      "  %",
X      "  currentfile color_packet readhexstring pop pop",
X      "  color_packet 0 get 0.299 mul",
X      "  color_packet 1 get 0.587 mul add",
X      "  color_packet 2 get 0.114 mul add",
X      "  cvi",
X      "  /gray_packet exch def",
X      "  compression 0 gt",
X      "  {",
X      "    /number_pixels 1 def",
X      "  }",
X      "  {",
X      "    currentfile byte readhexstring pop 0 get",
X      "    /number_pixels exch 1 add def",
X      "  } ifelse",
X      "  0 1 number_pixels 1 sub",
X      "  {",
X      "    pixels exch gray_packet put",
X      "  } for",
X      "  pixels 0 number_pixels getinterval",
X      "} bind def",
X      "",
X      "/GrayPseudoClassPacket",
X      "{",
X      "  %",
X      "  % Get a PseudoClass packet;  convert to grayscale.",
X      "  %",
X      "  % Parameters: ",
X      "  %   index: index into the colormap.",
X      "  %   length: number of pixels minus one of this color (optional).",
X      "  %",
X      "  currentfile byte readhexstring pop 0 get",
X      "  /offset exch 3 mul def",
X      "  /color_packet colormap offset 3 getinterval def",
X      "  color_packet 0 get 0.299 mul",
X      "  color_packet 1 get 0.587 mul add",
X      "  color_packet 2 get 0.114 mul add",
X      "  cvi",
X      "  /gray_packet exch def",
X      "  compression 0 gt",
X      "  {",
X      "    /number_pixels 1 def",
X      "  }",
X      "  {",
X      "    currentfile byte readhexstring pop 0 get",
X      "    /number_pixels exch 1 add def",
X      "  } ifelse",
X      "  0 1 number_pixels 1 sub",
X      "  {",
X      "    pixels exch gray_packet put",
X      "  } for",
X      "  pixels 0 number_pixels getinterval",
X      "} bind def",
X      "",
X      "/PseudoClassPacket",
X      "{",
X      "  %",
X      "  % Get a PseudoClass packet.",
X      "  %",
X      "  % Parameters: ",
X      "  %   index: index into the colormap.",
X      "  %   length: number of pixels minus one of this color (optional).",
X      "  %",
X      "  %",
X      "  currentfile byte readhexstring pop 0 get",
X      "  /offset exch 3 mul def",
X      "  /color_packet colormap offset 3 getinterval def",
X      "  compression 0 gt",
X      "  {",
X      "    /number_pixels 3 def",
X      "  }",
X      "  {",
X      "    currentfile byte readhexstring pop 0 get",
X      "    /number_pixels exch 1 add 3 mul def",
X      "  } ifelse",
X      "  0 3 number_pixels 1 sub",
X      "  {",
X      "    pixels exch color_packet putinterval",
X      "  } for",
X      "  pixels 0 number_pixels getinterval",
X      "} bind def",
X      "",
X      "/PseudoClassImage",
X      "{",
X      "  %",
X      "  % Display a PseudoClass image.",
X      "  %",
X      "  % Parameters: ",
X      "  %   colors: number of colors in the colormap.",
X      "  %   colormap: red, green, blue color packets.",
X      "  %",
X      "  currentfile buffer readline pop",
X      "  token pop /colors exch def pop",
X      "  /colors colors 3 mul def",
X      "  /colormap colors string def",
X      "  currentfile colormap readhexstring pop pop",
X      "  systemdict /colorimage known",
X      "  {",
X      "    columns rows 8",
X      "    [",
X      "      columns 0 0",
X      "      rows neg 0 rows",
X      "    ]",
X      "    { PseudoClassPacket } false 3 colorimage",
X      "  }",
X      "  {",
X      "    %",
X      "    % No colorimage operator;  convert to grayscale.",
X      "    %",
X      "    columns rows 8",
X      "    [",
X      "      columns 0 0",
X      "      rows neg 0 rows",
X      "    ]",
X      "    { GrayPseudoClassPacket } image",
X      "  } ifelse",
X      "} bind def",
X      "",
X      "/DisplayImage",
X      "{",
X      "  %",
X      "  % Display a DirectClass or PseudoClass image.",
X      "  %",
X      "  % Parameters: ",
X      "  %   x & y translation.",
X      "  %   x & y scale.",
X      "  %   image columns & rows.",
X      "  %   class: 0-DirectClass or 1-PseudoClass.",
X      "  %   compression: 0-RunlengthEncodedCompression or 1-NoCompression.",
X      "  %   hex color packets.",
X      "  %",
X      "  gsave",
X      "  currentfile buffer readline pop",
X      "  token pop /x exch def",
X      "  token pop /y exch def pop",
X      "  x y translate",
X      "  currentfile buffer readline pop",
X      "  token pop /x exch def",
X      "  token pop /y exch def pop",
X      "  x y scale",
X      "  currentfile buffer readline pop",
X      "  token pop /columns exch def",
X      "  token pop /rows exch def pop",
X      "  currentfile buffer readline pop",
X      "  token pop /class exch def pop",
X      "  currentfile buffer readline pop",
X      "  token pop /compression exch def pop",
X      "  class 0 gt { PseudoClassImage } { DirectClassImage } ifelse",
X      "  grestore",
X      "  showpage",
X      "} bind def",
X      "",
X      "DisplayImage",
X      NULL
X    };
X
X  char
X    **q;
X
X  int
X    center,
X    x,
X    y;
X
X  register RunlengthPacket
X    *p;
X
X  register int
X    i,
X    j;
X
X  unsigned int
X    height,
X    width;
X
X  /*
X    Open output image file.
X  */
X  if (*image->filename == '-')
X    image->file=stdout;
X  else
X    image->file=fopen(image->filename,"w");
X  if (image->file == (FILE *) NULL)
X    {
X      (void) fprintf(stderr,"%s: unable to print image, cannot open %s.\n",
X        application_name,image->filename);
X      return(False);
X    }
X  width=image->columns;
X  height=image->rows;
X  center=True;
X  if (geometry != (char *) NULL)
X    {
X      int
X        flags;
X
X      /*
X        User specified Postscript page position.
X      */
X      x=0;
X      y=0;
X      flags=XParseGeometry(geometry,&x,&y,&width,&height);
X      center=(flags & (XValue | YValue)) == 0;
X      if (flags & XValue)
X        if (flags & XNegative)
X          x=PageWidth+x-width;
X      if (flags & YValue)
X        if (flags & YNegative)
X          y=PageHeight+y-height;
X      y=PageHeight-y-height;
X    }
X  if (center)
X    {
X      int
X        delta_x,
X        delta_y;
X
X      unsigned long
X        scale;
X
X      /*
X        Center image on Postscript page.
X      */
X      if (width > (PageWidth-(2*PageLeftMargin)))
X        {
X          scale=((PageWidth-(2*PageLeftMargin)) << 14)/width;
X          width=(width*scale) >> 14;
X          height=(height*scale) >> 14;
X        }
X      if (height > (PageHeight-(2*PageBottomMargin)))
X        {
X          scale=((PageHeight-(2*PageBottomMargin)) << 14)/height;
X          width=(width*scale) >> 14;
X          height=(height*scale) >> 14;
X        }
X      delta_x=PageWidth-(width+(2*PageLeftMargin));
X      delta_y=PageHeight-(height+(2*PageBottomMargin));
X      if (delta_x >= 0)
X        x=delta_x/2+PageLeftMargin;
X      else
X        x=PageLeftMargin;
X      if (delta_y >= 0)
X        y=delta_y/2+PageBottomMargin;
X      else
X        y=PageBottomMargin;
X    }
X  /*
X    Output encapsulated Postscript header.
X  */
X  (void) fprintf(image->file,"%%!PS-Adobe-2.0 EPSF-2.0\n");
X  (void) fprintf(image->file,"%%%%BoundingBox: %d %d %d %d\n",x,y,x+width,
X    y+height);
X  (void) fprintf(image->file,"%%%%Creator: ImageMagick\n");
X  (void) fprintf(image->file,"%%%%Title: %s\n",image->filename);
X  (void) fprintf(image->file,"%%%%EndComments\n");
X  /*
X    Output encapsulated Postscript commands.
X  */
X  for (q=Postscript; *q; q++)
X    (void) fprintf(image->file,"%s\n",*q);
X  /*
X    Output image data.
X  */
X  (void) fprintf(image->file,"%d %d\n%d %d\n%d %d\n%d\n%d\n",x,y,width,height,
X    image->columns,image->rows,(image->class == PseudoClass),
X    image->compression == NoCompression);
X  x=0;
X  p=image->pixels;
X  switch (image->class)
X  {
X    case DirectClass:
X    {
X      switch (image->compression)
X      {
X        case RunlengthEncodedCompression:
X        default:
X        {
X          /*
X            Dump runlength-encoded DirectColor packets.
X          */
X          for (i=0; i < image->packets; i++)
X          {
X            x++;
X            (void) fprintf(image->file,"%02x%02x%02x%02x",p->red,p->green,
X              p->blue,p->length);
X            if (x == 9)
X              {
X                x=0;
X                (void) fprintf(image->file,"\n");
X              }
X            p++;
X          }
X          break;
X        }
X        case NoCompression:
X        {
X          /*
X            Dump DirectColor packets.
X          */
X          for (i=0; i < image->packets; i++)
X          {
X            for (j=0; j <= p->length; j++)
X            {
X              x++;
X              (void) fprintf(image->file,"%02x%02x%02x",p->red,p->green,
X                p->blue);
X              if (x == 12)
X                {
X                  x=0;
X                  (void) fprintf(image->file,"\n");
X                }
X            }
X            p++;
X          }
X          break;
X        }
X      }
X      break;
X    }
X    case PseudoClass:
X    {
X      /*
X        Dump number of colors, colormap, PseudoColor packets.
X      */
X      (void) fprintf(image->file,"%d\n",image->colors);
X      for (i=0; i < image->colors; i++)
X        (void) fprintf(image->file,"%02x%02x%02x\n",image->colormap[i].red,
X          image->colormap[i].green,image->colormap[i].blue);
X      switch (image->compression)
X      {
X        case RunlengthEncodedCompression:
X        default:
X        {
X          for (i=0; i < image->packets; i++)
X          {
X            x++;
X            (void) fprintf(image->file,"%02x%02x",p->index,p->length);
X            if (x == 18)
X              {
X                x=0;
X                (void) fprintf(image->file,"\n");
X              }
X            p++;
X          }
X          break;
X        }
X        case NoCompression:
X        {
X          for (i=0; i < image->packets; i++)
X          {
X            for (j=0; j <= p->length; j++)
X            {
X              x++;
X              (void) fprintf(image->file,"%02x",p->index);
X              if (x == 36)
X                {
X                  x=0;
X                  (void) fprintf(image->file,"\n");
X                }
X            }
X            p++;
X          }
X        }
X        break;
X      }
X    }
X  }
X  (void) fprintf(image->file,"\n\n");
X  (void) fprintf(image->file,"%%%%Trailer\n");
X  if (image->file != stdin)
X    (void) fclose(image->file);
X  return(True);
}
X
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%  R e a d D a t a                                                            %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function ReadData reads data from the image file and returns it.  If it
%  cannot read the requested number of items, False is returned indicating
%  an error.
%
%  The format of the ReadData routine is:
%
%      status=ReadData(data,size,number_items,file)
%
%  A description of each parameter follows:
%
%    o status:  Function ReadData returns True if all the data requested
%      is obtained without error, otherwise False.
%
%    o data:  Specifies an area to place the information reuested from
%      the file.
%
%    o size:  Specifies an integer representing the length of an
%      individual item to be read from the file.
%
%    o numer_items:  Specifies an integer representing the number of items
%      to read from the file.
%
%    o file:  Specifies a file to read the data.
%
%
*/
unsigned int ReadData(data,size,number_items,file)
char
X  *data;
X
int
X  size,
X  number_items;
X
FILE
X  *file;
{
X  size*=number_items;
X  while (size > 0)
X  {
X    number_items=fread(data,1,size,file);
X    if (number_items <= 0)
X      return(False);
X    size-=number_items;
X    data+=number_items;
X  }
X  return(True);
}
X
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   R e a d I m a g e                                                         %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Function ReadImage reads an image file and returns it.  It allocates the
%  memory necessary for the new Image structure and returns a pointer to the
%  new image.
%
%  The format of the ReadImage routine is:
%
%      image=ReadImage(filename)
%
%  A description of each parameter follows:
%
%    o image: Function ReadImage returns a pointer to the image after reading.
%      A null image is returned if there is a a memory shortage or if the
%      image cannot be read.
%
%    o filename: Specifies the name of the image to read.
%
%
*/
Image *ReadImage(filename)
char
X  *filename;
{
#define MaxKeywordLength  256
X
X  char
X    keyword[MaxKeywordLength],
X    value[MaxKeywordLength];
X
X  Image
X    *image;
X
X  long int
X    count;
X
X  register int
X    c,
X    i;
X
X  register RunlengthPacket
X    *q;
X
X  register unsigned char
X    blue,
X    green,
X    *p,
X    red;
X
X  unsigned char
X    *pixels;
X
X  unsigned int
X    packets,
X    packet_size,
X    status;
X
X  /*
X    Allocate image structure.
X  */
X  image=(Image *) malloc(sizeof(Image));
X  if (image == (Image *) NULL)
X    return((Image *) NULL);
X  /*
X    Initialize Image structure.
X  */
X  image->id=UnknownId;
X  image->class=DirectClass;
X  image->compression=NoCompression;
X  image->columns=0;
X  image->rows=0;
X  image->packets=0;
X  image->colors=0;
X  image->scene=0;
X  image->colormap=(ColorPacket *) NULL;
X  image->pixels=(RunlengthPacket *) NULL;
X  image->comments=(char *) NULL;
X  /*
X    Open image file.
X  */
X  (void) strcpy(image->filename,filename);
X  if (*image->filename == '-')
X    image->file=stdin;
X  else
X    if (strcmp(image->filename+strlen(image->filename)-2,".Z") != 0)
X      image->file=fopen(image->filename,"r");
X    else
X      {
X        char
X          command[256];
X
X        /*
X          Image file is compressed-- uncompress it.
X        */
X        (void) sprintf(command,"uncompress -c %s",image->filename);
X        image->file=(FILE *) popen(command,"r");
X      }
X  if (image->file == (FILE *) NULL)
X    {
X      Warning("unable to open file",image->filename);
X      (void) DestroyImage(image);
X      return((Image *) NULL);
X    }
X  /*
X    Decode image header;  header terminates one character beyond a ':'.
X  */
X  do { c=fgetc(image->file); } while (isspace(c));
X  while ((c > 0) && (c != ':'))
X  {
X    register char
X      *p;
X
X    if (c == '{')
X      {
X        register char
X          *q;
X
X        /*
X          Comment.
X        */
X        if (image->comments == (char *) NULL)
X          {
X            /*
X              Allocate initial memory for a comment.
X            */
X            image->comments=(char *) malloc(256);
X            if (image->comments == (char *) NULL)
X              {
X                Warning("unable to read image","memory allocation failed");
X                DestroyImage(image);
X                return((Image *) NULL);
X              }
X            *image->comments=(char) NULL;
X          }
X        p=image->comments+strlen(image->comments);
X        q=p+(255-(strlen(image->comments) % 256));
X        c=fgetc(image->file);
X        while ((c > 0) && (c != '}'))
X        {
X          if (p == q)
X            {
X              /*
X                Allocate more memory for the comment.
X              */
X              image->comments=(char *) realloc((char *) image->comments,
X                (unsigned int) (strlen(image->comments)+256));
X              if (image->comments == (char *) NULL)
X                {
X                  Warning("unable to read image","memory allocation failed");
X                  DestroyImage(image);
X                  return((Image *) NULL);
X                }
X              q=p+255;
X            }
X          *p++=c;
X          c=fgetc(image->file);
X        }
X        *p=(char) NULL;
X        c=fgetc(image->file);
X      }
X    else
X      if (isalnum(c))
X        {
X          /*
X            Determine a keyword and its value.
X          */
X          p=keyword;
X          do
X          {
X            if ((p-keyword) < (MaxKeywordLength-1))
X              *p++=c;
X            c=fgetc(image->file);
X          } while (isalnum(c));
X          *p=(char) NULL;
X          while (isspace(c) || (c == '='))
X            c=fgetc(image->file);
X          p=value;
X          while (isalnum(c))
X          {
X            if ((p-value) < (MaxKeywordLength-1))
X              *p++=c;
X            c=fgetc(image->file);
X          }
X          *p=(char) NULL;
X          /*
X            Assign a value to the specified keyword.
X          */
X          if (strcmp(keyword,"class") == 0)
X            if (strcmp(value,"PseudoClass") == 0)
X              image->class=PseudoClass;
X            else
X              if (strcmp(value,"DirectClass") == 0)
X                image->class=DirectClass;
X              else
X                image->class=UnknownClass;
X          if (strcmp(keyword,"compression") == 0)
X            if (strcmp(value,"QEncoded") == 0)
X              image->compression=QEncodedCompression;
X            else
X              if (strcmp(value,"RunlengthEncoded") == 0)
X                image->compression=RunlengthEncodedCompression;
X              else
X                image->compression=UnknownCompression;
X          if (strcmp(keyword,"colors") == 0)
X            image->colors=(unsigned int) atoi(value);
X          if (strcmp(keyword,"columns") == 0)
X            image->columns=(unsigned int) atoi(value);
X          if (strcmp(keyword,"id") == 0)
X            if ((strcmp(value,"ImageMagick") == 0) ||
X                (strcmp(value,"XImager") == 0))
X              image->id=ImageMagickId;
X            else
X              image->id=UnknownId;
X          if (strcmp(keyword,"packets") == 0)
X            image->packets=(unsigned int) atoi(value);
X          if (strcmp(keyword,"rows") == 0)
X            image->rows=(unsigned int) atoi(value);
X          if (strcmp(keyword,"scene") == 0)
X            image->scene=(unsigned int) atoi(value);
X        }
X      else
X        c=fgetc(image->file);
X    while (isspace(c))
X      c=fgetc(image->file);
X  }
X  (void) fgetc(image->file);
X  /*
X    Verify that required image information is valid.
X  */
X  if ((image->id == UnknownId) ||
X      (image->class == UnknownClass) ||
X      (image->compression == UnknownCompression) ||
X      ((image->columns*image->rows) == 0))
X    {
X      Warning("incorrect image header in file",image->filename);
X      DestroyImage(image);
X      return((Image *) NULL);
X    }
X  if ((image->columns*image->rows) > MaxImageSize)
X    {
X      Warning("unable to read image","image size too large");
X      DestroyImage(image);
X      return((Image *) NULL);
X    }
X  /*
X    Read image from disk and convert to runlength-encoded packets.
X  */
X  switch (image->class)
X  {
X    case DirectClass:
X    {
X      /*
X        Transfer pixels to DirectClass image pixel buffer.
X      */
X      switch (image->compression)
X      {
X        case NoCompression:
X        {
X          /*
X            Allocate image buffers and read image from disk.
X          */
X          image->packets=image->columns*image->rows;
X          packet_size=3;
X          pixels=(unsigned char *)
X            malloc((unsigned int) image->packets*packet_size);
X          image->pixels=(RunlengthPacket *)
X            malloc(image->packets*sizeof(RunlengthPacket));
X          if ((pixels == (unsigned char *) NULL) ||
X              (image->pixels == (RunlengthPacket *) NULL))
X            {
X              Warning("unable to read image","memory allocation failed");
X              DestroyImage(image);
X              return((Image *) NULL);
X            }
X          status=ReadData((char *) pixels,(int) packet_size,(int)
X            image->packets,image->file);
X          if (status == False)
X            {
X              Warning("insufficient image data in file",image->filename);
X              DestroyImage(image);
X              return((Image *) NULL);
X            }
X          /*
X            Convert to runlength-encoded DirectClass packets.
X          */
X          image->packets=image->columns*image->rows;
X          p=pixels;
X          q=image->pixels;
X          for (i=0; i < image->packets; i++)
X          {
X            q->red=(*p++);
X            q->green=(*p++);
X            q->blue=(*p++);
X            q->index=0;
X            q->length=0;
X            q++;
X          }
X          break;
X        }
X        case QEncodedCompression:
X        {
X          extern unsigned int
X            QDecodeImage();
X
X          unsigned char
X            *compressed_pixels;
X
X          /*
X            Allocate image buffers and read image from disk.
X          */
X          packet_size=1;
X          if (image->packets == 0)
X            image->packets=image->columns*image->rows*3;
X          pixels=(unsigned char *)
X            malloc((unsigned int) image->packets*packet_size);
X          image->pixels=(RunlengthPacket *)
X            malloc(image->columns*image->rows*sizeof(RunlengthPacket));
X          if ((pixels == (unsigned char *) NULL) ||
X              (image->pixels == (RunlengthPacket *) NULL))
X            {
X              Warning("unable to read image","memory allocation failed");
X              DestroyImage(image);
X              return((Image *) NULL);
X            }
X          status=ReadData((char *) pixels,(int) packet_size,
X            (int) image->packets,image->file);
X          /*
X            Uncompress image.
X          */
X          image->packets=image->columns*image->rows;
X          packet_size=3;
X          compressed_pixels=pixels;
X          pixels=(unsigned char *)
X            malloc((unsigned int) image->packets*packet_size);
X          if (pixels == (unsigned char *) NULL)
X            {
X              Warning("unable to read image","memory allocation failed");
X              DestroyImage(image);
X              return((Image *) NULL);
X            }
X          packets=QDecodeImage(compressed_pixels,pixels,
X            image->columns*(int) packet_size,image->rows);
X          if (packets != (image->packets*packet_size))
X            {
X              Warning("insufficient image data in file",image->filename);
X              DestroyImage(image);
X              return((Image *) NULL);
X            }
X          (void) free((char *) compressed_pixels);
X          /*
X            Convert to runlength-encoded DirectClass packets.
X          */
X          p=pixels;
X          image->packets=0;
X          q=image->pixels;
X          q->length=MaxRunlength;
X          for (i=0; i < (image->columns*image->rows); i++)
X          {
X            red=(*p++);
X            green=(*p++);
X            blue=(*p++);
X            if ((red == q->red) && (green == q->green) && (blue == q->blue) &&
X                (q->length < MaxRunlength))
X              q->length++;
X            else
X              {
X                if (image->packets > 0)
X                  q++;
X                image->packets++;
X                q->red=red;
X                q->green=green;
X                q->blue=blue;
X                q->index=0;
X                q->length=0;
X              }
X          }
X          image->pixels=(RunlengthPacket *) realloc((char *) image->pixels,
X            image->packets*sizeof(RunlengthPacket));
X          break;
X        }
X        case RunlengthEncodedCompression:
X        {
X          /*
X            Allocate image buffers and read image from disk.
X          */
X          packet_size=4;
X          if (image->packets == 0)
X            {
X              /*
X                Number of packets is unspecified.
X              */
X              pixels=(unsigned char *)
X                malloc((unsigned int) (image->columns*image->rows*packet_size));
X              image->pixels=(RunlengthPacket *)
X                malloc(image->columns*image->rows*sizeof(RunlengthPacket));
X              if ((pixels == (unsigned char *) NULL) ||
X                  (image->pixels == (RunlengthPacket *) NULL))
X                {
X                  Warning("unable to read image","memory allocation failed");
X                  DestroyImage(image);
X                  return((Image *) NULL);
X                }
X              count=0;
X              image->packets=0;
X              p=pixels;
X              do
X              {
X                (void) ReadData((char *) p,(int) packet_size,1,image->file);
X                image->packets++;
X                p+=(packet_size-1);
X                count+=(*p+1);
X                p++;
X              }
X              while (count < (image->columns*image->rows));
X              p=pixels;
X            }
X          else
X            {
X              pixels=(unsigned char *)
X                malloc((unsigned int) image->packets*packet_size);
X              image->pixels=(RunlengthPacket *)
X                malloc(image->packets*sizeof(RunlengthPacket));
X              if ((pixels == (unsigned char *) NULL) ||
X                  (image->pixels == (RunlengthPacket *) NULL))
X                {
X                  Warning("unable to read image","memory allocation failed");
X                  DestroyImage(image);
X                  return((Image *) NULL);
X                }
X              (void) ReadData((char *) pixels,(int) packet_size,
X                (int) image->packets,image->file);
X            }
X          count=0;
X          p=pixels;
X          q=image->pixels;
X          for (i=0; i < image->packets; i++)
X          {
X            q->red=(*p++);
X            q->green=(*p++);
X            q->blue=(*p++);
X            q->index=0;
X            q->length=(*p++);
X            count+=(q->length+1);
X            q++;
X          }
X          /*
X            Guarentee the correct number of runlength packets.
X          */
X          if (count > (image->columns*image->rows))
X            {
X              Warning("insufficient image data in file",image->filename);
X              DestroyImage(image);
X              return((Image *) NULL);
X            }
X          else
X            if (count < (image->columns*image->rows))
X              {
X                Warning("too much image data in file",image->filename);
X                DestroyImage(image);
X                return((Image *) NULL);
X              }
X          break;
X        }
X      }
X      break;
X    }
X    case PseudoClass:
X    {
X      register unsigned short
X        index;
X
X      if (image->colors == 0)
X        {
X          /*
X            Create grayscale map.
X          */
X          image->colors=256;
X          image->colormap=(ColorPacket *)
X            malloc(image->colors*sizeof(ColorPacket));
X          if (image->colormap == (ColorPacket *) NULL)
X            {
X              Warning("unable to read image","memory allocation failed");
X              DestroyImage(image);
X              return((Image *) NULL);
X            }
X          for (i=0; i < image->colors; i++)
X          {
X            image->colormap[i].red=(unsigned char) i;
X            image->colormap[i].green=(unsigned char) i;
X            image->colormap[i].blue=(unsigned char) i;
X          }
X        }
X      else
X        {
X          unsigned char
X            *colormap;
X
X          /*
X            Read colormap from disk.
X          */
X          packet_size=3;
X          colormap=(unsigned char *)
X            malloc((unsigned int) image->colors*packet_size);
X          image->colormap=(ColorPacket *)
X            malloc(image->colors*sizeof(ColorPacket));
X          if ((colormap == (unsigned char *) NULL) ||
X              (image->colormap == (ColorPacket *) NULL))
X            {
X              Warning("unable to read image","memory allocation failed");
X              DestroyImage(image);
X              return((Image *) NULL);
X            }
X          (void) ReadData((char *) colormap,(int) packet_size,
X            (int) image->colors,image->file);
X          p=colormap;
X          for (i=0; i < image->colors; i++)
X          {
X            image->colormap[i].red=(*p++);
X            image->colormap[i].green=(*p++);
X            image->colormap[i].blue=(*p++);
X          }
X          (void) free((char *) colormap);
X        }
X      /*
X        Transfer pixels to PseudoClass image pixel buffer.
X      */
X      switch (image->compression)
X      {
X        case NoCompression:
X        {
X          /*
X            Allocate image buffers and read image from disk.
X          */
X          image->packets=image->columns*image->rows;
X          packet_size=1;
X          if (image->colors > 256)
X            packet_size++;
X          pixels=(unsigned char *)
X            malloc((unsigned int) image->packets*packet_size);
X          image->pixels=(RunlengthPacket *)
X            malloc(image->packets*sizeof(RunlengthPacket));
X          if ((pixels == (unsigned char *) NULL) ||
X              (image->pixels == (RunlengthPacket *) NULL))
X            {
X              Warning("unable to read image","memory allocation failed");
X              DestroyImage(image);
X              return((Image *) NULL);
X            }
X          status=ReadData((char *) pixels,(int) packet_size,
X            (int) (image->columns*image->rows),image->file);
X          if (status == False)
X            {
X              Warning("insufficient image data in file",image->filename);
X              DestroyImage(image);
X              return((Image *) NULL);
X            }
X          /*
X            Convert to runlength-encoded PseudoClass packets.
X          */
X          image->packets=image->columns*image->rows;
X          p=pixels;
X          q=image->pixels;
X          if (image->colors <= 256)
X            for (i=0; i < image->packets; i++)
X            {
X              index=(*p++);
X              q->red=image->colormap[index].red;
X              q->green=image->colormap[index].green;
X              q->blue=image->colormap[index].blue;
X              q->index=index;
X              q->length=0;
X              q++;
X            }
X          else
X            for (i=0; i < image->packets; i++)
X            {
X              index=(*p++) << 8;
X              index|=(*p++);
X              q->red=image->colormap[index].red;
X              q->green=image->colormap[index].green;
X              q->blue=image->colormap[index].blue;
X              q->index=index;
X              q->length=0;
X              q++;
X            }
X          break;
X        }
X        case QEncodedCompression:
X        {
X          extern unsigned int
X            QDecodeImage();
X
X          unsigned char
X            *compressed_pixels;
X
X          /*
X            Allocate image buffers and read image from disk.
X          */
X          packet_size=1;
X          if (image->packets == 0)
X            image->packets=(image->columns*image->rows)*
X              (image->colors > 256 ? 2 : 1);
X          pixels=(unsigned char *)
X            malloc((unsigned int) image->packets*packet_size);
X          image->pixels=(RunlengthPacket *)
X            malloc(image->columns*image->rows*sizeof(RunlengthPacket));
X          if ((pixels == (unsigned char *) NULL) ||
X              (image->pixels == (RunlengthPacket *) NULL))
X            {
X              Warning("unable to allocate memory",(char *) NULL);
X              DestroyImage(image);
X              return((Image *) NULL);
X            }
X          status=ReadData((char *) pixels,(int) packet_size,
X            (int) image->packets,image->file);
X          /*
X            Uncompress image.
X          */
X          image->packets=image->columns*image->rows;
X          packet_size=1;
X          if (image->colors > 256)
X            packet_size++;
X          compressed_pixels=pixels;
X          pixels=(unsigned char *)
X            malloc((unsigned int) image->packets*packet_size);
X          if (pixels == (unsigned char *) NULL)
X            {
X              Warning("unable to read image","memory allocation failed");
X              DestroyImage(image);
X              return((Image *) NULL);
X            }
X          packets=QDecodeImage(compressed_pixels,pixels,image->columns*
X            (int) packet_size,image->rows);
X          if (packets != (image->packets*packet_size))
X            {
X              Warning("insufficient image data in file",image->filename);
X              DestroyImage(image);
X              return((Image *) NULL);
X            }
X          (void) free((char *) compressed_pixels);
X          /*
X            Convert to runlength-encoded PseudoClass packets.
X          */
X          p=pixels;
X          image->packets=0;
X          q=image->pixels;
X          q->length=MaxRunlength;
X          if (image->colors <= 256)
X            for (i=0; i < (image->columns*image->rows); i++)
X            {
X              index=(*p++);
X              red=image->colormap[index].red;
X              green=image->colormap[index].green;
X              blue=image->colormap[index].blue;
X              if ((red == q->red) && (green == q->green) && (blue == q->blue) &&
X                  (q->length < MaxRunlength))
X                q->length++;
X              else
X                {
X                  if (image->packets > 0)
X                    q++;
X                  image->packets++;
X                  q->red=red;
X                  q->green=green;
X                  q->blue=blue;
X                  q->index=index;
X                  q->length=0;
X                }
X            }
X          else
X            for (i=0; i < (image->columns*image->rows); i++)
X            {
X              index=(*p++) << 8;
X              index|=(*p++);
X              red=image->colormap[index].red;
X              green=image->colormap[index].green;
X              blue=image->colormap[index].blue;
X              if ((red == q->red) && (green == q->green) && (blue == q->blue) &&
X                  (q->length < MaxRunlength))
X                q->length++;
X              else
X                {
X                  if (image->packets > 0)
X                    q++;
X                  image->packets++;
X                  q->red=red;
X                  q->green=green;
X                  q->blue=blue;
X                  q->index=index;
X                  q->length=0;
X                }
X            }
X          image->pixels=(RunlengthPacket *) realloc((char *) image->pixels,
X            image->packets*sizeof(RunlengthPacket));
X          break;
X        }
X        case RunlengthEncodedCompression:
X        {
X          packet_size=2;
X          if (image->colors > 256)
X            packet_size++;
X          if (image->packets == 0)
X            {
X              /*
X                Number of packets is unspecified.
X              */
X              pixels=(unsigned char *)
X                malloc((unsigned int) (image->columns*image->rows*packet_size));
X              image->pixels=(RunlengthPacket *)
X                malloc((unsigned int) packets*sizeof(RunlengthPacket));
X              if ((pixels == (unsigned char *) NULL) ||
X                  (image->pixels == (RunlengthPacket *) NULL))
X                {
X                  Warning("unable to read image","memory allocation failed");
X                  DestroyImage(image);
X                  return((Image *) NULL);
X                }
X              count=0;
X              image->packets=0;
X              p=pixels;
X              do
X              {
X                (void) ReadData((char *) p,(int) packet_size,1,image->file);
X                image->packets++;
X                p+=(packet_size-1);
X                count+=(*p+1);
X                p++;
X              }
X              while (count < (image->columns*image->rows));
X            }
X          else
X            {
X              pixels=(unsigned char *)
X                malloc((unsigned int) image->packets*packet_size);
X              image->pixels=(RunlengthPacket *)
X                malloc(image->packets*sizeof(RunlengthPacket));
X              if ((pixels == (unsigned char *) NULL) ||
X                  (image->pixels == (RunlengthPacket *) NULL))
X                {
X                  Warning("unable to read image","memory allocation failed");
X                  DestroyImage(image);
X                  return((Image *) NULL);
X                }
X              (void) ReadData((char *) pixels,(int) packet_size,
X                (int) image->packets,image->file);
X            }
X          count=0;
X          p=pixels;
X          q=image->pixels;
X          if (image->colors <= 256)
X            for (i=0; i < image->packets; i++)
X            {
X              index=(*p++);
X              q->red=image->colormap[index].red;
X              q->green=image->colormap[index].green;
X              q->blue=image->colormap[index].blue;
X              q->index=index;
X              q->length=(*p++);
X              count+=(q->length+1);
X              q++;
X            }
X          else
X            for (i=0; i < image->packets; i++)
X            {
X              index=(*p++) << 8;
X              index|=(*p++);
X              q->red=image->colormap[index].red;
X              q->green=image->colormap[index].green;
X              q->blue=image->colormap[index].blue;
X              q->index=index;
X              q->length=(*p++);
SHAR_EOF
true || echo 'restore of ImageMagick/image.c failed'
fi
echo 'End of ImageMagick part 4'
echo 'File ImageMagick/image.c is continued in part 5'
echo 5 > _shar_seq_.tmp
exit 0
--
Dan Heller
O'Reilly && Associates       Z-Code Software    Comp-sources-x:
Senior Writer                President          comp-sources-x at uunet.uu.net
argv at ora.com                 argv at zipcode.com



More information about the Comp.sources.x mailing list