Image		*get_blue_channe_image(Image *img)
{
  unsigned int	i = 0;
  unsigned int	j = 0;
  PixelPacket	*px_original;
  PixelPacket	*px_new;
  Image		*new_img;
  ExceptionInfo	exception;
  ImageInfo	*new_img_info;

  GetExceptionInfo(&exception);
  if ((new_img_info = CloneImageInfo((ImageInfo *)NULL)) == NULL) {
    CatchException(&exception);
    DestroyImageInfo(new_img_info);
    return (NULL);
  }

  new_img_info->colorspace = RGBColorspace;
  new_img = AllocateImage(new_img_info);
  new_img->rows = img->rows;
  new_img->columns = img->columns;

  if ((px_original = GetImagePixelsEx(img, 0, 0, img->columns, img->rows, &exception)) == NULL)
    {
      DestroyImage(new_img);
      CatchException(&exception);
      return (NULL);
    }

  if ((px_new = SetImagePixelsEx(new_img, 0, 0, new_img->columns, new_img->rows, &exception)) == NULL)
    {
      DestroyImage(new_img);
      CatchException(&exception);
      return (NULL);
    }

  while (i < img->rows)
    {
      j = 0;
      while (j < img->columns)
	{
	  px_new[(new_img->columns * i) + j].red = 0;
	  px_new[(new_img->columns * i) + j].blue = px_original[(img->columns * i) + j].blue;
	  px_new[(new_img->columns * i) + j].green = 0;
	  j++;
	}
      i++;
    }
  SyncImagePixels(new_img);

  DestroyImageInfo(new_img_info);

  return (new_img);
}
Image		*get_green_grayscale_image(Image *img)
{
  unsigned int	i = 0;
  unsigned int	j = 0;
  PixelPacket	*px_original;
  Image		*new_img;
  ExceptionInfo	exception;
  unsigned char *new_raw_image;

  GetExceptionInfo(&exception);

  if ((px_original = GetImagePixelsEx(img, 0, 0, img->columns, img->rows, &exception)) == NULL)
    {
      CatchException(&exception);
      return (NULL);
    }

  new_raw_image = malloc((img->rows * img->columns) * sizeof(*new_raw_image));

  while (i < img->rows)
    {
      j = 0;
      while (j < img->columns)
	{
	  new_raw_image[(img->columns * i) + j] = px_original[(img->columns * i) + j].green;
	  j++;
	}
      i++;
    }

  if ((new_img = ConstituteImage(img->columns, img->rows, "I", CharPixel, new_raw_image, &exception)) == NULL) {
    CatchException(&exception);
    return (NULL);
  }

  free(new_raw_image);
  return (new_img);
}
Beispiel #3
0
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   P i x e l I t e r a t e T r i p l e M o d i f y                           %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  PixelIterateTripleModify() iterates through pixel regions of three images
%  and invokes a user-provided callback function (of type
%  PixelIteratorTripleModifyCallback) for each row of pixels.  The first two
%  images are read-only, while the third image is read-write for update.
%  Access of the first two images is done lock-step using the same coordinates.
%  This is useful to support operations such as image differencing.
%
%  The format of the PixelIterateTripleModify method is:
%
%      MagickPassFail PixelIterateTripleModify(
%                                PixelIteratorTripleModifyCallback call_back,
%                                const PixelIteratorOptions *options,
%                                const char *description,
%                                void *mutable_data,
%                                const void *immutable_data,
%                                const unsigned long columns,
%                                const unsigned long rows,
%                                const Image *source1_image,
%                                const Image *source2_image,
%                                const long source_x,
%                                const long source_y,
%                                Image *update_image,
%                                const long update_x,
%                                const long update_y,
%                                ExceptionInfo *exception)
%
%  A description of each parameter follows:
%
%    o call_back: A user-provided C callback function which reads from
%      a region of source pixels and updates a region of destination pixels.
%
%    o options: Pixel iterator execution options (may be NULL).
%
%    o description: textual description of operation being performed.
%
%    o mutable_data: User-provided mutable context data.
%
%    o immutable_data: User-provided immutable context data.
%
%    o columns: Width of pixel region
%
%    o rows: Height of pixel region
%
%    o source1_image: The address of the constant source 1 Image.
%
%    o source2_image: The address of the constant source 2 Image.
%
%    o source_x: The horizontal ordinate of the top left corner of the source regions.
%
%    o source_y: The vertical ordinate of the top left corner of the source regions.
%
%    o update_image: The address of the update Image.
%
%    o update_x: The horizontal ordinate of the top left corner of the update region.
%
%    o update_y: The vertical ordinate of the top left corner of the update region.
%
%    o exception: If an error is reported, this argument is updated with the reason.
%
*/
static MagickPassFail
PixelIterateTripleImplementation(PixelIteratorTripleModifyCallback call_back,
                                 const PixelIteratorOptions *options,
                                 const char *description,
                                 void *mutable_data,
                                 const void *immutable_data,
                                 const unsigned long columns,
                                 const unsigned long rows,
                                 const Image *source1_image,
                                 const Image *source2_image,
                                 const long source_x,
                                 const long source_y,
                                 Image *update_image,
                                 const long update_x,
                                 const long update_y,
                                 ExceptionInfo *exception,
                                 MagickBool set)
{
  MagickPassFail
    status = MagickPass;

  register long
    row;

  unsigned long
    row_count=0;

  int
    max_threads;

  max_threads=omp_get_max_threads();
  (void) SetRegionThreads(max_threads,options,columns,rows);

#if defined(HAVE_OPENMP)
#  pragma omp parallel for schedule(static,1) shared(row_count, status)
#endif
  for (row=0; row < (long) rows; row++)
    {
      MagickBool
        thread_status;

      const PixelPacket
        *source1_pixels,
        *source2_pixels;

      const IndexPacket
        *source1_indexes,
        *source2_indexes;

      PixelPacket
        *update_pixels;

      IndexPacket
        *update_indexes;

      long
        source_row,
        update_row;

      thread_status=status;
      if (thread_status == MagickFail)
        continue;

      source_row=source_y+row;
      update_row=update_y+row;

      /*
        First image (read only).
      */
      source1_pixels=AcquireImagePixels(source1_image, source_x, source_row,
                                        columns, 1, exception);
      if (!source1_pixels)
        thread_status=MagickFail;
      source1_indexes=AccessImmutableIndexes(source1_image);

      /*
        Second image (read only).
      */
      source2_pixels=AcquireImagePixels(source2_image, source_x, source_row,
                                        columns, 1, exception);
      if (!source2_pixels)
        thread_status=MagickFail;
      source2_indexes=AccessImmutableIndexes(source2_image);

      /*
        Third image (read/write).
      */
      if (set)
        update_pixels=SetImagePixelsEx(update_image, update_x, update_row,
                                       columns, 1, exception);
      else
        update_pixels=GetImagePixelsEx(update_image, update_x, update_row,
                                       columns, 1, exception);
      if (!update_pixels)
        {
          thread_status=MagickFail;
          CopyException(exception,&update_image->exception);
        }
      update_indexes=AccessMutableIndexes(update_image);

      if (thread_status != MagickFail)
        status=(call_back)(mutable_data,immutable_data,
                           source1_image,source1_pixels,source1_indexes,
                           source2_image,source2_pixels,source2_indexes,
                           update_image,update_pixels,update_indexes,
                           columns,exception);
      
      if (!SyncImagePixelsEx(update_image,exception))
        thread_status=MagickFail;

#if defined(HAVE_OPENMP)
#  pragma omp critical (GM_PixelIterateTripleImplementation)
#endif
      {
        row_count++;
        if (QuantumTick(row_count,rows))
          if (!MagickMonitorFormatted(row_count,rows,exception,description,
                                      source1_image->filename,
                                      source2_image->filename,
                                      update_image->filename))
            thread_status=MagickFail;

        if (thread_status == MagickFail)
          status=MagickFail;
      }
    }

  omp_set_num_threads(max_threads);

  return (status);
}
Beispiel #4
0
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   P i x e l I t e r a t e M o n o M o d i f y                               %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  PixelIterateMonoModify() iterates through a region of an image and invokes
%  a user-provided callback function (of type PixelIteratorMonoReadCallback)
%  for a region of pixels. This is useful to support simple operations such as
%  level shifting, colorspace translation, or thresholding.
%
%  The format of the PixelIterateMonoModify method is:
%
%      MagickPassFail PixelIterateMonoModify(
%                              PixelIteratorMonoModifyCallback call_back,
%                              const PixelIteratorOptions *options,
%                              const char *description,
%                              void *mutable_data,
%                              const void *immutable_data,
%                              const long x,
%                              const long y,
%                              const unsigned long columns,
%                              const unsigned long rows,
%                              Image *image,
%                              ExceptionInfo *exception)
%
%  A description of each parameter follows:
%
%    o call_back: A user-provided C callback function which is passed the
%       address of pixels from each image.
%
%    o options: Pixel iterator execution options (may be NULL).
%
%    o description: textual description of operation being performed.
%
%    o mutable_data: User-provided mutable context data.
%
%    o immutable_data: User-provided immutable context data.
%
%    o x: The horizontal ordinate of the top left corner of the region.
%
%    o y: The vertical ordinate of the top left corner of the region.
%
%    o columns: Width of pixel region
%
%    o rows: Height of pixel region
%
%    o image: The address of the Image.
%
%    o exception: If an error is reported, this argument is updated with the reason.
%
*/
MagickExport MagickPassFail
PixelIterateMonoModify(PixelIteratorMonoModifyCallback call_back,
                       const PixelIteratorOptions *options,
                       const char *description,
                       void *mutable_data,
                       const void *immutable_data,
                       const long x,
                       const long y,
                       const unsigned long columns,
                       const unsigned long rows,
                       Image *image,
                       ExceptionInfo *exception)
{
  MagickPassFail
    status = MagickPass;

  register long
    row;

  unsigned long
    row_count=0;

  int
    max_threads;

  max_threads=omp_get_max_threads();
  (void) SetRegionThreads(max_threads,options,columns,rows);

#if defined(HAVE_OPENMP)
#  pragma omp parallel for schedule(static,1) shared(row_count, status)
#endif
  for (row=y; row < (long) (y+rows); row++)
    {
      MagickBool
        thread_status;

      PixelPacket
        *pixels;

      IndexPacket
        *indexes;

      thread_status=status;
      if (thread_status == MagickFail)
        continue;

      pixels=GetImagePixelsEx(image, x, row, columns, 1, exception);
      if (!pixels)
        thread_status=MagickFail;
      indexes=AccessMutableIndexes(image);
      
      if (thread_status != MagickFail)
        thread_status=(call_back)(mutable_data,immutable_data,image,pixels,indexes,columns,exception);

      if (thread_status != MagickFail)
        if (!SyncImagePixelsEx(image,exception))
          thread_status=MagickFail;

#if defined(HAVE_OPENMP)
#  pragma omp critical (GM_PixelIterateMonoModify)
#endif
      {
        row_count++;
        if (QuantumTick(row_count,rows))
          if (!MagickMonitorFormatted(row_count,rows,exception,
                                      description,image->filename))
            thread_status=MagickFail;

        if (thread_status == MagickFail)
          status=MagickFail;
      }
    }

  omp_set_num_threads(max_threads);

  return (status);
}
Beispiel #5
0
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   R e a d S C T I m a g e                                                   %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Method ReadSCTImage reads a Scitex 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 ReadSCTImage method is:
%
%      Image *ReadSCTImage(const ImageInfo *image_info,ExceptionInfo *exception)
%
%  A description of each parameter follows:
%
%    o image:  Method ReadSCTImage returns a pointer to the image after
%      reading.  A null image is returned if there is a memory shortage or
%      if the image cannot be read.
%
%    o image_info: Specifies a pointer to a ImageInfo structure.
%
%    o exception: return any errors or warnings in this structure.
%
%
*/
static Image *ReadSCTImage(const ImageInfo *image_info,ExceptionInfo *exception)
{
  char
    buffer[768],
    magick[2];

  Image
    *image;

  long
    y;

  register long
    x;

  register PixelPacket
    *q;

  int
    c;

  unsigned int
    status;

  /*
    Open image file.
  */
  assert(image_info != (const ImageInfo *) NULL);
  assert(image_info->signature == MagickSignature);
  assert(exception != (ExceptionInfo *) NULL);
  assert(exception->signature == MagickSignature);
  image=AllocateImage(image_info);
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
  if (status == False)
    ThrowReaderException(FileOpenError,UnableToOpenFile,image);
  /*
    Read control block.
  */
  do
    {
      if (ReadBlob(image,80,(char *) buffer) != 80)
        break;
      if (ReadBlob(image,2,(char *) magick) != 2)
        break;
      if ((LocaleNCompare((char *) magick,"CT",2) != 0) &&
          (LocaleNCompare((char *) magick,"LW",2) != 0) &&
          (LocaleNCompare((char *) magick,"BM",2) != 0) &&
          (LocaleNCompare((char *) magick,"PG",2) != 0) &&
          (LocaleNCompare((char *) magick,"TX",2) != 0))
        ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
      if ((LocaleNCompare((char *) magick,"LW",2) == 0) ||
          (LocaleNCompare((char *) magick,"BM",2) == 0) ||
          (LocaleNCompare((char *) magick,"PG",2) == 0) ||
          (LocaleNCompare((char *) magick,"TX",2) == 0))
        ThrowReaderException(CoderError,OnlyContinuousTonePictureSupported,image);
      if (ReadBlob(image,174,(char *) buffer) != 174)
        break;
      if (ReadBlob(image,768,(char *) buffer) != 768)
        break;
      /*
        Read parameter block.
      */
      if (ReadBlob(image,32,(char *) buffer) != 32)
        break;
      if (ReadBlob(image,14,(char *) buffer) != 14)
        break;
      image->rows=MagickAtoL(buffer) & 0x7FFFFFFF;
      if (ReadBlob(image,14,(char *) buffer) != 14)
        break;
      image->columns=MagickAtoL(buffer) & 0x7FFFFFFF;
      if (ReadBlob(image,196,(char *) buffer) != 196)
        break;
      if (ReadBlob(image,768,(char *) buffer) != 768)
        break;
      image->colorspace=CMYKColorspace;
    }
  while (0);
  if (EOFBlob(image))
    ThrowReaderException(CorruptImageError,UnexpectedEndOfFile,image);
  if (image_info->ping)
    {
      CloseBlob(image);
      return(image);
    }

  if (CheckImagePixelLimits(image, exception) != MagickPass)
    ThrowReaderException(ResourceLimitError,ImagePixelLimitExceeded,image);

  /*
    Convert SCT raster image to pixel packets.
  */
  for (y=0; y < (long) image->rows; y++)
  {
    q=SetImagePixelsEx(image,0,y,image->columns,1,exception);
    if (q == (PixelPacket *) NULL)
      break;
    for (x=0; x < (long) image->columns; x++)
    {
      if ((c = ReadBlobByte(image)) == EOF)
        break;
      q->red=(Quantum) (MaxRGB-ScaleCharToQuantum(c));
      q++;
    }
    if ((image->columns % 2) != 0)
      if (ReadBlobByte(image) == EOF)  /* pad */
        break;
    q=GetImagePixelsEx(image,0,y,image->columns,1,exception);
    if (q == (PixelPacket *) NULL)
      break;
    for (x=0; x < (long) image->columns; x++)
    {
      if ((c = ReadBlobByte(image)) == EOF)
        break;
      q->green=(Quantum) (MaxRGB-ScaleCharToQuantum(c));
      q++;
    }
    if ((image->columns % 2) != 0)
      if (ReadBlobByte(image) == EOF)  /* pad */
        break;
    q=GetImagePixelsEx(image,0,y,image->columns,1,exception);
    if (q == (PixelPacket *) NULL)
      break;
    for (x=0; x < (long) image->columns; x++)
    {
      if ((c = ReadBlobByte(image)) == EOF)
        break;
      q->blue=(Quantum) (MaxRGB-ScaleCharToQuantum(c));
      q++;
    }
    if ((image->columns % 2) != 0)
      if (ReadBlobByte(image) == EOF)  /* pad */
        break;
    q=GetImagePixelsEx(image,0,y,image->columns,1,exception);
    if (q == (PixelPacket *) NULL)
      break;
    for (x=0; x < (long) image->columns; x++)
    {
      if ((c = ReadBlobByte(image)) == EOF)
        break;
      q->opacity=(Quantum) (MaxRGB-ScaleCharToQuantum(c));
      q++;
    }
    if (!SyncImagePixelsEx(image,exception))
      break;
    if ((image->columns % 2) != 0)
      if (ReadBlobByte(image) == EOF)  /* pad */
        break;
    if (QuantumTick(y,image->rows))
      if (!MagickMonitorFormatted(y,image->rows,exception,LoadImageText,
                                  image->filename,
				  image->columns,image->rows))
        break;
    if (EOFBlob(image))
      break;
  }
  if (EOFBlob(image))
    ThrowException(exception,CorruptImageError,UnexpectedEndOfFile,
      image->filename);
  CloseBlob(image);
  return(image);
}
Beispiel #6
0
static void XShearImage(Image *image,const double degrees,
                        const unsigned long width,const unsigned long height,
                        const long x_offset,long y_offset)
{
#define XShearImageText  "[%s] X Shear: %+g degrees, region %lux%lu%+ld%+ld...  "

  long
    y;

  unsigned long
    row_count=0;

  unsigned int
    is_grayscale;

  MagickPassFail
    status=MagickPass;

  assert(image != (Image *) NULL);
  is_grayscale=image->is_grayscale;

#if defined(HAVE_OPENMP)
#  pragma omp parallel for schedule(dynamic,8) shared(row_count, status)
#endif
  for (y=0; y < (long) height; y++)
    {
      double
        alpha,
        displacement;

      long
        step;

      PixelPacket
        pixel;

      register long
        i;

      register PixelPacket
        *p,
        *q;

      enum
        {
          LEFT,
          RIGHT
        } direction;

      MagickPassFail
        thread_status;
      
      thread_status=status;
      if (thread_status == MagickFail)
        continue;

      displacement=degrees*(y-height/2.0);
      if (displacement == 0.0)
        continue;
      if (displacement > 0.0)
        direction=RIGHT;
      else
        {
          displacement*=(-1.0);
          direction=LEFT;
        }
      step=(long) floor(displacement);
      alpha=MaxRGBDouble*(displacement-step);
      if (alpha == 0.0)
        {
          /*
            No fractional displacement-- just copy.
          */
          switch (direction)
            {
            case LEFT:
              {
                /*
                  Transfer pixels left-to-right.
                */
                if (step > x_offset)
                  break;
                p=GetImagePixelsEx(image,0,y+y_offset,image->columns,1,&image->exception);
                if (p == (PixelPacket *) NULL)
                  {
                    thread_status=MagickFail;
                    break;
                  }
                p+=x_offset;
                q=p-step;
                (void) memcpy(q,p,width*sizeof(PixelPacket));
                q+=width;
                for (i=0; i < (long) step; i++)
                  *q++=image->background_color;
                break;
              }
            case RIGHT:
              {
                /*
                  Transfer pixels right-to-left.
                */
                p=GetImagePixelsEx(image,0,y+y_offset,image->columns,1,&image->exception);
                if (p == (PixelPacket *) NULL)
                  {
                    thread_status=MagickFail;
                    break;
                  }
                p+=x_offset+width;
                q=p+step;
                for (i=0; i < (long) width; i++)
                  *--q=(*--p);
                for (i=0; i < (long) step; i++)
                  *--q=image->background_color;
                break;
              }
            }
          if (!SyncImagePixelsEx(image,&image->exception))
            thread_status=MagickFail;

#if defined(HAVE_OPENMP)
#  pragma omp critical (GM_XShearImage)
#endif
          {
            row_count++;
            if (QuantumTick(row_count,height))
              if (!MagickMonitorFormatted(row_count,height,&image->exception,
                                          XShearImageText,image->filename,
					  degrees,width,height,
					  x_offset,y_offset))
                thread_status=MagickFail;
            
            if (thread_status == MagickFail)
              status=MagickFail;
          }

          continue;
        }
      /*
        Fractional displacement.
      */
      step++;
      pixel=image->background_color;
      switch (direction)
        {
        case LEFT:
          {
            /*
              Transfer pixels left-to-right.
            */
            if (step > x_offset)
              break;
            p=GetImagePixelsEx(image,0,y+y_offset,image->columns,1,&image->exception);
            if (p == (PixelPacket *) NULL)
              {
                thread_status=MagickFail;
                break;
              }
            p+=x_offset;
            q=p-step;
            for (i=0; i < (long) width; i++)
              {
                if ((x_offset+i) < step)
                  {
                    pixel=(*++p);
                    q++;
                    continue;
                  }
                BlendCompositePixel(q,&pixel,p,alpha);
                q++;
                pixel=(*p++);
              }
            BlendCompositePixel(q,&pixel,&image->background_color,alpha);
            q++;
            for (i=0; i < (step-1); i++)
              *q++=image->background_color;
            break;
          }
        case RIGHT:
          {
            /*
              Transfer pixels right-to-left.
            */
            p=GetImagePixelsEx(image,0,y+y_offset,image->columns,1,&image->exception);
            if (p == (PixelPacket *) NULL)
              {
                thread_status=MagickFail;
                break;
              }
            p+=x_offset+width;
            q=p+step;
            for (i=0; i < (long) width; i++)
              {
                p--;
                q--;
                if ((x_offset+width+step-i) >= image->columns)
                  continue;
                BlendCompositePixel(q,&pixel,p,alpha);
                pixel=(*p);
              }
            --q;
            BlendCompositePixel(q,&pixel,&image->background_color,alpha);
            for (i=0; i < (step-1); i++)
              *--q=image->background_color;
            break;
          }
        }
      if (!SyncImagePixelsEx(image,&image->exception))
        thread_status=MagickFail;
#if defined(HAVE_OPENMP)
#  pragma omp critical (GM_XShearImage)
#endif
      {
        row_count++;
        if (QuantumTick(row_count,height))
          if (!MagickMonitorFormatted(row_count,height,&image->exception,
                                          XShearImageText,image->filename,
					  degrees,width,height,
					  x_offset,y_offset))
            thread_status=MagickFail;
        
        if (thread_status == MagickFail)
          status=MagickFail;
      }
    }
  if (is_grayscale && IsGray(image->background_color))
    image->is_grayscale=True;
}
Beispiel #7
0
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
+   Y S h e a r I m a g e                                                     %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Procedure YShearImage shears the image in the Y direction with a shear
%  angle of 'degrees'.  Positive angles shear counter-clockwise (right-hand
%  rule), and negative angles shear clockwise.  Angles are measured relative
%  to a horizontal X-axis.  Y shears will increase the height of an image
%  creating 'empty' triangles on the top and bottom of the source image.
%
%  The format of the YShearImage method is:
%
%      void YShearImage(Image *image,const double degrees,
%        const unsigned long width,const unsigned long height,long x_offset,
%        const long y_offset)
%
%  A description of each parameter follows.
%
%    o image: The image.
%
%    o degrees: A double representing the shearing angle along the Y axis.
%
%    o width, height, x_offset, y_offset: Defines a region of the image
%      to shear.
%
%
*/
static void YShearImage(Image *image,const double degrees,
                        const unsigned long width,const unsigned long height,long x_offset,
                        const long y_offset)
{
#define YShearImageText  "[%s] Y Shear: %+g degrees, region %lux%lu%+ld%+ld...  "

  long
    y;

  unsigned long
    row_count=0;

  unsigned int
    is_grayscale;

  MagickPassFail
    status=MagickPass;

  assert(image != (Image *) NULL);
  is_grayscale=image->is_grayscale;

#if defined(HAVE_OPENMP)
#  pragma omp parallel for schedule(dynamic,8) shared(row_count, status)
#endif
  for (y=0; y < (long) width; y++)
    {
      double
        alpha,
        displacement;

      enum
        {
          UP,
          DOWN
        } direction;

      long
        step;

      register PixelPacket
        *p,
        *q;

      register long
        i;

      PixelPacket
        pixel;

      MagickPassFail
        thread_status;
      
      thread_status=status;
      if (thread_status == MagickFail)
        continue;

      displacement=degrees*(y-width/2.0);
      if (displacement == 0.0)
        continue;
      if (displacement > 0.0)
        direction=DOWN;
      else
        {
          displacement*=(-1.0);
          direction=UP;
        }
      step=(long) floor(displacement);
      alpha=(double) MaxRGB*(displacement-step);
      if (alpha == 0.0)
        {
          /*
            No fractional displacement-- just copy the pixels.
          */
          switch (direction)
            {
            case UP:
              {
                /*
                  Transfer pixels top-to-bottom.
                */
                if (step > y_offset)
                  break;
                p=GetImagePixelsEx(image,y+x_offset,0,1,image->rows,&image->exception);
                if (p == (PixelPacket *) NULL)
                  {
                    thread_status=MagickFail;
                    break;
                  }
                p+=y_offset;
                q=p-step;
                (void) memcpy(q,p,height*sizeof(PixelPacket));
                q+=height;
                for (i=0; i < (long) step; i++)
                  *q++=image->background_color;
                break;
              }
            case DOWN:
              {
                /*
                  Transfer pixels bottom-to-top.
                */
                p=GetImagePixelsEx(image,y+x_offset,0,1,image->rows,&image->exception);
                if (p == (PixelPacket *) NULL)
                  {
                    thread_status=MagickFail;
                    break;
                  }
                p+=y_offset+height;
                q=p+step;
                for (i=0; i < (long) height; i++)
                  *--q=(*--p);
                for (i=0; i < (long) step; i++)
                  *--q=image->background_color;
                break;
              }
            }
          if (!SyncImagePixelsEx(image,&image->exception))
            thread_status=MagickFail;

#if defined(HAVE_OPENMP)
#  pragma omp critical (GM_YShearImage)
#endif
          {
            row_count++;
            if (QuantumTick(row_count,width))
              if (!MagickMonitorFormatted(row_count,width,&image->exception,
                                          YShearImageText,image->filename,
					  degrees,width,height,
					  x_offset,y_offset))
                thread_status=MagickFail;
            
            if (thread_status == MagickFail)
              status=MagickFail;
          }

          continue;
        }
      /*
        Fractional displacment.
      */
      step++;
      pixel=image->background_color;
      switch (direction)
        {
        case UP:
          {
            /*
              Transfer pixels top-to-bottom.
            */
            if (step > y_offset)
              break;
            p=GetImagePixelsEx(image,y+x_offset,0,1,image->rows,&image->exception);
            if (p == (PixelPacket *) NULL)
              {
                thread_status=MagickFail;
                break;
              }
            p+=y_offset;
            q=p-step;
            for (i=0; i < (long) height; i++)
              {
                if ((y_offset+i) < step)
                  {
                    pixel=(*++p);
                    q++;
                    continue;
                  }
                BlendCompositePixel(q,&pixel,p,alpha);
                q++;
                pixel=(*p++);
              }
            BlendCompositePixel(q,&pixel,&image->background_color,alpha);
            q++;
            for (i=0; i < (step-1); i++)
              *q++=image->background_color;
            break;
          }
        case DOWN:
          {
            /*
              Transfer pixels bottom-to-top.
            */
            p=GetImagePixelsEx(image,y+x_offset,0,1,image->rows,&image->exception);
            if (p == (PixelPacket *) NULL)
              {
                thread_status=MagickFail;
                break;
              }
            p+=y_offset+height;
            q=p+step;
            for (i=0; i < (long) height; i++)
              {
                p--;
                q--;
                if ((y_offset+height+step-i) >= image->rows)
                  continue;
                BlendCompositePixel(q,&pixel,p,alpha);
                pixel=(*p);
              }
            --q;
            BlendCompositePixel(q,&pixel,&image->background_color,alpha);
            for (i=0; i < (step-1); i++)
              *--q=image->background_color;
            break;
          }
        }
      if (!SyncImagePixelsEx(image,&image->exception))
        thread_status=MagickFail;

#if defined(HAVE_OPENMP)
#  pragma omp critical (GM_YShearImage)
#endif
      {
        row_count++;
        if (QuantumTick(row_count,width))
          if (!MagickMonitorFormatted(row_count,width,&image->exception,
                                      YShearImageText,image->filename,
				      degrees,width,height,
				      x_offset,y_offset))
            thread_status=MagickFail;
        
        if (thread_status == MagickFail)
          status=MagickFail;
      }
    }
  if (is_grayscale && IsGray(image->background_color))
    image->is_grayscale=True;
}
Image		*apply_green_contrast(Image *img, unsigned char min, unsigned char max)
{
unsigned int	i = 0;
  unsigned int	j = 0;
  PixelPacket	*px_original;
  PixelPacket	*px_new;
  Image		*new_img;
  ExceptionInfo	exception;
  ImageInfo	*new_img_info;
  unsigned char pixel_value;
  unsigned int	height = img->rows;
  unsigned int	width = img->columns;
  unsigned int	dataset_min = 255;
  unsigned int	dataset_max = 0;

  GetExceptionInfo(&exception);
  if ((new_img_info = CloneImageInfo((ImageInfo *)NULL)) == NULL) {
    CatchException(&exception);
    DestroyImageInfo(new_img_info);
    return (NULL);
  }

  new_img_info->colorspace = RGBColorspace;
  new_img = AllocateImage(new_img_info);
  new_img->rows = img->rows;
  new_img->columns = img->columns;

  if ((px_original = GetImagePixelsEx(img, 0, 0, img->columns, img->rows, &exception)) == NULL)
    {
      DestroyImage(new_img);
      CatchException(&exception);
      return (NULL);
    }

  if ((px_new = SetImagePixelsEx(new_img, 0, 0, new_img->columns, new_img->rows, &exception)) == NULL)
    {
      DestroyImage(new_img);
      CatchException(&exception);
      return (NULL);
    }

  while (i < height)
    {
      j = 0;
      while (j < width)
	{
	  pixel_value = px_original[(width * i) + j].green;
	  if (pixel_value < dataset_min)
	    dataset_min = pixel_value;
	  if (pixel_value > dataset_max)
	    dataset_max = pixel_value;
	  j++;
	}
      i++;
    }

  i = 0;

  while (i < height)
    {
      j = 0;
      while (j < width)
	{
	  pixel_value = px_original[(width * i) + j].green;
	  pixel_value = (pixel_value >= 255 ? 254 : pixel_value);

	  pixel_value = get_contrasted_value(min, max, dataset_min, dataset_max, pixel_value);

	  px_new[(width * i) + j].red = 0;
	  px_new[(width * i) + j].green = pixel_value;
	  px_new[(width * i) + j].blue = 0;
	  j++;
	}
      i++;
    }

  SyncImagePixels(new_img);

  DestroyImageInfo(new_img_info);
  return(new_img);
}
Image		*substract_grayscale_to_original(Image *img, Image *gray_img, int min, int max)
{
  unsigned int	i = 0;
  unsigned int	j = 0;
  PixelPacket	*px_original;
  PixelPacket	*px_gray;
  PixelPacket	*px_new;
  Image		*new_img;
  ExceptionInfo	exception;
  ImageInfo	*new_img_info;

  GetExceptionInfo(&exception);
  if ((new_img_info = CloneImageInfo((ImageInfo *)NULL)) == NULL) {
    CatchException(&exception);
    DestroyImageInfo(new_img_info);
    return (NULL);
  }

  new_img_info->colorspace = RGBColorspace;
  new_img = AllocateImage(new_img_info);
  new_img->rows = img->rows;
  new_img->columns = img->columns;

  if ((px_original = GetImagePixelsEx(img, 0, 0, img->columns, img->rows, &exception)) == NULL)
    {
      DestroyImage(new_img);
      CatchException(&exception);
      return (NULL);
    }

  if ((px_gray = GetImagePixelsEx(gray_img, 0, 0, img->columns, img->rows, &exception)) == NULL)
    {
      DestroyImage(new_img);
      CatchException(&exception);
      return (NULL);
    }

  if ((px_new = SetImagePixelsEx(new_img, 0, 0, new_img->columns, new_img->rows, &exception)) == NULL)
    {
      DestroyImage(new_img);
      CatchException(&exception);
      return (NULL);
    }

  while (i < img->rows)
    {
      j = 0;
      while (j < img->columns)
	{
	 if(px_gray[(new_img->columns * i) + j].red > max || px_gray[(new_img->columns * i) + j].red < min)
	 {
	    px_new[(new_img->columns * i) + j].red = 0;
	    px_new[(new_img->columns * i) + j].blue = 0;
	    px_new[(new_img->columns * i) + j].green = 0;
	 }
	 else
	 {
	   px_new[(new_img->columns * i) + j].red = px_original[(new_img->columns * i) + j].red;
	   px_new[(new_img->columns * i) + j].blue = px_original[(new_img->columns * i) + j].blue;
	   px_new[(new_img->columns * i) + j].green = px_original[(new_img->columns * i) + j].green;
	 }
	  j++;
	}
      i++;
    }
  SyncImagePixels(new_img);

  DestroyImageInfo(new_img_info);

  return (new_img);
}