]> granicus.if.org Git - imagemagick/blobdiff - MagickCore/shear.c
(no commit message)
[imagemagick] / MagickCore / shear.c
index da0f8b2270e4d231fdc832e51e35d8baad685260..16dd2ff7833a8a89e8d040cf80ef0ce5d9743fc9 100644 (file)
 %    MagickCore Methods to Shear or Rotate an Image by an Arbitrary Angle     %
 %                                                                             %
 %                               Software Design                               %
-%                                 John Cristy                                 %
+%                                    Cristy                                   %
 %                                  July 1992                                  %
 %                                                                             %
 %                                                                             %
-%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  Copyright 1999-2014 ImageMagick Studio LLC, a non-profit organization      %
 %  dedicated to making software imaging solutions freely available.           %
 %                                                                             %
 %  You may not use this file except in compliance with the License.  You may  %
 %                                                                             %
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
-%  The RotateImage, XShearImage, and YShearImage methods are based on the
-%  paper "A Fast Algorithm for General Raster Rotatation" by Alan W. Paeth,
-%  Graphics Interface '86 (Vancouver).  RotateImage is adapted from a similar
+%  The XShearImage() and YShearImage() methods are based on the paper "A Fast
+%  Algorithm for General Raster Rotatation" by Alan W. Paeth, Graphics
+%  Interface '86 (Vancouver).  ShearRotateImage() is adapted from a similar
 %  method based on the Paeth paper written by Michael Halle of the Spatial
 %  Imaging Group, MIT Media Lab.
 %
-%
 */
 \f
 /*
@@ -50,6 +49,7 @@
 #include "MagickCore/attribute.h"
 #include "MagickCore/blob-private.h"
 #include "MagickCore/cache-private.h"
+#include "MagickCore/channel.h"
 #include "MagickCore/color-private.h"
 #include "MagickCore/colorspace-private.h"
 #include "MagickCore/composite.h"
@@ -63,6 +63,7 @@
 #include "MagickCore/geometry.h"
 #include "MagickCore/image.h"
 #include "MagickCore/image-private.h"
+#include "MagickCore/matrix.h"
 #include "MagickCore/memory_.h"
 #include "MagickCore/list.h"
 #include "MagickCore/monitor.h"
 %                                                                             %
 %                                                                             %
 %                                                                             %
-%     A f f i n e T r a n s f o r m I m a g e                                 %
-%                                                                             %
-%                                                                             %
-%                                                                             %
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%
-%  AffineTransformImage() transforms an image as dictated by the affine matrix.
-%  It allocates the memory necessary for the new Image structure and returns
-%  a pointer to the new image.
-%
-%  The format of the AffineTransformImage method is:
-%
-%      Image *AffineTransformImage(const Image *image,
-%        AffineMatrix *affine_matrix,ExceptionInfo *exception)
-%
-%  A description of each parameter follows:
-%
-%    o image: the image.
-%
-%    o affine_matrix: the affine matrix.
-%
-%    o exception: return any errors or warnings in this structure.
-%
-*/
-MagickExport Image *AffineTransformImage(const Image *image,
-  const AffineMatrix *affine_matrix,ExceptionInfo *exception)
-{
-  double
-    distort[6];
-
-  Image
-    *deskew_image;
-
-  /*
-    Affine transform image.
-  */
-  assert(image->signature == MagickSignature);
-  if (image->debug != MagickFalse)
-    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
-  assert(affine_matrix != (AffineMatrix *) NULL);
-  assert(exception != (ExceptionInfo *) NULL);
-  assert(exception->signature == MagickSignature);
-  distort[0]=affine_matrix->sx;
-  distort[1]=affine_matrix->rx;
-  distort[2]=affine_matrix->ry;
-  distort[3]=affine_matrix->sy;
-  distort[4]=affine_matrix->tx;
-  distort[5]=affine_matrix->ty;
-  deskew_image=DistortImage(image,AffineProjectionDistortion,6,distort,
-    MagickTrue,exception);
-  return(deskew_image);
-}
-\f
-/*
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%                                                                             %
-%                                                                             %
-%                                                                             %
 +   C r o p T o F i t I m a g e                                               %
 %                                                                             %
 %                                                                             %
@@ -154,8 +97,8 @@ MagickExport Image *AffineTransformImage(const Image *image,
 %  The format of the CropToFitImage method is:
 %
 %      MagickBooleanType CropToFitImage(Image **image,
-%        const MagickRealType x_shear,const MagickRealType x_shear,
-%        const MagickRealType width,const MagickRealType height,
+%        const double x_shear,const double x_shear,
+%        const double width,const double height,
 %        const MagickBooleanType rotate,ExceptionInfo *exception)
 %
 %  A description of each parameter follows.
@@ -168,8 +111,8 @@ MagickExport Image *AffineTransformImage(const Image *image,
 %
 */
 static MagickBooleanType CropToFitImage(Image **image,
-  const MagickRealType x_shear,const MagickRealType y_shear,
-  const MagickRealType width,const MagickRealType height,
+  const double x_shear,const double y_shear,
+  const double width,const double height,
   const MagickBooleanType rotate,ExceptionInfo *exception)
 {
   Image
@@ -251,6 +194,15 @@ static MagickBooleanType CropToFitImage(Image **image,
 %  imperfections in the scanning or surface, or simply because the paper was
 %  not placed completely flat when scanned.
 %
+%  The result will be auto-croped if the artifact "deskew:auto-crop" is
+%  defined, while the amount the image is to be deskewed, in degrees is also
+%  saved as the artifact "deskew:angle".
+%
+%  If the artifact "deskew:auto-crop" is given the image will be automatically
+%  cropped of the excess background.  The value is the border width of all
+%  pixels around the edge that will be used to determine an average border
+%  color for the automatic trim.
+%
 %  The format of the DeskewImage method is:
 %
 %      Image *DeskewImage(const Image *image,const double threshold,
@@ -266,331 +218,27 @@ static MagickBooleanType CropToFitImage(Image **image,
 %
 */
 
-typedef struct _RadonInfo
-{
-  CacheType
-    type;
-
-  size_t
-    width,
-    height;
-
-  MagickSizeType
-    length;
-
-  MagickBooleanType
-    mapped;
-
-  char
-    path[MaxTextExtent];
-
-  int
-    file;
-
-  unsigned short
-    *cells;
-} RadonInfo;
-
-static RadonInfo *DestroyRadonInfo(RadonInfo *radon_info)
-{
-  assert(radon_info != (RadonInfo *) NULL);
-  switch (radon_info->type)
-  {
-    case MemoryCache:
-    {
-      if (radon_info->mapped == MagickFalse)
-        radon_info->cells=(unsigned short *) RelinquishMagickMemory(
-          radon_info->cells);
-      else
-        radon_info->cells=(unsigned short *) UnmapBlob(radon_info->cells,
-          (size_t) radon_info->length);
-      RelinquishMagickResource(MemoryResource,radon_info->length);
-      break;
-    }
-    case MapCache:
-    {
-      radon_info->cells=(unsigned short *) UnmapBlob(radon_info->cells,(size_t)
-        radon_info->length);
-      RelinquishMagickResource(MapResource,radon_info->length);
-    }
-    case DiskCache:
-    {
-      if (radon_info->file != -1)
-        (void) close(radon_info->file);
-      (void) RelinquishUniqueFileResource(radon_info->path);
-      RelinquishMagickResource(DiskResource,radon_info->length);
-      break;
-    }
-    default:
-      break;
-  }
-  return((RadonInfo *) RelinquishMagickMemory(radon_info));
-}
-
-static MagickBooleanType ResetRadonCells(RadonInfo *radon_info)
-{
-  register ssize_t
-    x;
-
-  ssize_t
-    count,
-    y;
-
-  unsigned short
-    value;
-
-  if (radon_info->type != DiskCache)
-    {
-      (void) ResetMagickMemory(radon_info->cells,0,(size_t) radon_info->length);
-      return(MagickTrue);
-    }
-  value=0;
-  (void) lseek(radon_info->file,0,SEEK_SET);
-  for (y=0; y < (ssize_t) radon_info->height; y++)
-  {
-    for (x=0; x < (ssize_t) radon_info->width; x++)
-    {
-      count=write(radon_info->file,&value,sizeof(*radon_info->cells));
-      if (count != (ssize_t) sizeof(*radon_info->cells))
-        break;
-    }
-    if (x < (ssize_t) radon_info->width)
-      break;
-  }
-  return(y < (ssize_t) radon_info->height ? MagickFalse : MagickTrue);
-}
-
-static RadonInfo *AcquireRadonInfo(const Image *image,const size_t width,
-  const size_t height,ExceptionInfo *exception)
-{
-  MagickBooleanType
-    status;
-
-  RadonInfo
-    *radon_info;
-
-  radon_info=(RadonInfo *) AcquireMagickMemory(sizeof(*radon_info));
-  if (radon_info == (RadonInfo *) NULL)
-    return((RadonInfo *) NULL);
-  (void) ResetMagickMemory(radon_info,0,sizeof(*radon_info));
-  radon_info->width=width;
-  radon_info->height=height;
-  radon_info->length=(MagickSizeType) width*height*sizeof(*radon_info->cells);
-  radon_info->type=MemoryCache;
-  status=AcquireMagickResource(AreaResource,radon_info->length);
-  if ((status != MagickFalse) &&
-      (radon_info->length == (MagickSizeType) ((size_t) radon_info->length)))
-    {
-      status=AcquireMagickResource(MemoryResource,radon_info->length);
-      if (status != MagickFalse)
-        {
-          radon_info->mapped=MagickFalse;
-          radon_info->cells=(unsigned short *) AcquireMagickMemory((size_t)
-            radon_info->length);
-          if (radon_info->cells == (unsigned short *) NULL)
-            {
-              radon_info->mapped=MagickTrue;
-              radon_info->cells=(unsigned short *) MapBlob(-1,IOMode,0,(size_t)
-                radon_info->length);
-            }
-          if (radon_info->cells == (unsigned short *) NULL)
-            RelinquishMagickResource(MemoryResource,radon_info->length);
-        }
-    }
-  radon_info->file=(-1);
-  if (radon_info->cells == (unsigned short *) NULL)
-    {
-      status=AcquireMagickResource(DiskResource,radon_info->length);
-      if (status == MagickFalse)
-        {
-          (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
-            "CacheResourcesExhausted","`%s'",image->filename);
-          return(DestroyRadonInfo(radon_info));
-        }
-      radon_info->type=DiskCache;
-      (void) AcquireMagickResource(MemoryResource,radon_info->length);
-      radon_info->file=AcquireUniqueFileResource(radon_info->path);
-      if (radon_info->file == -1)
-        return(DestroyRadonInfo(radon_info));
-      status=AcquireMagickResource(MapResource,radon_info->length);
-      if (status != MagickFalse)
-        {
-          status=ResetRadonCells(radon_info);
-          if (status != MagickFalse)
-            {
-              radon_info->cells=(unsigned short *) MapBlob(radon_info->file,
-                IOMode,0,(size_t) radon_info->length);
-              if (radon_info->cells != (unsigned short *) NULL)
-                radon_info->type=MapCache;
-              else
-                RelinquishMagickResource(MapResource,radon_info->length);
-            }
-        }
-    }
-  return(radon_info);
-}
-
-static inline size_t MagickMin(const size_t x,const size_t y)
-{
-  if (x < y)
-    return(x);
-  return(y);
-}
-
-static inline ssize_t ReadRadonCell(const RadonInfo *radon_info,
-  const MagickOffsetType offset,const size_t length,unsigned char *buffer)
-{
-  register ssize_t
-    i;
-
-  ssize_t
-    count;
-
-#if !defined(MAGICKCORE_HAVE_PPREAD)
-#if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_ReadRadonCell)
-#endif
-  {
-    i=(-1);
-    if (lseek(radon_info->file,offset,SEEK_SET) >= 0)
-      {
-#endif
-        count=0;
-        for (i=0; i < (ssize_t) length; i+=count)
-        {
-#if !defined(MAGICKCORE_HAVE_PPREAD)
-          count=read(radon_info->file,buffer+i,MagickMin(length-i,(size_t)
-            SSIZE_MAX));
-#else
-          count=pread(radon_info->file,buffer+i,MagickMin(length-i,(size_t)
-            SSIZE_MAX),offset+i);
-#endif
-          if (count > 0)
-            continue;
-          count=0;
-          if (errno != EINTR)
-            {
-              i=(-1);
-              break;
-            }
-        }
-#if !defined(MAGICKCORE_HAVE_PPREAD)
-      }
-  }
-#endif
-  return(i);
-}
-
-static inline ssize_t WriteRadonCell(const RadonInfo *radon_info,
-  const MagickOffsetType offset,const size_t length,const unsigned char *buffer)
-{
-  register ssize_t
-    i;
-
-  ssize_t
-    count;
-
-#if !defined(MAGICKCORE_HAVE_PWRITE)
-#if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp critical (MagickCore_WriteRadonCell)
-#endif
-  {
-    if (lseek(radon_info->file,offset,SEEK_SET) >= 0)
-      {
-#endif
-        count=0;
-        for (i=0; i < (ssize_t) length; i+=count)
-        {
-#if !defined(MAGICKCORE_HAVE_PWRITE)
-          count=write(radon_info->file,buffer+i,MagickMin(length-i,(size_t)
-            SSIZE_MAX));
-#else
-          count=pwrite(radon_info->file,buffer+i,MagickMin(length-i,(size_t)
-            SSIZE_MAX),offset+i);
-#endif
-          if (count > 0)
-            continue;
-          count=0;
-          if (errno != EINTR)
-            {
-              i=(-1);
-              break;
-            }
-        }
-#if !defined(MAGICKCORE_HAVE_PWRITE)
-      }
-  }
-#endif
-  return(i);
-}
-
-static inline unsigned short GetRadonCell(const RadonInfo *radon_info,
-  const ssize_t x,const ssize_t y)
-{
-  MagickOffsetType
-    i;
-
-  unsigned short
-    value;
-
-  i=(MagickOffsetType) radon_info->height*x+y;
-  if ((i < 0) ||
-      ((MagickSizeType) (i*sizeof(*radon_info->cells)) >= radon_info->length))
-    return(0);
-  if (radon_info->type != DiskCache)
-    return(radon_info->cells[i]);
-  value=0;
-  (void) ReadRadonCell(radon_info,i*sizeof(*radon_info->cells),
-    sizeof(*radon_info->cells),(unsigned char *) &value);
-  return(value);
-}
-
-static inline MagickBooleanType SetRadonCell(const RadonInfo *radon_info,
-  const ssize_t x,const ssize_t y,const unsigned short value)
-{
-  MagickOffsetType
-    i;
-
-  ssize_t
-    count;
-
-  i=(MagickOffsetType) radon_info->height*x+y;
-  if ((i < 0) ||
-      ((MagickSizeType) (i*sizeof(*radon_info->cells)) >= radon_info->length))
-    return(MagickFalse);
-  if (radon_info->type != DiskCache)
-    {
-      radon_info->cells[i]=value;
-      return(MagickTrue);
-    }
-  count=WriteRadonCell(radon_info,i*sizeof(*radon_info->cells),
-    sizeof(*radon_info->cells),(const unsigned char *) &value);
-  if (count != (ssize_t) sizeof(*radon_info->cells))
-    return(MagickFalse);
-  return(MagickTrue);
-}
-
-static void RadonProjection(RadonInfo *source_cells,
-  RadonInfo *destination_cells,const ssize_t sign,size_t *projection)
+static void RadonProjection(const Image *image,MatrixInfo *source_matrixs,
+  MatrixInfo *destination_matrixs,const ssize_t sign,size_t *projection)
 {
-  RadonInfo
+  MatrixInfo
     *swap;
 
-  register ssize_t
-    x;
-
-  register RadonInfo
+  register MatrixInfo
     *p,
     *q;
 
+  register ssize_t
+    x;
+
   size_t
     step;
 
-  p=source_cells;
-  q=destination_cells;
-  for (step=1; step < p->width; step*=2)
+  p=source_matrixs;
+  q=destination_matrixs;
+  for (step=1; step < GetMatrixColumns(p); step*=2)
   {
-    for (x=0; x < (ssize_t) p->width; x+=2*(ssize_t) step)
+    for (x=0; x < (ssize_t) GetMatrixColumns(p); x+=2*(ssize_t) step)
     {
       register ssize_t
         i;
@@ -599,30 +247,46 @@ static void RadonProjection(RadonInfo *source_cells,
         y;
 
       unsigned short
-        cell;
+        element,
+        neighbor;
 
       for (i=0; i < (ssize_t) step; i++)
       {
-        for (y=0; y < (ssize_t) (p->height-i-1); y++)
+        for (y=0; y < (ssize_t) (GetMatrixRows(p)-i-1); y++)
         {
-          cell=GetRadonCell(p,x+i,y);
-          (void) SetRadonCell(q,x+2*i,y,cell+GetRadonCell(p,x+i+(ssize_t)
-            step,y+i));
-          (void) SetRadonCell(q,x+2*i+1,y,cell+GetRadonCell(p,x+i+(ssize_t)
-            step,y+i+1));
+          if (GetMatrixElement(p,x+i,y,&element) == MagickFalse)
+            continue;
+          if (GetMatrixElement(p,x+i+step,y+i,&neighbor) == MagickFalse)
+            continue;
+          neighbor+=element;
+          if (SetMatrixElement(q,x+2*i,y,&neighbor) == MagickFalse)
+            continue;
+          if (GetMatrixElement(p,x+i+step,y+i+1,&neighbor) == MagickFalse)
+            continue;
+          neighbor+=element;
+          if (SetMatrixElement(q,x+2*i+1,y,&neighbor) == MagickFalse)
+            continue;
         }
-        for ( ; y < (ssize_t) (p->height-i); y++)
+        for ( ; y < (ssize_t) (GetMatrixRows(p)-i); y++)
         {
-          cell=GetRadonCell(p,x+i,y);
-          (void) SetRadonCell(q,x+2*i,y,cell+GetRadonCell(p,x+i+(ssize_t) step,
-            y+i));
-          (void) SetRadonCell(q,x+2*i+1,y,cell);
+          if (GetMatrixElement(p,x+i,y,&element) == MagickFalse)
+            continue;
+          if (GetMatrixElement(p,x+i+step,y+i,&neighbor) == MagickFalse)
+            continue;
+          neighbor+=element;
+          if (SetMatrixElement(q,x+2*i,y,&neighbor) == MagickFalse)
+            continue;
+          if (SetMatrixElement(q,x+2*i+1,y,&element) == MagickFalse)
+            continue;
         }
-        for ( ; y < (ssize_t) p->height; y++)
+        for ( ; y < (ssize_t) GetMatrixRows(p); y++)
         {
-          cell=GetRadonCell(p,x+i,y);
-          (void) SetRadonCell(q,x+2*i,y,cell);
-          (void) SetRadonCell(q,x+2*i+1,y,cell);
+          if (GetMatrixElement(p,x+i,y,&element) == MagickFalse)
+            continue;
+          if (SetMatrixElement(q,x+2*i,y,&element) == MagickFalse)
+            continue;
+          if (SetMatrixElement(q,x+2*i+1,y,&element) == MagickFalse)
+            continue;
         }
       }
     }
@@ -631,9 +295,10 @@ static void RadonProjection(RadonInfo *source_cells,
     q=swap;
   }
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4)
+  #pragma omp parallel for schedule(static,4) \
+    magick_threads(image,image,1,1)
 #endif
-  for (x=0; x < (ssize_t) p->width; x++)
+  for (x=0; x < (ssize_t) GetMatrixColumns(p); x++)
   {
     register ssize_t
       y;
@@ -642,15 +307,23 @@ static void RadonProjection(RadonInfo *source_cells,
       sum;
 
     sum=0;
-    for (y=0; y < (ssize_t) (p->height-1); y++)
+    for (y=0; y < (ssize_t) (GetMatrixRows(p)-1); y++)
     {
       ssize_t
         delta;
 
-      delta=GetRadonCell(p,x,y)-(ssize_t) GetRadonCell(p,x,y+1);
+      unsigned short
+        element,
+        neighbor;
+
+      if (GetMatrixElement(p,x,y,&element) == MagickFalse)
+        continue;
+      if (GetMatrixElement(p,x,y+1,&neighbor) == MagickFalse)
+        continue;
+      delta=(ssize_t) element-(ssize_t) neighbor;
       sum+=delta*delta;
     }
-    projection[p->width+sign*x-1]=sum;
+    projection[GetMatrixColumns(p)+sign*x-1]=sum;
   }
 }
 
@@ -660,13 +333,13 @@ static MagickBooleanType RadonTransform(const Image *image,
   CacheView
     *image_view;
 
+  MatrixInfo
+    *destination_matrixs,
+    *source_matrixs;
+
   MagickBooleanType
     status;
 
-  RadonInfo
-    *destination_cells,
-    *source_cells;
-
   register ssize_t
     i;
 
@@ -684,21 +357,23 @@ static MagickBooleanType RadonTransform(const Image *image,
     bits[256];
 
   for (width=1; width < ((image->columns+7)/8); width<<=1) ;
-  source_cells=AcquireRadonInfo(image,width,image->rows,exception);
-  destination_cells=AcquireRadonInfo(image,width,image->rows,exception);
-  if ((source_cells == (RadonInfo *) NULL) ||
-      (destination_cells == (RadonInfo *) NULL))
+  source_matrixs=AcquireMatrixInfo(width,image->rows,sizeof(unsigned short),
+    exception);
+  destination_matrixs=AcquireMatrixInfo(width,image->rows,sizeof(unsigned short),
+    exception);
+  if ((source_matrixs == (MatrixInfo *) NULL) ||
+      (destination_matrixs == (MatrixInfo *) NULL))
     {
-      if (destination_cells != (RadonInfo *) NULL)
-        destination_cells=DestroyRadonInfo(destination_cells);
-      if (source_cells != (RadonInfo *) NULL)
-        source_cells=DestroyRadonInfo(source_cells);
+      if (destination_matrixs != (MatrixInfo *) NULL)
+        destination_matrixs=DestroyMatrixInfo(destination_matrixs);
+      if (source_matrixs != (MatrixInfo *) NULL)
+        source_matrixs=DestroyMatrixInfo(source_matrixs);
       return(MagickFalse);
     }
-  if (ResetRadonCells(source_cells) == MagickFalse)
+  if (NullMatrix(source_matrixs) == MagickFalse)
     {
-      destination_cells=DestroyRadonInfo(destination_cells);
-      source_cells=DestroyRadonInfo(source_cells);
+      destination_matrixs=DestroyMatrixInfo(destination_matrixs);
+      source_matrixs=DestroyMatrixInfo(source_matrixs);
       return(MagickFalse);
     }
   for (i=0; i < 256; i++)
@@ -709,9 +384,10 @@ static MagickBooleanType RadonTransform(const Image *image,
     bits[i]=(unsigned short) count;
   }
   status=MagickTrue;
-  image_view=AcquireCacheView(image);
+  image_view=AcquireVirtualCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(status)
+  #pragma omp parallel for schedule(static,4) shared(status) \
+    magick_threads(image,image,1,1)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -726,6 +402,9 @@ static MagickBooleanType RadonTransform(const Image *image,
       bit,
       byte;
 
+    unsigned short
+      value;
+
     if (status == MagickFalse)
       continue;
     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
@@ -740,12 +419,15 @@ static MagickBooleanType RadonTransform(const Image *image,
     for (x=0; x < (ssize_t) image->columns; x++)
     {
       byte<<=1;
-      if ((double) GetPixelIntensity(image,p) < threshold)
+      if (((MagickRealType) GetPixelRed(image,p) < threshold) ||
+          ((MagickRealType) GetPixelGreen(image,p) < threshold) ||
+          ((MagickRealType) GetPixelBlue(image,p) < threshold))
         byte|=0x01;
       bit++;
       if (bit == 8)
         {
-          (void) SetRadonCell(source_cells,--i,y,bits[byte]);
+          value=bits[byte];
+          (void) SetMatrixElement(source_matrixs,--i,y,&value);
           bit=0;
           byte=0;
         }
@@ -754,13 +436,15 @@ static MagickBooleanType RadonTransform(const Image *image,
     if (bit != 0)
       {
         byte<<=(8-bit);
-        (void) SetRadonCell(source_cells,--i,y,bits[byte]);
+        value=bits[byte];
+        (void) SetMatrixElement(source_matrixs,--i,y,&value);
       }
   }
-  RadonProjection(source_cells,destination_cells,-1,projection);
-  (void) ResetRadonCells(source_cells);
+  RadonProjection(image,source_matrixs,destination_matrixs,-1,projection);
+  (void) NullMatrix(source_matrixs);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(status)
+  #pragma omp parallel for schedule(static,4) shared(status) \
+    magick_threads(image,image,image->rows,1)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -775,6 +459,9 @@ static MagickBooleanType RadonTransform(const Image *image,
       bit,
       byte;
 
+    unsigned short
+     value;
+
     if (status == MagickFalse)
       continue;
     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
@@ -789,12 +476,15 @@ static MagickBooleanType RadonTransform(const Image *image,
     for (x=0; x < (ssize_t) image->columns; x++)
     {
       byte<<=1;
-      if ((double) GetPixelIntensity(image,p) < threshold)
+      if (((MagickRealType) GetPixelRed(image,p) < threshold) ||
+          ((MagickRealType) GetPixelGreen(image,p) < threshold) ||
+          ((MagickRealType) GetPixelBlue(image,p) < threshold))
         byte|=0x01;
       bit++;
       if (bit == 8)
         {
-          (void) SetRadonCell(source_cells,i++,y,bits[byte]);
+          value=bits[byte];
+          (void) SetMatrixElement(source_matrixs,i++,y,&value);
           bit=0;
           byte=0;
         }
@@ -803,13 +493,14 @@ static MagickBooleanType RadonTransform(const Image *image,
     if (bit != 0)
       {
         byte<<=(8-bit);
-        (void) SetRadonCell(source_cells,i++,y,bits[byte]);
+        value=bits[byte];
+        (void) SetMatrixElement(source_matrixs,i++,y,&value);
       }
   }
-  RadonProjection(source_cells,destination_cells,1,projection);
+  RadonProjection(image,source_matrixs,destination_matrixs,1,projection);
   image_view=DestroyCacheView(image_view);
-  destination_cells=DestroyRadonInfo(destination_cells);
-  source_cells=DestroyRadonInfo(source_cells);
+  destination_matrixs=DestroyMatrixInfo(destination_matrixs);
+  source_matrixs=DestroyMatrixInfo(source_matrixs);
   return(MagickTrue);
 }
 
@@ -822,7 +513,7 @@ static void GetImageBackgroundColor(Image *image,const ssize_t offset,
   PixelInfo
     background;
 
-  MagickRealType
+  double
     count;
 
   ssize_t
@@ -835,7 +526,7 @@ static void GetImageBackgroundColor(Image *image,const ssize_t offset,
     return;
   GetPixelInfo(image,&background);
   count=0.0;
-  image_view=AcquireCacheView(image);
+  image_view=AcquireVirtualCacheView(image,exception);
   for (y=0; y < (ssize_t) image->rows; y++)
   {
     register const Quantum
@@ -863,15 +554,15 @@ static void GetImageBackgroundColor(Image *image,const ssize_t offset,
     }
   }
   image_view=DestroyCacheView(image_view);
-  image->background_color.red=(double) ClampToQuantum((MagickRealType)
-    QuantumRange*background.red/count);
-  image->background_color.green=(double) ClampToQuantum((MagickRealType)
-    QuantumRange*background.green/count);
-  image->background_color.blue=(double) ClampToQuantum((MagickRealType)
-    QuantumRange*background.blue/count);
+  image->background_color.red=(double) ClampToQuantum(QuantumRange*
+    background.red/count);
+  image->background_color.green=(double) ClampToQuantum(QuantumRange*
+    background.green/count);
+  image->background_color.blue=(double) ClampToQuantum(QuantumRange*
+    background.blue/count);
   if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-    image->background_color.alpha=(double) ClampToQuantum((MagickRealType)
-      QuantumRange*background.alpha/count);
+    image->background_color.alpha=(double) ClampToQuantum(QuantumRange*
+      background.alpha/count);
 }
 
 MagickExport Image *DeskewImage(const Image *image,const double threshold,
@@ -934,17 +625,25 @@ MagickExport Image *DeskewImage(const Image *image,const double threshold,
       }
   }
   projection=(size_t *) RelinquishMagickMemory(projection);
+  degrees=RadiansToDegrees(-atan((double) skew/width/8));
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TransformEvent,GetMagickModule(),
+      "  Deskew angle: %g",degrees);
   /*
     Deskew image.
   */
   clone_image=CloneImage(image,0,0,MagickTrue,exception);
   if (clone_image == (Image *) NULL)
     return((Image *) NULL);
-  (void) SetImageVirtualPixelMethod(clone_image,BackgroundVirtualPixelMethod);
-  degrees=RadiansToDegrees(-atan((double) skew/width/8));
-  if (image->debug != MagickFalse)
-    (void) LogMagickEvent(TransformEvent,GetMagickModule(),
-      "  Deskew angle: %g",degrees);
+  {
+    char
+      angle[MaxTextExtent];
+
+    (void) FormatLocaleString(angle,MaxTextExtent,"%.20g",degrees);
+    (void) SetImageArtifact(clone_image,"deskew:angle",angle);
+  }
+  (void) SetImageVirtualPixelMethod(clone_image,BackgroundVirtualPixelMethod,
+    exception);
   affine_matrix.sx=cos(DegreesToRadians(fmod((double) degrees,360.0)));
   affine_matrix.rx=sin(DegreesToRadians(fmod((double) degrees,360.0)));
   affine_matrix.ry=(-sin(DegreesToRadians(fmod((double) degrees,360.0))));
@@ -989,7 +688,7 @@ MagickExport Image *DeskewImage(const Image *image,const double threshold,
 %                                                                             %
 %                                                                             %
 %                                                                             %
-+   I n t e g r a l R o t a t e I m a g e                                     %
+%   I n t e g r a l R o t a t e I m a g e                                     %
 %                                                                             %
 %                                                                             %
 %                                                                             %
@@ -1011,7 +710,7 @@ MagickExport Image *DeskewImage(const Image *image,const double threshold,
 %    o rotations: Specifies the number of 90 degree rotations.
 %
 */
-static Image *IntegralRotateImage(const Image *image,size_t rotations,
+MagickExport Image *IntegralRotateImage(const Image *image,size_t rotations,
   ExceptionInfo *exception)
 {
 #define RotateImageTag  "Rotate/Image"
@@ -1056,8 +755,8 @@ static Image *IntegralRotateImage(const Image *image,size_t rotations,
   */
   status=MagickTrue;
   progress=0;
-  image_view=AcquireCacheView(image);
-  rotate_view=AcquireCacheView(rotate_image);
+  image_view=AcquireVirtualCacheView(image,exception);
+  rotate_view=AcquireAuthenticCacheView(rotate_image,exception);
   switch (rotations)
   {
     case 0:
@@ -1082,7 +781,8 @@ static Image *IntegralRotateImage(const Image *image,size_t rotations,
       GetPixelCacheTileSize(image,&tile_width,&tile_height);
       tile_width=image->columns;
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-      #pragma omp parallel for schedule(dynamic,4) shared(progress, status) omp_throttle(1)
+      #pragma omp parallel for schedule(static,4) shared(status) \
+        magick_threads(image,image,1,1)
 #endif
       for (tile_y=0; tile_y < (ssize_t) image->rows; tile_y+=(ssize_t) tile_height)
       {
@@ -1147,18 +847,18 @@ static Image *IntegralRotateImage(const Image *image,size_t rotations,
               register ssize_t
                 i;
 
+              if (GetPixelReadMask(image,tile_pixels) == 0)
+                {
+                  tile_pixels-=width*GetPixelChannels(image);
+                  q+=GetPixelChannels(rotate_image);
+                  continue;
+                }
               for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
               {
-                PixelChannel
-                  channel;
-
-                PixelTrait
-                  rotate_traits,
-                  traits;
-
-                traits=GetPixelChannelMapTraits(image,(PixelChannel) i);
-                channel=GetPixelChannelMapChannel(image,(PixelChannel) i);
-                rotate_traits=GetPixelChannelMapTraits(rotate_image,channel);
+                PixelChannel channel=GetPixelChannelChannel(image,i);
+                PixelTrait traits=GetPixelChannelTraits(image,channel);
+                PixelTrait rotate_traits=GetPixelChannelTraits(rotate_image,
+                  channel);
                 if ((traits == UndefinedPixelTrait) ||
                     (rotate_traits == UndefinedPixelTrait))
                   continue;
@@ -1200,7 +900,8 @@ static Image *IntegralRotateImage(const Image *image,size_t rotations,
         Rotate 180 degrees.
       */
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-      #pragma omp parallel for schedule(dynamic,4) shared(progress,status) omp_throttle(1)
+      #pragma omp parallel for schedule(static,4) shared(status) \
+        magick_threads(image,image,1,1)
 #endif
       for (y=0; y < (ssize_t) image->rows; y++)
       {
@@ -1233,18 +934,17 @@ static Image *IntegralRotateImage(const Image *image,size_t rotations,
             i;
 
           q-=GetPixelChannels(rotate_image);
+          if (GetPixelReadMask(image,p) == 0)
+            {
+              p+=GetPixelChannels(image);
+              continue;
+            }
           for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
           {
-            PixelChannel
-              channel;
-
-            PixelTrait
-              rotate_traits,
-              traits;
-
-            traits=GetPixelChannelMapTraits(image,(PixelChannel) i);
-            channel=GetPixelChannelMapChannel(image,(PixelChannel) i);
-            rotate_traits=GetPixelChannelMapTraits(rotate_image,channel);
+            PixelChannel channel=GetPixelChannelChannel(image,i);
+            PixelTrait traits=GetPixelChannelTraits(image,channel);
+            PixelTrait rotate_traits=GetPixelChannelTraits(rotate_image,
+              channel);
             if ((traits == UndefinedPixelTrait) ||
                 (rotate_traits == UndefinedPixelTrait))
               continue;
@@ -1292,7 +992,8 @@ static Image *IntegralRotateImage(const Image *image,size_t rotations,
       GetPixelCacheTileSize(image,&tile_width,&tile_height);
       tile_width=image->columns;
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-      #pragma omp parallel for schedule(dynamic,4) shared(progress,status) omp_throttle(1)
+      #pragma omp parallel for schedule(static,4) shared(status) \
+        magick_threads(image,image,1,1)
 #endif
       for (tile_y=0; tile_y < (ssize_t) image->rows; tile_y+=(ssize_t) tile_height)
       {
@@ -1356,18 +1057,18 @@ static Image *IntegralRotateImage(const Image *image,size_t rotations,
               register ssize_t
                 i;
 
+              if (GetPixelReadMask(image,tile_pixels) == 0)
+                {
+                  tile_pixels+=width*GetPixelChannels(image);
+                  q+=GetPixelChannels(rotate_image);
+                  continue;
+                }
               for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
               {
-                PixelChannel
-                  channel;
-
-                PixelTrait
-                  rotate_traits,
-                  traits;
-
-                traits=GetPixelChannelMapTraits(image,(PixelChannel) i);
-                channel=GetPixelChannelMapChannel(image,(PixelChannel) i);
-                rotate_traits=GetPixelChannelMapTraits(rotate_image,channel);
+                PixelChannel channel=GetPixelChannelChannel(image,i);
+                PixelTrait traits=GetPixelChannelTraits(image,channel);
+                PixelTrait rotate_traits=GetPixelChannelTraits(rotate_image,
+                  channel);
                 if ((traits == UndefinedPixelTrait) ||
                     (rotate_traits == UndefinedPixelTrait))
                   continue;
@@ -1376,6 +1077,9 @@ static Image *IntegralRotateImage(const Image *image,size_t rotations,
               tile_pixels+=width*GetPixelChannels(image);
               q+=GetPixelChannels(rotate_image);
             }
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+            #pragma omp critical (MagickCore_IntegralRotateImage)
+#endif
             sync=SyncCacheViewAuthenticPixels(rotate_view,exception);
             if (sync == MagickFalse)
               status=MagickFalse;
@@ -1386,9 +1090,6 @@ static Image *IntegralRotateImage(const Image *image,size_t rotations,
             MagickBooleanType
               proceed;
 
-#if defined(MAGICKCORE_OPENMP_SUPPORT)
-            #pragma omp critical (MagickCore_IntegralRotateImage)
-#endif
             proceed=SetImageProgress(image,RotateImageTag,progress+=tile_height,
               image->rows);
             if (proceed == MagickFalse)
@@ -1432,7 +1133,7 @@ static Image *IntegralRotateImage(const Image *image,size_t rotations,
 %
 %  The format of the XShearImage method is:
 %
-%      MagickBooleanType XShearImage(Image *image,const MagickRealType degrees,
+%      MagickBooleanType XShearImage(Image *image,const double degrees,
 %        const size_t width,const size_t height,
 %        const ssize_t x_offset,const ssize_t y_offset,ExceptionInfo *exception)
 %
@@ -1440,7 +1141,7 @@ static Image *IntegralRotateImage(const Image *image,size_t rotations,
 %
 %    o image: the image.
 %
-%    o degrees: A MagickRealType representing the shearing angle along the X
+%    o degrees: A double representing the shearing angle along the X
 %      axis.
 %
 %    o width, height, x_offset, y_offset: Defines a region of the image
@@ -1449,7 +1150,7 @@ static Image *IntegralRotateImage(const Image *image,size_t rotations,
 %    o exception: return any errors or warnings in this structure.
 %
 */
-static MagickBooleanType XShearImage(Image *image,const MagickRealType degrees,
+static MagickBooleanType XShearImage(Image *image,const double degrees,
   const size_t width,const size_t height,const ssize_t x_offset,
   const ssize_t y_offset,ExceptionInfo *exception)
 {
@@ -1486,9 +1187,10 @@ static MagickBooleanType XShearImage(Image *image,const MagickRealType degrees,
   status=MagickTrue;
   background=image->background_color;
   progress=0;
-  image_view=AcquireCacheView(image);
+  image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress, status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status) \
+    magick_threads(image,image,height,1)
 #endif
   for (y=0; y < (ssize_t) height; y++)
   {
@@ -1497,7 +1199,7 @@ static MagickBooleanType XShearImage(Image *image,const MagickRealType degrees,
       source,
       destination;
 
-    MagickRealType
+    double
       area,
       displacement;
 
@@ -1524,7 +1226,7 @@ static MagickBooleanType XShearImage(Image *image,const MagickRealType degrees,
         continue;
       }
     p+=x_offset*GetPixelChannels(image);
-    displacement=degrees*(MagickRealType) (y-height/2.0);
+    displacement=degrees*(double) (y-height/2.0);
     if (displacement == 0.0)
       continue;
     if (displacement > 0.0)
@@ -1535,7 +1237,7 @@ static MagickBooleanType XShearImage(Image *image,const MagickRealType degrees,
         direction=LEFT;
       }
     step=(ssize_t) floor((double) displacement);
-    area=(MagickRealType) (displacement-step);
+    area=(double) (displacement-step);
     step++;
     pixel=background;
     GetPixelInfo(image,&source);
@@ -1555,25 +1257,25 @@ static MagickBooleanType XShearImage(Image *image,const MagickRealType degrees,
           if ((x_offset+i) < step)
             {
               p+=GetPixelChannels(image);
-              SetPixelInfo(image,p,&pixel);
+              GetPixelInfoPixel(image,p,&pixel);
               q+=GetPixelChannels(image);
               continue;
             }
-          SetPixelInfo(image,p,&source);
-          CompositePixelInfoAreaBlend(&pixel,(MagickRealType) pixel.alpha,
-            &source,(MagickRealType) GetPixelAlpha(image,p),area,&destination);
-          SetPixelPixelInfo(image,&destination,q);
-          SetPixelInfo(image,p,&pixel);
+          GetPixelInfoPixel(image,p,&source);
+          CompositePixelInfoAreaBlend(&pixel,(double) pixel.alpha,
+            &source,(double) GetPixelAlpha(image,p),area,&destination);
+          SetPixelInfoPixel(image,&destination,q);
+          GetPixelInfoPixel(image,p,&pixel);
           p+=GetPixelChannels(image);
           q+=GetPixelChannels(image);
         }
-        CompositePixelInfoAreaBlend(&pixel,(MagickRealType) pixel.alpha,
-          &background,(MagickRealType) background.alpha,area,&destination);
-        SetPixelPixelInfo(image,&destination,q);
+        CompositePixelInfoAreaBlend(&pixel,(double) pixel.alpha,
+          &background,(double) background.alpha,area,&destination);
+        SetPixelInfoPixel(image,&destination,q);
         q+=GetPixelChannels(image);
         for (i=0; i < (step-1); i++)
         {
-          SetPixelPixelInfo(image,&background,q);
+          SetPixelInfoPixel(image,&background,q);
           q+=GetPixelChannels(image);
         }
         break;
@@ -1589,22 +1291,22 @@ static MagickBooleanType XShearImage(Image *image,const MagickRealType degrees,
         {
           p-=GetPixelChannels(image);
           q-=GetPixelChannels(image);
-          if ((size_t) (x_offset+width+step-i) >= image->columns)
+          if ((size_t) (x_offset+width+step-i) > image->columns)
             continue;
-          SetPixelInfo(image,p,&source);
-          CompositePixelInfoAreaBlend(&pixel,(MagickRealType) pixel.alpha,
-            &source,(MagickRealType) GetPixelAlpha(image,p),area,&destination);
-          SetPixelPixelInfo(image,&destination,q);
-          SetPixelInfo(image,p,&pixel);
+          GetPixelInfoPixel(image,p,&source);
+          CompositePixelInfoAreaBlend(&pixel,(double) pixel.alpha,
+            &source,(double) GetPixelAlpha(image,p),area,&destination);
+          SetPixelInfoPixel(image,&destination,q);
+          GetPixelInfoPixel(image,p,&pixel);
         }
-        CompositePixelInfoAreaBlend(&pixel,(MagickRealType) pixel.alpha,
-          &background,(MagickRealType) background.alpha,area,&destination);
+        CompositePixelInfoAreaBlend(&pixel,(double) pixel.alpha,
+          &background,(double) background.alpha,area,&destination);
         q-=GetPixelChannels(image);
-        SetPixelPixelInfo(image,&destination,q);
+        SetPixelInfoPixel(image,&destination,q);
         for (i=0; i < (step-1); i++)
         {
           q-=GetPixelChannels(image);
-          SetPixelPixelInfo(image,&background,q);
+          SetPixelInfoPixel(image,&background,q);
         }
         break;
       }
@@ -1647,7 +1349,7 @@ static MagickBooleanType XShearImage(Image *image,const MagickRealType degrees,
 %
 %  The format of the YShearImage method is:
 %
-%      MagickBooleanType YShearImage(Image *image,const MagickRealType degrees,
+%      MagickBooleanType YShearImage(Image *image,const double degrees,
 %        const size_t width,const size_t height,
 %        const ssize_t x_offset,const ssize_t y_offset,ExceptionInfo *exception)
 %
@@ -1655,7 +1357,7 @@ static MagickBooleanType XShearImage(Image *image,const MagickRealType degrees,
 %
 %    o image: the image.
 %
-%    o degrees: A MagickRealType representing the shearing angle along the Y
+%    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
@@ -1664,7 +1366,7 @@ static MagickBooleanType XShearImage(Image *image,const MagickRealType degrees,
 %    o exception: return any errors or warnings in this structure.
 %
 */
-static MagickBooleanType YShearImage(Image *image,const MagickRealType degrees,
+static MagickBooleanType YShearImage(Image *image,const double degrees,
   const size_t width,const size_t height,const ssize_t x_offset,
   const ssize_t y_offset,ExceptionInfo *exception)
 {
@@ -1701,16 +1403,17 @@ static MagickBooleanType YShearImage(Image *image,const MagickRealType degrees,
   status=MagickTrue;
   progress=0;
   background=image->background_color;
-  image_view=AcquireCacheView(image);
+  image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(progress, status)
+  #pragma omp parallel for schedule(static,4) shared(progress,status) \
+    magick_threads(image,image,width,1)
 #endif
   for (x=0; x < (ssize_t) width; x++)
   {
     ssize_t
       step;
 
-    MagickRealType
+    double
       area,
       displacement;
 
@@ -1739,7 +1442,7 @@ static MagickBooleanType YShearImage(Image *image,const MagickRealType degrees,
         continue;
       }
     p+=y_offset*GetPixelChannels(image);
-    displacement=degrees*(MagickRealType) (x-width/2.0);
+    displacement=degrees*(double) (x-width/2.0);
     if (displacement == 0.0)
       continue;
     if (displacement > 0.0)
@@ -1750,7 +1453,7 @@ static MagickBooleanType YShearImage(Image *image,const MagickRealType degrees,
         direction=UP;
       }
     step=(ssize_t) floor((double) displacement);
-    area=(MagickRealType) (displacement-step);
+    area=(double) (displacement-step);
     step++;
     pixel=background;
     GetPixelInfo(image,&source);
@@ -1770,26 +1473,26 @@ static MagickBooleanType YShearImage(Image *image,const MagickRealType degrees,
           if ((y_offset+i) < step)
             {
               p+=GetPixelChannels(image);
-              SetPixelInfo(image,p,&pixel);
+              GetPixelInfoPixel(image,p,&pixel);
               q+=GetPixelChannels(image);
               continue;
             }
-          SetPixelInfo(image,p,&source);
-          CompositePixelInfoAreaBlend(&pixel,(MagickRealType) pixel.alpha,
-            &source,(MagickRealType) GetPixelAlpha(image,p),area,
+          GetPixelInfoPixel(image,p,&source);
+          CompositePixelInfoAreaBlend(&pixel,(double) pixel.alpha,
+            &source,(double) GetPixelAlpha(image,p),area,
             &destination);
-          SetPixelPixelInfo(image,&destination,q);
-          SetPixelInfo(image,p,&pixel);
+          SetPixelInfoPixel(image,&destination,q);
+          GetPixelInfoPixel(image,p,&pixel);
           p+=GetPixelChannels(image);
           q+=GetPixelChannels(image);
         }
-        CompositePixelInfoAreaBlend(&pixel,(MagickRealType) pixel.alpha,
-          &background,(MagickRealType) background.alpha,area,&destination);
-        SetPixelPixelInfo(image,&destination,q);
+        CompositePixelInfoAreaBlend(&pixel,(double) pixel.alpha,
+          &background,(double) background.alpha,area,&destination);
+        SetPixelInfoPixel(image,&destination,q);
         q+=GetPixelChannels(image);
         for (i=0; i < (step-1); i++)
         {
-          SetPixelPixelInfo(image,&background,q);
+          SetPixelInfoPixel(image,&background,q);
           q+=GetPixelChannels(image);
         }
         break;
@@ -1805,23 +1508,23 @@ static MagickBooleanType YShearImage(Image *image,const MagickRealType degrees,
         {
           p-=GetPixelChannels(image);
           q-=GetPixelChannels(image);
-          if ((size_t) (y_offset+height+step-i) >= image->rows)
+          if ((size_t) (y_offset+height+step-i) > image->rows)
             continue;
-          SetPixelInfo(image,p,&source);
-          CompositePixelInfoAreaBlend(&pixel,(MagickRealType) pixel.alpha,
-            &source,(MagickRealType) GetPixelAlpha(image,p),area,
+          GetPixelInfoPixel(image,p,&source);
+          CompositePixelInfoAreaBlend(&pixel,(double) pixel.alpha,
+            &source,(double) GetPixelAlpha(image,p),area,
             &destination);
-          SetPixelPixelInfo(image,&destination,q);
-          SetPixelInfo(image,p,&pixel);
+          SetPixelInfoPixel(image,&destination,q);
+          GetPixelInfoPixel(image,p,&pixel);
         }
-        CompositePixelInfoAreaBlend(&pixel,(MagickRealType) pixel.alpha,
-          &background,(MagickRealType) background.alpha,area,&destination);
+        CompositePixelInfoAreaBlend(&pixel,(double) pixel.alpha,
+          &background,(double) background.alpha,area,&destination);
         q-=GetPixelChannels(image);
-        SetPixelPixelInfo(image,&destination,q);
+        SetPixelInfoPixel(image,&destination,q);
         for (i=0; i < (step-1); i++)
         {
           q-=GetPixelChannels(image);
-          SetPixelPixelInfo(image,&background,q);
+          SetPixelInfoPixel(image,&background,q);
         }
         break;
       }
@@ -1850,79 +1553,6 @@ static MagickBooleanType YShearImage(Image *image,const MagickRealType degrees,
 %                                                                             %
 %                                                                             %
 %                                                                             %
-%   R o t a t e I m a g e                                                     %
-%                                                                             %
-%                                                                             %
-%                                                                             %
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%
-%  RotateImage() creates a new image that is a rotated copy of an existing
-%  one.  Positive angles rotate counter-clockwise (right-hand rule), while
-%  negative angles rotate clockwise.  Rotated images are usually larger than
-%  the originals and have 'empty' triangular corners.  X axis.  Empty
-%  triangles left over from shearing the image are filled with the background
-%  color defined by member 'background_color' of the image.  RotateImage
-%  allocates the memory necessary for the new Image structure and returns a
-%  pointer to the new image.
-%
-%  The format of the RotateImage method is:
-%
-%      Image *RotateImage(const Image *image,const double degrees,
-%        ExceptionInfo *exception)
-%
-%  A description of each parameter follows.
-%
-%    o image: the image.
-%
-%    o degrees: Specifies the number of degrees to rotate the image.
-%
-%    o exception: return any errors or warnings in this structure.
-%
-*/
-MagickExport Image *RotateImage(const Image *image,const double degrees,
-  ExceptionInfo *exception)
-{
-  Image
-    *rotate_image;
-
-  MagickRealType
-    angle;
-
-  PointInfo
-    shear;
-
-  size_t
-    rotations;
-
-  /*
-    Adjust rotation angle.
-  */
-  assert(image != (Image *) NULL);
-  assert(image->signature == MagickSignature);
-  if (image->debug != MagickFalse)
-    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
-  assert(exception != (ExceptionInfo *) NULL);
-  assert(exception->signature == MagickSignature);
-  angle=degrees;
-  while (angle < -45.0)
-    angle+=360.0;
-  for (rotations=0; angle > 45.0; rotations++)
-    angle-=90.0;
-  rotations%=4;
-  shear.x=(-tan((double) DegreesToRadians(angle)/2.0));
-  shear.y=sin((double) DegreesToRadians(angle));
-  if ((fabs(shear.x) < MagickEpsilon) && (fabs(shear.y) < MagickEpsilon))
-    return(IntegralRotateImage(image,rotations,exception));
-  rotate_image=DistortImage(image,ScaleRotateTranslateDistortion,1,&degrees,
-    MagickTrue,exception);
-  return(rotate_image);
-}
-\f
-/*
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%                                                                             %
-%                                                                             %
-%                                                                             %
 %   S h e a r I m a g e                                                       %
 %                                                                             %
 %                                                                             %
@@ -1964,10 +1594,6 @@ MagickExport Image *ShearImage(const Image *image,const double x_shear,
     *integral_image,
     *shear_image;
 
-  ssize_t
-    x_offset,
-    y_offset;
-
   MagickBooleanType
     status;
 
@@ -1975,10 +1601,8 @@ MagickExport Image *ShearImage(const Image *image,const double x_shear,
     shear;
 
   RectangleInfo
-    border_info;
-
-  size_t
-    y_width;
+    border_info,
+    bounds;
 
   assert(image != (Image *) NULL);
   assert(image->signature == MagickSignature);
@@ -2005,23 +1629,23 @@ MagickExport Image *ShearImage(const Image *image,const double x_shear,
       integral_image=DestroyImage(integral_image);
       return(integral_image);
     }
-  if (integral_image->matte == MagickFalse)
+  if (integral_image->alpha_trait != BlendPixelTrait)
     (void) SetImageAlphaChannel(integral_image,OpaqueAlphaChannel,exception);
   /*
     Compute image size.
   */
-  y_width=image->columns+(ssize_t) floor(fabs(shear.x)*image->rows+0.5);
-  x_offset=(ssize_t) ceil((double) image->columns+((fabs(shear.x)*image->rows)-
+  bounds.width=image->columns+(ssize_t) floor(fabs(shear.x)*image->rows+0.5);
+  bounds.x=(ssize_t) ceil((double) image->columns+((fabs(shear.x)*image->rows)-
     image->columns)/2.0-0.5);
-  y_offset=(ssize_t) ceil((double) image->rows+((fabs(shear.y)*y_width)-
+  bounds.y=(ssize_t) ceil((double) image->rows+((fabs(shear.y)*bounds.width)-
     image->rows)/2.0-0.5);
   /*
     Surround image with border.
   */
   integral_image->border_color=integral_image->background_color;
   integral_image->compose=CopyCompositeOp;
-  border_info.width=(size_t) x_offset;
-  border_info.height=(size_t) y_offset;
+  border_info.width=(size_t) bounds.x;
+  border_info.height=(size_t) bounds.y;
   shear_image=BorderImage(integral_image,&border_info,image->compose,exception);
   integral_image=DestroyImage(integral_image);
   if (shear_image == (Image *) NULL)
@@ -2029,17 +1653,17 @@ MagickExport Image *ShearImage(const Image *image,const double x_shear,
   /*
     Shear the image.
   */
-  if (shear_image->matte == MagickFalse)
+  if (shear_image->alpha_trait != BlendPixelTrait)
     (void) SetImageAlphaChannel(shear_image,OpaqueAlphaChannel,exception);
-  status=XShearImage(shear_image,shear.x,image->columns,image->rows,x_offset,
+  status=XShearImage(shear_image,shear.x,image->columns,image->rows,bounds.x,
     (ssize_t) (shear_image->rows-image->rows)/2,exception);
   if (status == MagickFalse)
     {
       shear_image=DestroyImage(shear_image);
       return((Image *) NULL);
     }
-  status=YShearImage(shear_image,shear.y,y_width,image->rows,(ssize_t)
-    (shear_image->columns-y_width)/2,y_offset,exception);
+  status=YShearImage(shear_image,shear.y,bounds.width,image->rows,(ssize_t)
+    (shear_image->columns-bounds.width)/2,bounds.y,exception);
   if (status == MagickFalse)
     {
       shear_image=DestroyImage(shear_image);
@@ -2047,13 +1671,166 @@ MagickExport Image *ShearImage(const Image *image,const double x_shear,
     }
   status=CropToFitImage(&shear_image,shear.x,shear.y,(MagickRealType)
     image->columns,(MagickRealType) image->rows,MagickFalse,exception);
-  if (status == MagickFalse)
-    {
-      shear_image=DestroyImage(shear_image);
-      return((Image *) NULL);
-    }
   shear_image->compose=image->compose;
   shear_image->page.width=0;
   shear_image->page.height=0;
+  if (status == MagickFalse)
+    shear_image=DestroyImage(shear_image);
   return(shear_image);
 }
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   S h e a r R o t a t e I m a g e                                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ShearRotateImage() creates a new image that is a rotated copy of an existing
+%  one.  Positive angles rotate counter-clockwise (right-hand rule), while
+%  negative angles rotate clockwise.  Rotated images are usually larger than
+%  the originals and have 'empty' triangular corners.  X axis.  Empty
+%  triangles left over from shearing the image are filled with the background
+%  color defined by member 'background_color' of the image.  ShearRotateImage
+%  allocates the memory necessary for the new Image structure and returns a
+%  pointer to the new image.
+%
+%  ShearRotateImage() is based on the paper "A Fast Algorithm for General
+%  Raster Rotatation" by Alan W. Paeth.  ShearRotateImage is adapted from a
+%  similar method based on the Paeth paper written by Michael Halle of the
+%  Spatial Imaging Group, MIT Media Lab.
+%
+%  The format of the ShearRotateImage method is:
+%
+%      Image *ShearRotateImage(const Image *image,const double degrees,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows.
+%
+%    o image: the image.
+%
+%    o degrees: Specifies the number of degrees to rotate the image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport Image *ShearRotateImage(const Image *image,const double degrees,
+  ExceptionInfo *exception)
+{
+  Image
+    *integral_image,
+    *rotate_image;
+
+  MagickBooleanType
+    status;
+
+  MagickRealType
+    angle;
+
+  PointInfo
+    shear;
+
+  RectangleInfo
+    border_info,
+    bounds;
+
+  size_t
+    height,
+    rotations,
+    shear_width,
+    width;
+
+  /*
+    Adjust rotation angle.
+  */
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  angle=degrees;
+  while (angle < -45.0)
+    angle+=360.0;
+  for (rotations=0; angle > 45.0; rotations++)
+    angle-=90.0;
+  rotations%=4;
+  /*
+    Calculate shear equations.
+  */
+  integral_image=IntegralRotateImage(image,rotations,exception);
+  if (integral_image == (Image *) NULL)
+    ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+  shear.x=(-tan((double) DegreesToRadians(angle)/2.0));
+  shear.y=sin((double) DegreesToRadians(angle));
+  if ((shear.x == 0.0) && (shear.y == 0.0))
+    return(integral_image);
+  if (SetImageStorageClass(integral_image,DirectClass,exception) == MagickFalse)
+    {
+      integral_image=DestroyImage(integral_image);
+      return(integral_image);
+    }
+  if (integral_image->alpha_trait != BlendPixelTrait)
+    (void) SetImageAlphaChannel(integral_image,OpaqueAlphaChannel,exception);
+  /*
+    Compute maximum bounds for 3 shear operations.
+  */
+  width=integral_image->columns;
+  height=integral_image->rows;
+  bounds.width=(size_t) floor(fabs((double) height*shear.x)+width+0.5);
+  bounds.height=(size_t) floor(fabs((double) bounds.width*shear.y)+height+0.5);
+  shear_width=(size_t) floor(fabs((double) bounds.height*shear.x)+
+    bounds.width+0.5);
+  bounds.x=(ssize_t) floor((double) ((shear_width > bounds.width) ? width :
+    bounds.width-shear_width+2)/2.0+0.5);
+  bounds.y=(ssize_t) floor(((double) bounds.height-height+2)/2.0+0.5);
+  /*
+    Surround image with a border.
+  */
+  integral_image->border_color=integral_image->background_color;
+  integral_image->compose=CopyCompositeOp;
+  border_info.width=(size_t) bounds.x;
+  border_info.height=(size_t) bounds.y;
+  rotate_image=BorderImage(integral_image,&border_info,image->compose,
+    exception);
+  integral_image=DestroyImage(integral_image);
+  if (rotate_image == (Image *) NULL)
+    ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+  /*
+    Rotate the image.
+  */
+  status=XShearImage(rotate_image,shear.x,width,height,bounds.x,(ssize_t)
+    (rotate_image->rows-height)/2,exception);
+  if (status == MagickFalse)
+    {
+      rotate_image=DestroyImage(rotate_image);
+      return((Image *) NULL);
+    }
+  status=YShearImage(rotate_image,shear.y,bounds.width,height,(ssize_t)
+    (rotate_image->columns-bounds.width)/2,bounds.y,exception);
+  if (status == MagickFalse)
+    {
+      rotate_image=DestroyImage(rotate_image);
+      return((Image *) NULL);
+    }
+  status=XShearImage(rotate_image,shear.x,bounds.width,bounds.height,(ssize_t)
+    (rotate_image->columns-bounds.width)/2,(ssize_t) (rotate_image->rows-
+    bounds.height)/2,exception);
+  if (status == MagickFalse)
+    {
+      rotate_image=DestroyImage(rotate_image);
+      return((Image *) NULL);
+    }
+  status=CropToFitImage(&rotate_image,shear.x,shear.y,(MagickRealType) width,
+    (MagickRealType) height,MagickTrue,exception);
+  rotate_image->compose=image->compose;
+  rotate_image->page.width=0;
+  rotate_image->page.height=0;
+  if (status == MagickFalse)
+    rotate_image=DestroyImage(rotate_image);
+  return(rotate_image);
+}