]> granicus.if.org Git - imagemagick/blobdiff - MagickCore/pixel.c
(no commit message)
[imagemagick] / MagickCore / pixel.c
index 43c9c6eae8ac5834da38188b0169d2b6fe5cab59..79c890b2e9ba642b2d3d76611b74b380c1ae53dd 100644 (file)
 %
 %  The format of the AcquirePixelChannelMap() method is:
 %
-%      PixelChannelMap **AcquirePixelChannelMap(void)
+%      PixelChannelMap *AcquirePixelChannelMap(void)
 %
 */
-MagickExport PixelChannelMap **AcquirePixelChannelMap(void)
+MagickExport PixelChannelMap *AcquirePixelChannelMap(void)
 {
   PixelChannelMap
-    **channel_map;
+    *channel_map;
 
   register ssize_t
     i;
 
-  channel_map=(PixelChannelMap **) AcquireAlignedMemory(MaxPixelChannelMaps,
-    sizeof(**channel_map));
-  if (channel_map == (PixelChannelMap **) NULL)
+  channel_map=(PixelChannelMap *) AcquireQuantumMemory(MaxPixelChannels,
+    sizeof(*channel_map));
+  if (channel_map == (PixelChannelMap *) NULL)
     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
-  for (i=0; i < MaxPixelChannelMaps; i++)
-  {
-    register ssize_t
-      j;
-
-    channel_map[i]=(PixelChannelMap *) AcquireQuantumMemory(MaxPixelChannels,
-      sizeof(*channel_map[i]));
-    if (channel_map[i] == (PixelChannelMap *) NULL)
-      ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
-    (void) ResetMagickMemory(channel_map[i],0,MaxPixelChannels*
-      sizeof(*channel_map[i]));
-    for (j=0; j < MaxPixelChannels; j++)
-      channel_map[i][j].channel=(PixelChannel) j;
-  }
+  (void) ResetMagickMemory(channel_map,0,MaxPixelChannels*sizeof(*channel_map));
+  for (i=0; i < MaxPixelChannels; i++)
+    channel_map[i].channel=(PixelChannel) i;
   return(channel_map);
 }
 \f
@@ -130,30 +119,24 @@ MagickExport PixelChannelMap **AcquirePixelChannelMap(void)
 %
 %  The format of the ClonePixelChannelMap() method is:
 %
-%      PixelChannelMap **ClonePixelChannelMap(
-%        PixelChannelMap **channel_map)
+%      PixelChannelMap *ClonePixelChannelMap(PixelChannelMap *channel_map)
 %
 %  A description of each parameter follows:
 %
 %    o channel_map: the pixel component map.
 %
 */
-MagickExport PixelChannelMap **ClonePixelChannelMap(
-  PixelChannelMap **channel_map)
+MagickExport PixelChannelMap *ClonePixelChannelMap(PixelChannelMap *channel_map)
 {
   PixelChannelMap
-    **clone_map;
-
-  register ssize_t
-    i;
+    *clone_map;
 
-  assert(channel_map != (PixelChannelMap **) NULL);
+  assert(channel_map != (PixelChannelMap *) NULL);
   clone_map=AcquirePixelChannelMap();
-  if (clone_map == (PixelChannelMap **) NULL)
-    return((PixelChannelMap **) NULL);
-  for (i=0; i < MaxPixelChannelMaps; i++)
-    (void) CopyMagickMemory(clone_map[i],channel_map[i],MaxPixelChannels*
-      sizeof(*channel_map[i]));
+  if (clone_map == (PixelChannelMap *) NULL)
+    return((PixelChannelMap *) NULL);
+  (void) CopyMagickMemory(clone_map,channel_map,MaxPixelChannels*
+    sizeof(*channel_map));
   return(clone_map);
 }
 \f
@@ -208,23 +191,19 @@ MagickExport PixelInfo *ClonePixelInfo(const PixelInfo *pixel)
 %
 %  The format of the DestroyPixelChannelMap() method is:
 %
-%      PixelChannelMap **DestroyPixelChannelMap(PixelChannelMap **channel_map)
+%      PixelChannelMap *DestroyPixelChannelMap(PixelChannelMap *channel_map)
 %
 %  A description of each parameter follows:
 %
 %    o channel_map: the pixel component map.
 %
 */
-MagickExport PixelChannelMap **DestroyPixelChannelMap(
-  PixelChannelMap **channel_map)
+MagickExport PixelChannelMap *DestroyPixelChannelMap(
+  PixelChannelMap *channel_map)
 {
-  register ssize_t
-    i;
-
-  assert(channel_map != (PixelChannelMap **) NULL);
-  for (i=0; i < MaxPixelChannelMaps; i++)
-    channel_map[i]=(PixelChannelMap *) RelinquishMagickMemory(channel_map[i]);
-  return((PixelChannelMap **) RelinquishMagickMemory(channel_map));
+  assert(channel_map != (PixelChannelMap *) NULL);
+  channel_map=(PixelChannelMap *) RelinquishMagickMemory(channel_map);
+  return((PixelChannelMap *) RelinquishMagickMemory(channel_map));
 }
 \f
 /*
@@ -1818,7 +1797,7 @@ MagickExport void GetPixelInfo(const Image *image,
 %      MagickBooleanType ImportImagePixels(Image *image,const ssize_t x_offset,
 %        const ssize_t y_offset,const size_t columns,
 %        const size_t rows,const char *map,const StorageType type,
-%        const void *pixels)
+%        const void *pixels,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
@@ -1842,15 +1821,14 @@ MagickExport void GetPixelInfo(const Image *image,
 %      map and type.  You must preallocate this array where the expected
 %      length varies depending on the values of width, height, map, and type.
 %
+%    o exception: return any errors or warnings in this structure.
+%
 */
 MagickExport MagickBooleanType ImportImagePixels(Image *image,
   const ssize_t x_offset,const ssize_t y_offset,const size_t columns,
   const size_t rows,const char *map,const StorageType type,
-  const void *pixels)
+  const void *pixels,ExceptionInfo *exception)
 {
-  ExceptionInfo
-    *exception;
-
   QuantumType
     *quantum_map;
 
@@ -1900,7 +1878,7 @@ MagickExport MagickBooleanType ImportImagePixels(Image *image,
       case 'c':
       {
         quantum_map[i]=CyanQuantum;
-        (void) SetImageColorspace(image,CMYKColorspace);
+        (void) SetImageColorspace(image,CMYKColorspace,exception);
         break;
       }
       case 'g':
@@ -1913,7 +1891,7 @@ MagickExport MagickBooleanType ImportImagePixels(Image *image,
       case 'k':
       {
         quantum_map[i]=BlackQuantum;
-        (void) SetImageColorspace(image,CMYKColorspace);
+        (void) SetImageColorspace(image,CMYKColorspace,exception);
         break;
       }
       case 'I':
@@ -1926,7 +1904,7 @@ MagickExport MagickBooleanType ImportImagePixels(Image *image,
       case 'M':
       {
         quantum_map[i]=MagentaQuantum;
-        (void) SetImageColorspace(image,CMYKColorspace);
+        (void) SetImageColorspace(image,CMYKColorspace,exception);
         break;
       }
       case 'O':
@@ -1952,24 +1930,23 @@ MagickExport MagickBooleanType ImportImagePixels(Image *image,
       case 'y':
       {
         quantum_map[i]=YellowQuantum;
-        (void) SetImageColorspace(image,CMYKColorspace);
+        (void) SetImageColorspace(image,CMYKColorspace,exception);
         break;
       }
       default:
       {
         quantum_map=(QuantumType *) RelinquishMagickMemory(quantum_map);
-        (void) ThrowMagickException(&image->exception,GetMagickModule(),
-          OptionError,"UnrecognizedPixelMap","`%s'",map);
+        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
+          "UnrecognizedPixelMap","`%s'",map);
         return(MagickFalse);
       }
     }
   }
-  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
+  if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
     return(MagickFalse);
   /*
     Transfer the pixels from the pixel datarray to the image.
   */
-  exception=(&image->exception);
   switch (type)
   {
     case CharPixel:
@@ -3567,23 +3544,93 @@ MagickExport MagickBooleanType ImportImagePixels(Image *image,
 %                                                                             %
 %                                                                             %
 %                                                                             %
-%   I n t e r p o l a t e M a g i c k P i x e l P a c k e t                   %
++   I n i t i a l i z e P i x e l C h a n n e l M a p                         %
 %                                                                             %
 %                                                                             %
 %                                                                             %
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
-%  InterpolatePixelInfo() applies bi-linear or tri-linear interpolation
-%  between a floating point coordinate and the pixels surrounding that
-%  coordinate.  No pixel area resampling, or scaling of the result is
-%  performed.
+%  InitializePixelChannelMap() defines the standard pixel component map.
 %
-%  The format of the InterpolatePixelInfo method is:
+%  The format of the InitializePixelChannelMap() method is:
 %
-%      MagickBooleanType InterpolatePixelInfo(const Image *image,
-%        const CacheView *image_view,const InterpolatePixelMethod method,
-%        const double x,const double y,PixelInfo *pixel,
-%        ExceptionInfo *exception)
+%      void InitializePixelChannelMap(Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+*/
+MagickExport void InitializePixelChannelMap(Image *image)
+{
+  PixelChannel
+    alpha_channel;
+
+  register ssize_t
+    i;
+
+  for (i=0; i < (ssize_t) MaxPixelChannels; i++)
+  {
+    SetPixelChannelMapChannel(image,(PixelChannel) i,(PixelChannel) i);
+    SetPixelChannelMapTraits(image,(PixelChannel) i,UndefinedPixelTrait);
+  }
+  image->sync=MagickTrue;
+  image->number_channels=4;
+  if (0 && image->colorspace == GRAYColorspace)
+    image->number_channels=2;
+  if (image->colorspace == CMYKColorspace)
+    image->number_channels++;
+  if (image->storage_class == PseudoClass)
+    image->number_channels++;
+  for (i=0; i < (ssize_t) image->number_channels; i++)
+    SetPixelChannelMapTraits(image,(PixelChannel) i,(PixelTrait)
+      UpdatePixelTrait);
+  alpha_channel=GetPixelChannelMapChannel(image,AlphaPixelChannel);
+  if (image->matte == MagickFalse)
+    SetPixelChannelMapTraits(image,AlphaPixelChannel,CopyPixelTrait);
+  else
+    for (i=0; i < (ssize_t) image->number_channels; i++)
+      if ((PixelChannel) i != alpha_channel)
+        SetPixelChannelMapTraits(image,(PixelChannel) i,(PixelTrait)
+          (UpdatePixelTrait | BlendPixelTrait));
+  if (0 && image->colorspace == GRAYColorspace)
+    {
+      image->number_channels=2;
+      SetPixelChannelMapChannel(image,GreenPixelChannel,RedPixelChannel);
+      SetPixelChannelMapChannel(image,BluePixelChannel,RedPixelChannel);
+    }
+  if (image->storage_class == PseudoClass)
+    {
+      SetPixelChannelMapChannel(image,IndexPixelChannel,IndexPixelChannel);
+      SetPixelChannelMapTraits(image,IndexPixelChannel,CopyPixelTrait);
+    }
+  image->number_channels+=image->number_meta_channels;
+  for ( ; i < (ssize_t) image->number_channels; i++)
+    SetPixelChannelMapTraits(image,(PixelChannel) i,CopyPixelTrait);
+  (void) SetPixelChannelMask(image,image->channel_mask);
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   I n t e r p o l a t e P i x e l C h a n n e l                             %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  InterpolatePixelChannel() applies a pixel interpolation method between a
+%  floating point coordinate and the pixels surrounding that coordinate.  No
+%  pixel area resampling, or scaling of the result is performed.
+%
+%  The format of the InterpolatePixelChannel method is:
+%
+%      MagickBooleanType InterpolatePixelChannel(const Image *image,
+%        const CacheView *image_view,const PixelChannel channel,
+%        const PixelInterpolateMethod method,const double x,const double y,
+%        double *pixel,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
@@ -3591,6 +3638,8 @@ MagickExport MagickBooleanType ImportImagePixels(Image *image,
 %
 %    o image_view: the image view.
 %
+%    o channel: the pixel channel to interpolate.
+%
 %    o method: the pixel color interpolation method.
 %
 %    o x,y: A double representing the current (x,y) position of the pixel.
@@ -3601,72 +3650,6 @@ MagickExport MagickBooleanType ImportImagePixels(Image *image,
 %
 */
 
-static inline void AlphaBlendPixelInfo(const Image *image,
-  const Quantum *pixel,PixelInfo *pixel_info,MagickRealType *alpha)
-{
-  if (image->matte == MagickFalse)
-    {
-      *alpha=1.0;
-      pixel_info->red=(MagickRealType) GetPixelRed(image,pixel);
-      pixel_info->green=(MagickRealType) GetPixelGreen(image,pixel);
-      pixel_info->blue=(MagickRealType) GetPixelBlue(image,pixel);
-      pixel_info->black=0.0;
-      if (image->colorspace == CMYKColorspace)
-        pixel_info->black=(MagickRealType) GetPixelBlack(image,pixel);
-      pixel_info->alpha=(MagickRealType) GetPixelAlpha(image,pixel);
-      return;
-    }
-  *alpha=QuantumScale*GetPixelAlpha(image,pixel);
-  pixel_info->red=(*alpha*GetPixelRed(image,pixel));
-  pixel_info->green=(*alpha*GetPixelGreen(image,pixel));
-  pixel_info->blue=(*alpha*GetPixelBlue(image,pixel));
-  pixel_info->black=0.0;
-  if (image->colorspace == CMYKColorspace)
-    pixel_info->black=(*alpha*GetPixelBlack(image,pixel));
-  pixel_info->alpha=(MagickRealType) GetPixelAlpha(image,pixel);
-}
-
-static void BicubicInterpolate(const PixelInfo *pixels,const double dx,
-  PixelInfo *pixel)
-{
-  MagickRealType
-    dx2,
-    p,
-    q,
-    r,
-    s;
-
-  dx2=dx*dx;
-  p=(pixels[3].red-pixels[2].red)-(pixels[0].red-pixels[1].red);
-  q=(pixels[0].red-pixels[1].red)-p;
-  r=pixels[2].red-pixels[0].red;
-  s=pixels[1].red;
-  pixel->red=(dx*dx2*p)+(dx2*q)+(dx*r)+s;
-  p=(pixels[3].green-pixels[2].green)-(pixels[0].green-pixels[1].green);
-  q=(pixels[0].green-pixels[1].green)-p;
-  r=pixels[2].green-pixels[0].green;
-  s=pixels[1].green;
-  pixel->green=(dx*dx2*p)+(dx2*q)+(dx*r)+s;
-  p=(pixels[3].blue-pixels[2].blue)-(pixels[0].blue-pixels[1].blue);
-  q=(pixels[0].blue-pixels[1].blue)-p;
-  r=pixels[2].blue-pixels[0].blue;
-  s=pixels[1].blue;
-  pixel->blue=(dx*dx2*p)+(dx2*q)+(dx*r)+s;
-  p=(pixels[3].alpha-pixels[2].alpha)-(pixels[0].alpha-pixels[1].alpha);
-  q=(pixels[0].alpha-pixels[1].alpha)-p;
-  r=pixels[2].alpha-pixels[0].alpha;
-  s=pixels[1].alpha;
-  pixel->alpha=(dx*dx2*p)+(dx2*q)+(dx*r)+s;
-  if (pixel->colorspace == CMYKColorspace)
-    {
-      p=(pixels[3].black-pixels[2].black)-(pixels[0].black-pixels[1].black);
-      q=(pixels[0].black-pixels[1].black)-p;
-      r=pixels[2].black-pixels[0].black;
-      s=pixels[1].black;
-      pixel->black=(dx*dx2*p)+(dx2*q)+(dx*r)+s;
-    }
-}
-
 static inline double MagickMax(const MagickRealType x,const MagickRealType y)
 {
   if (x > y)
@@ -3704,20 +3687,22 @@ static inline ssize_t NearestNeighbor(const MagickRealType x)
   return((ssize_t) (x-0.5));
 }
 
-MagickExport MagickBooleanType InterpolatePixelInfo(const Image *image,
-  const CacheView *image_view,const InterpolatePixelMethod method,
-  const double x,const double y,PixelInfo *pixel,ExceptionInfo *exception)
+MagickExport MagickBooleanType InterpolatePixelChannel(const Image *image,
+  const CacheView *image_view,const PixelChannel channel,
+  const PixelInterpolateMethod method,const double x,const double y,
+  double *pixel,ExceptionInfo *exception)
 {
   MagickBooleanType
     status;
 
   MagickRealType
     alpha[16],
-    gamma;
-
-  PixelInfo
+    gamma,
     pixels[16];
 
+  PixelTrait
+    traits;
+
   register const Quantum
     *p;
 
@@ -3728,10 +3713,13 @@ MagickExport MagickBooleanType InterpolatePixelInfo(const Image *image,
     x_offset,
     y_offset;
 
+  assert(image != (Image *) NULL);
   assert(image != (Image *) NULL);
   assert(image->signature == MagickSignature);
   assert(image_view != (CacheView *) NULL);
   status=MagickTrue;
+  *pixel=0.0;
+  traits=GetPixelChannelMapTraits(image,channel);
   x_offset=(ssize_t) floor(x);
   y_offset=(ssize_t) floor(y);
   switch (method == UndefinedInterpolatePixel ? image->interpolate : method)
@@ -3745,49 +3733,31 @@ MagickExport MagickBooleanType InterpolatePixelInfo(const Image *image,
           status=MagickFalse;
           break;
         }
-      AlphaBlendPixelInfo(image,p,pixels+0,alpha+0);
-      AlphaBlendPixelInfo(image,p+1*GetPixelChannels(image),pixels+1,alpha+1);
-      AlphaBlendPixelInfo(image,p+2*GetPixelChannels(image),pixels+2,alpha+2);
-      AlphaBlendPixelInfo(image,p+3*GetPixelChannels(image),pixels+3,alpha+3);
-      AlphaBlendPixelInfo(image,p+4*GetPixelChannels(image),pixels+4,alpha+4);
-      AlphaBlendPixelInfo(image,p+5*GetPixelChannels(image),pixels+5,alpha+5);
-      AlphaBlendPixelInfo(image,p+6*GetPixelChannels(image),pixels+6,alpha+6);
-      AlphaBlendPixelInfo(image,p+7*GetPixelChannels(image),pixels+7,alpha+7);
-      AlphaBlendPixelInfo(image,p+8*GetPixelChannels(image),pixels+8,alpha+8);
-      AlphaBlendPixelInfo(image,p+9*GetPixelChannels(image),pixels+9,alpha+9);
-      AlphaBlendPixelInfo(image,p+10*GetPixelChannels(image),pixels+10,alpha+
-        10);
-      AlphaBlendPixelInfo(image,p+11*GetPixelChannels(image),pixels+11,alpha+
-        11);
-      AlphaBlendPixelInfo(image,p+12*GetPixelChannels(image),pixels+12,alpha+
-        12);
-      AlphaBlendPixelInfo(image,p+13*GetPixelChannels(image),pixels+13,alpha+
-        13);
-      AlphaBlendPixelInfo(image,p+14*GetPixelChannels(image),pixels+14,alpha+
-        14);
-      AlphaBlendPixelInfo(image,p+15*GetPixelChannels(image),pixels+15,alpha+
-        15);
-      pixel->red=0.0;
-      pixel->green=0.0;
-      pixel->blue=0.0;
-      pixel->black=0.0;
-      pixel->alpha=0.0;
-      for (i=0; i < 16L; i++)
+      if ((traits & BlendPixelTrait) == 0)
+        for (i=0; i < 16; i++)
+        {
+          alpha[i]=1.0;
+          pixels[i]=(MagickRealType) p[i*GetPixelChannels(image)+channel];
+        }
+      else
+        for (i=0; i < 16; i++)
+        {
+          alpha[i]=QuantumScale*GetPixelAlpha(image,p+i*
+            GetPixelChannels(image));
+          pixels[i]=alpha[i]*p[i*GetPixelChannels(image)+channel];
+        }
+      for (i=0; i < 16; i++)
       {
         gamma=1.0/(fabs((double) alpha[i]) <= MagickEpsilon ? 1.0 : alpha[i]);
-        pixel->red+=gamma*0.0625*pixels[i].red;
-        pixel->green+=gamma*0.0625*pixels[i].green;
-        pixel->blue+=gamma*0.0625*pixels[i].blue;
-        if (image->colorspace == CMYKColorspace)
-          pixel->black+=gamma*0.0625*pixels[i].black;
-        pixel->alpha+=0.0625*pixels[i].alpha;
+        *pixel+=gamma*0.0625*pixels[i];
       }
       break;
     }
     case BicubicInterpolatePixel:
     {
-      PixelInfo
-        u[4];
+      MagickRealType
+        u[4],
+        v[4];
 
       PointInfo
         delta;
@@ -3799,33 +3769,36 @@ MagickExport MagickBooleanType InterpolatePixelInfo(const Image *image,
           status=MagickFalse;
           break;
         }
-      AlphaBlendPixelInfo(image,p,pixels+0,alpha+0);
-      AlphaBlendPixelInfo(image,p+1*GetPixelChannels(image),pixels+1,alpha+1);
-      AlphaBlendPixelInfo(image,p+2*GetPixelChannels(image),pixels+2,alpha+2);
-      AlphaBlendPixelInfo(image,p+3*GetPixelChannels(image),pixels+3,alpha+3);
-      AlphaBlendPixelInfo(image,p+4*GetPixelChannels(image),pixels+4,alpha+4);
-      AlphaBlendPixelInfo(image,p+5*GetPixelChannels(image),pixels+5,alpha+5);
-      AlphaBlendPixelInfo(image,p+6*GetPixelChannels(image),pixels+6,alpha+6);
-      AlphaBlendPixelInfo(image,p+7*GetPixelChannels(image),pixels+7,alpha+7);
-      AlphaBlendPixelInfo(image,p+8*GetPixelChannels(image),pixels+8,alpha+8);
-      AlphaBlendPixelInfo(image,p+9*GetPixelChannels(image),pixels+9,alpha+9);
-      AlphaBlendPixelInfo(image,p+10*GetPixelChannels(image),pixels+10,alpha+
-        10);
-      AlphaBlendPixelInfo(image,p+11*GetPixelChannels(image),pixels+11,alpha+
-        11);
-      AlphaBlendPixelInfo(image,p+12*GetPixelChannels(image),pixels+12,alpha+
-        12);
-      AlphaBlendPixelInfo(image,p+13*GetPixelChannels(image),pixels+13,alpha+
-        13);
-      AlphaBlendPixelInfo(image,p+14*GetPixelChannels(image),pixels+14,alpha+
-        14);
-      AlphaBlendPixelInfo(image,p+15*GetPixelChannels(image),pixels+15,alpha+
-        15);
+      if ((traits & BlendPixelTrait) == 0)
+        for (i=0; i < 16; i++)
+        {
+          alpha[i]=1.0;
+          pixels[i]=(MagickRealType) p[i*GetPixelChannels(image)+channel];
+        }
+      else
+        for (i=0; i < 16; i++)
+        {
+          alpha[i]=QuantumScale*GetPixelAlpha(image,p+i*
+            GetPixelChannels(image));
+          pixels[i]=alpha[i]*p[i*GetPixelChannels(image)+channel];
+        }
       delta.x=x-x_offset;
       delta.y=y-y_offset;
-      for (i=0; i < 4L; i++)
-        BicubicInterpolate(pixels+4*i,delta.x,u+i);
-      BicubicInterpolate(u,delta.y,pixel);
+      for (i=0; i < 4; i++)
+      {
+        u[0]=(pixels[4*i+3]-pixels[4*i+2])-(pixels[4*i+0]-pixels[4*i+1]);
+        u[1]=(pixels[4*i+0]-pixels[4*i+1])-u[0];
+        u[2]=pixels[4*i+2]-pixels[4*i+0];
+        u[3]=pixels[4*i+1];
+        v[i]=(delta.x*delta.x*delta.x*u[0])+(delta.x*delta.x*u[1])+(delta.x*
+          u[2])+u[3];
+      }
+      u[0]=(v[3]-v[2])-(v[0]-v[1]);
+      u[1]=(v[0]-v[1])-u[0];
+      u[2]=v[2]-v[0];
+      u[3]=v[1];
+      *pixel=(delta.y*delta.y*delta.y*u[0])+(delta.y*delta.y*u[1])+(delta.y*
+        u[2])+u[3];
       break;
     }
     case BilinearInterpolatePixel:
@@ -3841,10 +3814,19 @@ MagickExport MagickBooleanType InterpolatePixelInfo(const Image *image,
           status=MagickFalse;
           break;
         }
-      AlphaBlendPixelInfo(image,p,pixels+0,alpha+0);
-      AlphaBlendPixelInfo(image,p+1*GetPixelChannels(image),pixels+1,alpha+1);
-      AlphaBlendPixelInfo(image,p+2*GetPixelChannels(image),pixels+2,alpha+2);
-      AlphaBlendPixelInfo(image,p+3*GetPixelChannels(image),pixels+3,alpha+3);
+      if ((traits & BlendPixelTrait) == 0)
+        for (i=0; i < 4; i++)
+        {
+          alpha[i]=1.0;
+          pixels[i]=(MagickRealType) p[i*GetPixelChannels(image)+channel];
+        }
+      else
+        for (i=0; i < 4; i++)
+        {
+          alpha[i]=QuantumScale*GetPixelAlpha(image,p+i*
+            GetPixelChannels(image));
+          pixels[i]=alpha[i]*p[i*GetPixelChannels(image)+channel];
+        }
       delta.x=x-x_offset;
       delta.y=y-y_offset;
       epsilon.x=1.0-delta.x;
@@ -3852,21 +3834,8 @@ MagickExport MagickBooleanType InterpolatePixelInfo(const Image *image,
       gamma=((epsilon.y*(epsilon.x*alpha[0]+delta.x*alpha[1])+delta.y*
         (epsilon.x*alpha[2]+delta.x*alpha[3])));
       gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
-      pixel->red=gamma*(epsilon.y*(epsilon.x*pixels[0].red+delta.x*
-        pixels[1].red)+delta.y*(epsilon.x*pixels[2].red+delta.x*pixels[3].red));
-      pixel->green=gamma*(epsilon.y*(epsilon.x*pixels[0].green+delta.x*
-        pixels[1].green)+delta.y*(epsilon.x*pixels[2].green+delta.x*
-        pixels[3].green));
-      pixel->blue=gamma*(epsilon.y*(epsilon.x*pixels[0].blue+delta.x*
-        pixels[1].blue)+delta.y*(epsilon.x*pixels[2].blue+delta.x*
-        pixels[3].blue));
-      if (image->colorspace == CMYKColorspace)
-        pixel->black=gamma*(epsilon.y*(epsilon.x*pixels[0].black+delta.x*
-          pixels[1].black)+delta.y*(epsilon.x*pixels[2].black+delta.x*
-          pixels[3].black));
-      pixel->alpha=(epsilon.y*(epsilon.x*pixels[0].alpha+delta.x*
-        pixels[1].alpha)+delta.y*(epsilon.x*pixels[2].alpha+delta.x*
-        pixels[3].alpha));
+      *pixel=gamma*(epsilon.y*(epsilon.x*pixels[0]+delta.x*pixels[1])+delta.y*
+        (epsilon.x*pixels[2]+delta.x*pixels[3]));
       break;
     }
     case FilterInterpolatePixel:
@@ -3898,8 +3867,10 @@ MagickExport MagickBooleanType InterpolatePixelInfo(const Image *image,
         break;
       filter_view=AcquireCacheView(filter_image);
       p=GetCacheViewVirtualPixels(filter_view,0,0,1,1,exception);
-      if (p != (const Quantum *) NULL)
-        SetPixelInfo(image,p,pixel);
+      if (p == (const Quantum *) NULL)
+        status=MagickFalse;
+      else
+        *pixel=(double) p[channel];
       filter_view=DestroyCacheView(filter_view);
       filter_image=DestroyImage(filter_image);
       break;
@@ -3912,7 +3883,19 @@ MagickExport MagickBooleanType InterpolatePixelInfo(const Image *image,
           status=MagickFalse;
           break;
         }
-      SetPixelInfo(image,p,pixel);
+      *pixel=(double) p[channel];
+      break;
+    }
+    case NearestNeighborInterpolatePixel:
+    {
+      p=GetCacheViewVirtualPixels(image_view,NearestNeighbor(x),
+        NearestNeighbor(y),1,1,exception);
+      if (p == (const Quantum *) NULL)
+        {
+          status=MagickFalse;
+          break;
+        }
+      *pixel=(double) p[channel];
       break;
     }
     case MeshInterpolatePixel:
@@ -3921,23 +3904,31 @@ MagickExport MagickBooleanType InterpolatePixelInfo(const Image *image,
         delta,
         luminance;
 
-      p=GetCacheViewVirtualPixels(image_view,x_offset,y_offset,2,2,
-        exception);
+      p=GetCacheViewVirtualPixels(image_view,x_offset,y_offset,2,2,exception);
       if (p == (const Quantum *) NULL)
         {
           status=MagickFalse;
           break;
         }
-      AlphaBlendPixelInfo(image,p,pixels+0,alpha+0);
-      AlphaBlendPixelInfo(image,p+1*GetPixelChannels(image),pixels+1,alpha+1);
-      AlphaBlendPixelInfo(image,p+2*GetPixelChannels(image),pixels+2,alpha+2);
-      AlphaBlendPixelInfo(image,p+3*GetPixelChannels(image),pixels+3,alpha+3);
+      if ((traits & BlendPixelTrait) == 0)
+        for (i=0; i < 4; i++)
+        {
+          alpha[i]=1.0;
+          pixels[i]=(MagickRealType) p[i*GetPixelChannels(image)+channel];
+        }
+      else
+        for (i=0; i < 4; i++)
+        {
+          alpha[i]=QuantumScale*GetPixelAlpha(image,p+i*
+            GetPixelChannels(image));
+          pixels[i]=alpha[i]*p[i*GetPixelChannels(image)+channel];
+        }
       delta.x=x-x_offset;
       delta.y=y-y_offset;
-      luminance.x=GetPixelInfoLuminance(pixels+0)-(double)
-        GetPixelInfoLuminance(pixels+3);
-      luminance.y=GetPixelInfoLuminance(pixels+1)-(double)
-        GetPixelInfoLuminance(pixels+2);
+      luminance.x=GetPixelLuminance(image,p)-(double)
+        GetPixelLuminance(image,p+3*GetPixelChannels(image));
+      luminance.y=GetPixelLuminance(image,p+GetPixelChannels(image))-(double)
+        GetPixelLuminance(image,p+2*GetPixelChannels(image));
       if (fabs(luminance.x) < fabs(luminance.y))
         {
           /*
@@ -3946,7 +3937,959 @@ MagickExport MagickBooleanType InterpolatePixelInfo(const Image *image,
           if (delta.x <= delta.y)
             {
               /*
-                Bottom-left triangle  (pixel:2, diagonal: 0-3).
+                Bottom-left triangle (pixel: 2, diagonal: 0-3).
+              */
+              delta.y=1.0-delta.y;
+              gamma=MeshInterpolate(&delta,alpha[2],alpha[3],alpha[0]);
+              gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+              *pixel=gamma*MeshInterpolate(&delta,pixels[2],pixels[3],
+                pixels[0]);
+            }
+          else
+            {
+              /*
+                Top-right triangle (pixel: 1, diagonal: 0-3).
+              */
+              delta.x=1.0-delta.x;
+              gamma=MeshInterpolate(&delta,alpha[1],alpha[0],alpha[3]);
+              gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+              *pixel=gamma*MeshInterpolate(&delta,pixels[1],pixels[0],
+                pixels[3]);
+            }
+        }
+      else
+        {
+          /*
+            Diagonal 1-2 NE-SW.
+          */
+          if (delta.x <= (1.0-delta.y))
+            {
+              /*
+                Top-left triangle (pixel: 0, diagonal: 1-2).
+              */
+              gamma=MeshInterpolate(&delta,alpha[0],alpha[1],alpha[2]);
+              gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+              *pixel=gamma*MeshInterpolate(&delta,pixels[0],pixels[1],
+                pixels[2]);
+            }
+          else
+            {
+              /*
+                Bottom-right triangle (pixel: 3, diagonal: 1-2).
+              */
+              delta.x=1.0-delta.x;
+              delta.y=1.0-delta.y;
+              gamma=MeshInterpolate(&delta,alpha[3],alpha[2],alpha[1]);
+              gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+              *pixel=gamma*MeshInterpolate(&delta,pixels[3],pixels[2],
+                pixels[1]);
+            }
+        }
+      break;
+    }
+    case SplineInterpolatePixel:
+    {
+      MagickRealType
+        dx,
+        dy;
+
+      PointInfo
+        delta;
+
+      ssize_t
+        j,
+        n;
+
+      p=GetCacheViewVirtualPixels(image_view,x_offset-1,y_offset-1,4,4,
+        exception);
+      if (p == (const Quantum *) NULL)
+        {
+          status=MagickFalse;
+          break;
+        }
+      if ((traits & BlendPixelTrait) == 0)
+        for (i=0; i < 16; i++)
+        {
+          alpha[i]=1.0;
+          pixels[i]=(MagickRealType) p[i*GetPixelChannels(image)+channel];
+        }
+      else
+        for (i=0; i < 16; i++)
+        {
+          alpha[i]=QuantumScale*GetPixelAlpha(image,p+i*
+            GetPixelChannels(image));
+          pixels[i]=alpha[i]*p[i*GetPixelChannels(image)+channel];
+        }
+      delta.x=x-x_offset;
+      delta.y=y-y_offset;
+      n=0;
+      for (i=(-1); i < 3L; i++)
+      {
+        dy=CubicWeightingFunction((MagickRealType) i-delta.y);
+        for (j=(-1); j < 3L; j++)
+        {
+          dx=CubicWeightingFunction(delta.x-(MagickRealType) j);
+          gamma=1.0/(fabs((double) alpha[n]) <= MagickEpsilon ? 1.0 : alpha[n]);
+          *pixel+=gamma*dx*dy*pixels[n];
+          n++;
+        }
+      }
+      break;
+    }
+  }
+  return(status);
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   I n t e r p o l a t e P i x e l C h a n n e l s                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  InterpolatePixelChannels() applies a pixel interpolation method between a
+%  floating point coordinate and the pixels surrounding that coordinate.  No
+%  pixel area resampling, or scaling of the result is performed.
+%
+%  The format of the InterpolatePixelChannels method is:
+%
+%      MagickBooleanType InterpolatePixelChannels(const Image *source,
+%        const CacheView *source_view,const Image *destination,
+%        const PixelInterpolateMethod method,const double x,const double y,
+%        Quantum *pixel,ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o source: the source.
+%
+%    o source_view: the source view.
+%
+%    o destination: the destination image.
+%
+%    o method: the pixel color interpolation method.
+%
+%    o x,y: A double representing the current (x,y) position of the pixel.
+%
+%    o pixel: return the interpolated pixel here.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickExport MagickBooleanType InterpolatePixelChannels(const Image *source,
+  const CacheView *source_view,const Image *destination,
+  const PixelInterpolateMethod method,const double x,const double y,
+  Quantum *pixel,ExceptionInfo *exception)
+{
+  MagickBooleanType
+    status;
+
+  MagickRealType
+    alpha[16],
+    gamma,
+    pixels[16];
+
+  PixelChannel
+    channel;
+
+  PixelTrait
+    destination_traits,
+    traits;
+
+  register const Quantum
+    *p;
+
+  register ssize_t
+    i;
+
+  ssize_t
+    x_offset,
+    y_offset;
+
+  assert(source != (Image *) NULL);
+  assert(source != (Image *) NULL);
+  assert(source->signature == MagickSignature);
+  assert(source_view != (CacheView *) NULL);
+  status=MagickTrue;
+  x_offset=(ssize_t) floor(x);
+  y_offset=(ssize_t) floor(y);
+  switch (method == UndefinedInterpolatePixel ? source->interpolate : method)
+  {
+    case AverageInterpolatePixel:
+    {
+      p=GetCacheViewVirtualPixels(source_view,x_offset-1,y_offset-1,4,4,
+        exception);
+      if (p == (const Quantum *) NULL)
+        {
+          status=MagickFalse;
+          break;
+        }
+      for (i=0; i < (ssize_t) GetPixelChannels(source); i++)
+      {
+        double
+          sum;
+
+        register ssize_t
+          j;
+
+        traits=GetPixelChannelMapTraits(source,(PixelChannel) i);
+        channel=GetPixelChannelMapChannel(source,(PixelChannel) i);
+        destination_traits=GetPixelChannelMapTraits(destination,channel);
+        if ((traits == UndefinedPixelTrait) ||
+            (destination_traits == UndefinedPixelTrait))
+          continue;
+        for (j=0; j < 16; j++)
+          pixels[j]=(MagickRealType) p[j*GetPixelChannels(source)+i];
+        if ((traits & BlendPixelTrait) == 0)
+          {
+            for (j=0; j < 16; j++)
+              pixel[channel]+=0.0625*pixels[j];
+            continue;
+          }
+        sum=0.0;
+        for (j=0; j < 16; j++)
+        {
+          alpha[j]=QuantumScale*GetPixelAlpha(source,p+j*
+            GetPixelChannels(source));
+          pixels[j]*=alpha[j];
+          gamma=1.0/(fabs((double) alpha[j]) <= MagickEpsilon ? 1.0 : alpha[j]);
+          sum+=gamma*0.0625*pixels[j];
+        }
+        pixel[channel]=ClampToQuantum(sum);
+      }
+      break;
+    }
+    case BicubicInterpolatePixel:
+    {
+      MagickRealType
+        u[4],
+        v[4];
+
+      PointInfo
+        delta;
+
+      p=GetCacheViewVirtualPixels(source_view,x_offset-1,y_offset-1,4,4,
+        exception);
+      if (p == (const Quantum *) NULL)
+        {
+          status=MagickFalse;
+          break;
+        }
+      for (i=0; i < (ssize_t) GetPixelChannels(source); i++)
+      {
+        register ssize_t
+          j;
+
+        traits=GetPixelChannelMapTraits(source,(PixelChannel) i);
+        channel=GetPixelChannelMapChannel(source,(PixelChannel) i);
+        destination_traits=GetPixelChannelMapTraits(destination,channel);
+        if ((traits == UndefinedPixelTrait) ||
+            (destination_traits == UndefinedPixelTrait))
+          continue;
+        if ((traits & BlendPixelTrait) == 0)
+          for (j=0; j < 16; j++)
+          {
+            alpha[j]=1.0;
+            pixels[j]=(MagickRealType) p[j*GetPixelChannels(source)+i];
+          }
+        else
+          for (j=0; j < 16; j++)
+          {
+            alpha[j]=QuantumScale*GetPixelAlpha(source,p+j*
+              GetPixelChannels(source));
+            pixels[j]=alpha[j]*p[j*GetPixelChannels(source)+i];
+          }
+        delta.x=x-x_offset;
+        delta.y=y-y_offset;
+        for (j=0; j < 4; j++)
+        {
+          u[0]=(pixels[4*j+3]-pixels[4*j+2])-(pixels[4*j+0]-pixels[4*j+1]);
+          u[1]=(pixels[4*j+0]-pixels[4*j+1])-u[0];
+          u[2]=pixels[4*j+2]-pixels[4*j+0];
+          u[3]=pixels[4*j+1];
+          v[j]=(delta.x*delta.x*delta.x*u[0])+(delta.x*delta.x*u[1])+(delta.x*
+            u[2])+u[3];
+        }
+        u[0]=(v[3]-v[2])-(v[0]-v[1]);
+        u[1]=(v[0]-v[1])-u[0];
+        u[2]=v[2]-v[0];
+        u[3]=v[1];
+        pixel[channel]=ClampToQuantum((delta.y*delta.y*delta.y*u[0])+(delta.y*
+          delta.y*u[1])+(delta.y*u[2])+u[3]);
+      }
+      break;
+    }
+    case BilinearInterpolatePixel:
+    default:
+    {
+      p=GetCacheViewVirtualPixels(source_view,x_offset,y_offset,2,2,exception);
+      if (p == (const Quantum *) NULL)
+        {
+          status=MagickFalse;
+          break;
+        }
+      for (i=0; i < (ssize_t) GetPixelChannels(source); i++)
+      {
+        PointInfo
+          delta,
+          epsilon;
+
+        traits=GetPixelChannelMapTraits(source,(PixelChannel) i);
+        channel=GetPixelChannelMapChannel(source,(PixelChannel) i);
+        destination_traits=GetPixelChannelMapTraits(destination,channel);
+        if ((traits == UndefinedPixelTrait) ||
+            (destination_traits == UndefinedPixelTrait))
+          continue;
+        delta.x=x-x_offset;
+        delta.y=y-y_offset;
+        epsilon.x=1.0-delta.x;
+        epsilon.y=1.0-delta.y;
+        pixels[0]=(MagickRealType) p[i];
+        pixels[1]=(MagickRealType) p[GetPixelChannels(source)+i];
+        pixels[2]=(MagickRealType) p[2*GetPixelChannels(source)+i];
+        pixels[3]=(MagickRealType) p[3*GetPixelChannels(source)+i];
+        if ((traits & BlendPixelTrait) == 0)
+          {
+            gamma=((epsilon.y*(epsilon.x+delta.x)+delta.y*(epsilon.x+delta.x)));
+            gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+            pixel[channel]=ClampToQuantum(gamma*(epsilon.y*(epsilon.x*pixels[0]+
+              delta.x*pixels[1])+delta.y*(epsilon.x*pixels[2]+delta.x*
+              pixels[3])));
+            continue;
+          }
+        alpha[0]=QuantumScale*GetPixelAlpha(source,p);
+        alpha[1]=QuantumScale*GetPixelAlpha(source,p+GetPixelChannels(source));
+        alpha[2]=QuantumScale*GetPixelAlpha(source,p+2*
+          GetPixelChannels(source));
+        alpha[3]=QuantumScale*GetPixelAlpha(source,p+3*
+          GetPixelChannels(source));
+        pixels[0]*=alpha[0];
+        pixels[1]*=alpha[1];
+        pixels[2]*=alpha[2];
+        pixels[3]*=alpha[3];
+        gamma=((epsilon.y*(epsilon.x*alpha[0]+delta.x*alpha[1])+delta.y*
+          (epsilon.x*alpha[2]+delta.x*alpha[3])));
+        gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+        pixel[channel]=ClampToQuantum(gamma*(epsilon.y*(epsilon.x*pixels[0]+
+          delta.x*pixels[1])+delta.y*(epsilon.x*pixels[2]+delta.x*pixels[3])));
+      }
+      break;
+    }
+    case FilterInterpolatePixel:
+    {
+      for (i=0; i < (ssize_t) GetPixelChannels(source); i++)
+      {
+        CacheView
+          *filter_view;
+
+        Image
+          *excerpt_source,
+          *filter_source;
+
+        RectangleInfo
+          geometry;
+
+        traits=GetPixelChannelMapTraits(source,(PixelChannel) i);
+        channel=GetPixelChannelMapChannel(source,(PixelChannel) i);
+        destination_traits=GetPixelChannelMapTraits(destination,channel);
+        if ((traits == UndefinedPixelTrait) ||
+            (destination_traits == UndefinedPixelTrait))
+          continue;
+        geometry.width=4L;
+        geometry.height=4L;
+        geometry.x=x_offset-1;
+        geometry.y=y_offset-1;
+        excerpt_source=ExcerptImage(source,&geometry,exception);
+        if (excerpt_source == (Image *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        filter_source=ResizeImage(excerpt_source,1,1,source->filter,
+          source->blur,exception);
+        excerpt_source=DestroyImage(excerpt_source);
+        if (filter_source == (Image *) NULL)
+          continue;
+        filter_view=AcquireCacheView(filter_source);
+        p=GetCacheViewVirtualPixels(filter_view,0,0,1,1,exception);
+        if (p == (const Quantum *) NULL)
+          status=MagickFalse;
+        else
+          pixel[channel]=p[i];
+        filter_view=DestroyCacheView(filter_view);
+        filter_source=DestroyImage(filter_source);
+      }
+      break;
+    }
+    case IntegerInterpolatePixel:
+    {
+      p=GetCacheViewVirtualPixels(source_view,x_offset,y_offset,1,1,exception);
+      if (p == (const Quantum *) NULL)
+        {
+          status=MagickFalse;
+          break;
+        }
+      for (i=0; i < (ssize_t) GetPixelChannels(source); i++)
+      {
+        traits=GetPixelChannelMapTraits(source,(PixelChannel) i);
+        channel=GetPixelChannelMapChannel(source,(PixelChannel) i);
+        destination_traits=GetPixelChannelMapTraits(destination,channel);
+        if ((traits == UndefinedPixelTrait) ||
+            (destination_traits == UndefinedPixelTrait))
+          continue;
+        pixel[channel]=p[i];
+      }
+      break;
+    }
+    case NearestNeighborInterpolatePixel:
+    {
+      p=GetCacheViewVirtualPixels(source_view,NearestNeighbor(x),
+        NearestNeighbor(y),1,1,exception);
+      if (p == (const Quantum *) NULL)
+        {
+          status=MagickFalse;
+          break;
+        }
+      for (i=0; i < (ssize_t) GetPixelChannels(source); i++)
+      {
+        traits=GetPixelChannelMapTraits(source,(PixelChannel) i);
+        channel=GetPixelChannelMapChannel(source,(PixelChannel) i);
+        destination_traits=GetPixelChannelMapTraits(destination,channel);
+        if ((traits == UndefinedPixelTrait) ||
+            (destination_traits == UndefinedPixelTrait))
+          continue;
+        pixel[channel]=p[i];
+      }
+      break;
+    }
+    case MeshInterpolatePixel:
+    {
+      p=GetCacheViewVirtualPixels(source_view,x_offset,y_offset,2,2,exception);
+      if (p == (const Quantum *) NULL)
+        {
+          status=MagickFalse;
+          break;
+        }
+      for (i=0; i < (ssize_t) GetPixelChannels(source); i++)
+      {
+        PointInfo
+          delta,
+          luminance;
+
+        traits=GetPixelChannelMapTraits(source,(PixelChannel) i);
+        channel=GetPixelChannelMapChannel(source,(PixelChannel) i);
+        destination_traits=GetPixelChannelMapTraits(destination,channel);
+        if ((traits == UndefinedPixelTrait) ||
+            (destination_traits == UndefinedPixelTrait))
+          continue;
+       pixels[0]=(MagickRealType) p[i];
+       pixels[1]=(MagickRealType) p[GetPixelChannels(source)+i];
+       pixels[2]=(MagickRealType) p[2*GetPixelChannels(source)+i];
+       pixels[3]=(MagickRealType) p[3*GetPixelChannels(source)+i];
+       if ((traits & BlendPixelTrait) == 0)
+         {
+           alpha[0]=1.0;
+           alpha[1]=1.0;
+           alpha[2]=1.0;
+           alpha[3]=1.0;
+         }
+       else
+         {
+           alpha[0]=QuantumScale*GetPixelAlpha(source,p);
+           alpha[1]=QuantumScale*GetPixelAlpha(source,p+
+             GetPixelChannels(source));
+           alpha[2]=QuantumScale*GetPixelAlpha(source,p+2*
+             GetPixelChannels(source));
+           alpha[3]=QuantumScale*GetPixelAlpha(source,p+3*
+             GetPixelChannels(source));
+         }
+       delta.x=x-x_offset;
+       delta.y=y-y_offset;
+       luminance.x=GetPixelLuminance(source,p)-(double)
+         GetPixelLuminance(source,p+3*GetPixelChannels(source));
+       luminance.y=GetPixelLuminance(source,p+GetPixelChannels(source))-
+         (double) GetPixelLuminance(source,p+2*GetPixelChannels(source));
+       if (fabs(luminance.x) < fabs(luminance.y))
+         {
+           /*
+             Diagonal 0-3 NW-SE.
+           */
+           if (delta.x <= delta.y)
+             {
+               /*
+                 Bottom-left triangle (pixel: 2, diagonal: 0-3).
+               */
+               delta.y=1.0-delta.y;
+               gamma=MeshInterpolate(&delta,alpha[2],alpha[3],alpha[0]);
+               gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+               pixel[channel]=ClampToQuantum(gamma*MeshInterpolate(&delta,
+                 pixels[2],pixels[3],pixels[0]));
+             }
+           else
+             {
+               /*
+                 Top-right triangle (pixel: 1, diagonal: 0-3).
+               */
+               delta.x=1.0-delta.x;
+               gamma=MeshInterpolate(&delta,alpha[1],alpha[0],alpha[3]);
+               gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+               pixel[channel]=ClampToQuantum(gamma*MeshInterpolate(&delta,
+                 pixels[1],pixels[0],pixels[3]));
+             }
+         }
+       else
+         {
+           /*
+             Diagonal 1-2 NE-SW.
+           */
+           if (delta.x <= (1.0-delta.y))
+             {
+               /*
+                 Top-left triangle (pixel: 0, diagonal: 1-2).
+               */
+               gamma=MeshInterpolate(&delta,alpha[0],alpha[1],alpha[2]);
+               gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+               pixel[channel]=ClampToQuantum(gamma*MeshInterpolate(&delta,
+                 pixels[0],pixels[1],pixels[2]));
+             }
+           else
+             {
+               /*
+                 Bottom-right triangle (pixel: 3, diagonal: 1-2).
+               */
+               delta.x=1.0-delta.x;
+               delta.y=1.0-delta.y;
+               gamma=MeshInterpolate(&delta,alpha[3],alpha[2],alpha[1]);
+               gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+               pixel[channel]=ClampToQuantum(gamma*MeshInterpolate(&delta,
+                 pixels[3],pixels[2],pixels[1]));
+             }
+         }
+      }
+      break;
+    }
+    case SplineInterpolatePixel:
+    {
+      p=GetCacheViewVirtualPixels(source_view,x_offset-1,y_offset-1,4,4,
+        exception);
+      if (p == (const Quantum *) NULL)
+        {
+          status=MagickFalse;
+          break;
+        }
+      for (i=0; i < (ssize_t) GetPixelChannels(source); i++)
+      {
+        double
+          sum;
+
+        MagickRealType
+          dx,
+          dy;
+
+        PointInfo
+          delta;
+
+        register ssize_t
+          j;
+
+        ssize_t
+          k,
+          n;
+
+        traits=GetPixelChannelMapTraits(source,(PixelChannel) i);
+        channel=GetPixelChannelMapChannel(source,(PixelChannel) i);
+        destination_traits=GetPixelChannelMapTraits(destination,channel);
+        if ((traits == UndefinedPixelTrait) ||
+            (destination_traits == UndefinedPixelTrait))
+          continue;
+        if ((traits & BlendPixelTrait) == 0)
+          for (j=0; j < 16; j++)
+          {
+            alpha[j]=1.0;
+            pixels[j]=(MagickRealType) p[j*GetPixelChannels(source)+i];
+          }
+        else
+          for (j=0; j < 16; j++)
+          {
+            alpha[j]=QuantumScale*GetPixelAlpha(source,p+j*
+              GetPixelChannels(source));
+            pixels[j]=alpha[j]*p[j*GetPixelChannels(source)+i];
+          }
+        delta.x=x-x_offset;
+        delta.y=y-y_offset;
+        sum=0.0;
+        n=0;
+        for (j=(-1); j < 3L; j++)
+        {
+          dy=CubicWeightingFunction((MagickRealType) j-delta.y);
+          for (k=(-1); k < 3L; k++)
+          {
+            dx=CubicWeightingFunction(delta.x-(MagickRealType) k);
+            gamma=1.0/(fabs((double) alpha[n]) <= MagickEpsilon ? 1.0 :
+              alpha[n]);
+            sum+=gamma*dx*dy*pixels[n];
+            n++;
+          }
+        }
+        pixel[channel]=ClampToQuantum(sum);
+      }
+      break;
+    }
+  }
+  return(status);
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   I n t e r p o l a t e P i x e l I n f o                                   %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  InterpolatePixelInfo() applies a pixel interpolation method between a
+%  floating point coordinate and the pixels surrounding that coordinate.  No
+%  pixel area resampling, or scaling of the result is performed.
+%
+%  The format of the InterpolatePixelInfo method is:
+%
+%      MagickBooleanType InterpolatePixelInfo(const Image *image,
+%        const CacheView *image_view,const PixelInterpolateMethod method,
+%        const double x,const double y,PixelInfo *pixel,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o image_view: the image view.
+%
+%    o method: the pixel color interpolation method.
+%
+%    o x,y: A double representing the current (x,y) position of the pixel.
+%
+%    o pixel: return the interpolated pixel here.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+
+static inline void AlphaBlendPixelInfo(const Image *image,
+  const Quantum *pixel,PixelInfo *pixel_info,MagickRealType *alpha)
+{
+  if (image->matte == MagickFalse)
+    {
+      *alpha=1.0;
+      pixel_info->red=(MagickRealType) GetPixelRed(image,pixel);
+      pixel_info->green=(MagickRealType) GetPixelGreen(image,pixel);
+      pixel_info->blue=(MagickRealType) GetPixelBlue(image,pixel);
+      pixel_info->black=0.0;
+      if (image->colorspace == CMYKColorspace)
+        pixel_info->black=(MagickRealType) GetPixelBlack(image,pixel);
+      pixel_info->alpha=(MagickRealType) GetPixelAlpha(image,pixel);
+      return;
+    }
+  *alpha=QuantumScale*GetPixelAlpha(image,pixel);
+  pixel_info->red=(*alpha*GetPixelRed(image,pixel));
+  pixel_info->green=(*alpha*GetPixelGreen(image,pixel));
+  pixel_info->blue=(*alpha*GetPixelBlue(image,pixel));
+  pixel_info->black=0.0;
+  if (image->colorspace == CMYKColorspace)
+    pixel_info->black=(*alpha*GetPixelBlack(image,pixel));
+  pixel_info->alpha=(MagickRealType) GetPixelAlpha(image,pixel);
+}
+
+static void BicubicInterpolate(const PixelInfo *pixels,const double dx,
+  PixelInfo *pixel)
+{
+  MagickRealType
+    dx2,
+    p,
+    q,
+    r,
+    s;
+
+  dx2=dx*dx;
+  p=(pixels[3].red-pixels[2].red)-(pixels[0].red-pixels[1].red);
+  q=(pixels[0].red-pixels[1].red)-p;
+  r=pixels[2].red-pixels[0].red;
+  s=pixels[1].red;
+  pixel->red=(dx*dx2*p)+(dx2*q)+(dx*r)+s;
+  p=(pixels[3].green-pixels[2].green)-(pixels[0].green-pixels[1].green);
+  q=(pixels[0].green-pixels[1].green)-p;
+  r=pixels[2].green-pixels[0].green;
+  s=pixels[1].green;
+  pixel->green=(dx*dx2*p)+(dx2*q)+(dx*r)+s;
+  p=(pixels[3].blue-pixels[2].blue)-(pixels[0].blue-pixels[1].blue);
+  q=(pixels[0].blue-pixels[1].blue)-p;
+  r=pixels[2].blue-pixels[0].blue;
+  s=pixels[1].blue;
+  pixel->blue=(dx*dx2*p)+(dx2*q)+(dx*r)+s;
+  p=(pixels[3].alpha-pixels[2].alpha)-(pixels[0].alpha-pixels[1].alpha);
+  q=(pixels[0].alpha-pixels[1].alpha)-p;
+  r=pixels[2].alpha-pixels[0].alpha;
+  s=pixels[1].alpha;
+  pixel->alpha=(dx*dx2*p)+(dx2*q)+(dx*r)+s;
+  if (pixel->colorspace == CMYKColorspace)
+    {
+      p=(pixels[3].black-pixels[2].black)-(pixels[0].black-pixels[1].black);
+      q=(pixels[0].black-pixels[1].black)-p;
+      r=pixels[2].black-pixels[0].black;
+      s=pixels[1].black;
+      pixel->black=(dx*dx2*p)+(dx2*q)+(dx*r)+s;
+    }
+}
+
+MagickExport MagickBooleanType InterpolatePixelInfo(const Image *image,
+  const CacheView *image_view,const PixelInterpolateMethod method,
+  const double x,const double y,PixelInfo *pixel,ExceptionInfo *exception)
+{
+  MagickBooleanType
+    status;
+
+  MagickRealType
+    alpha[16],
+    gamma;
+
+  PixelInfo
+    pixels[16];
+
+  register const Quantum
+    *p;
+
+  register ssize_t
+    i;
+
+  ssize_t
+    x_offset,
+    y_offset;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  assert(image_view != (CacheView *) NULL);
+  status=MagickTrue;
+  x_offset=(ssize_t) floor(x);
+  y_offset=(ssize_t) floor(y);
+  switch (method == UndefinedInterpolatePixel ? image->interpolate : method)
+  {
+    case AverageInterpolatePixel:
+    {
+      p=GetCacheViewVirtualPixels(image_view,x_offset-1,y_offset-1,4,4,
+        exception);
+      if (p == (const Quantum *) NULL)
+        {
+          status=MagickFalse;
+          break;
+        }
+      AlphaBlendPixelInfo(image,p,pixels+0,alpha+0);
+      AlphaBlendPixelInfo(image,p+GetPixelChannels(image),pixels+1,alpha+1);
+      AlphaBlendPixelInfo(image,p+2*GetPixelChannels(image),pixels+2,alpha+2);
+      AlphaBlendPixelInfo(image,p+3*GetPixelChannels(image),pixels+3,alpha+3);
+      AlphaBlendPixelInfo(image,p+4*GetPixelChannels(image),pixels+4,alpha+4);
+      AlphaBlendPixelInfo(image,p+5*GetPixelChannels(image),pixels+5,alpha+5);
+      AlphaBlendPixelInfo(image,p+6*GetPixelChannels(image),pixels+6,alpha+6);
+      AlphaBlendPixelInfo(image,p+7*GetPixelChannels(image),pixels+7,alpha+7);
+      AlphaBlendPixelInfo(image,p+8*GetPixelChannels(image),pixels+8,alpha+8);
+      AlphaBlendPixelInfo(image,p+9*GetPixelChannels(image),pixels+9,alpha+9);
+      AlphaBlendPixelInfo(image,p+10*GetPixelChannels(image),pixels+10,alpha+
+        10);
+      AlphaBlendPixelInfo(image,p+11*GetPixelChannels(image),pixels+11,alpha+
+        11);
+      AlphaBlendPixelInfo(image,p+12*GetPixelChannels(image),pixels+12,alpha+
+        12);
+      AlphaBlendPixelInfo(image,p+13*GetPixelChannels(image),pixels+13,alpha+
+        13);
+      AlphaBlendPixelInfo(image,p+14*GetPixelChannels(image),pixels+14,alpha+
+        14);
+      AlphaBlendPixelInfo(image,p+15*GetPixelChannels(image),pixels+15,alpha+
+        15);
+      pixel->red=0.0;
+      pixel->green=0.0;
+      pixel->blue=0.0;
+      pixel->black=0.0;
+      pixel->alpha=0.0;
+      for (i=0; i < 16L; i++)
+      {
+        gamma=1.0/(fabs((double) alpha[i]) <= MagickEpsilon ? 1.0 : alpha[i]);
+        pixel->red+=gamma*0.0625*pixels[i].red;
+        pixel->green+=gamma*0.0625*pixels[i].green;
+        pixel->blue+=gamma*0.0625*pixels[i].blue;
+        if (image->colorspace == CMYKColorspace)
+          pixel->black+=gamma*0.0625*pixels[i].black;
+        pixel->alpha+=0.0625*pixels[i].alpha;
+      }
+      break;
+    }
+    case BicubicInterpolatePixel:
+    {
+      PixelInfo
+        u[4];
+
+      PointInfo
+        delta;
+
+      p=GetCacheViewVirtualPixels(image_view,x_offset-1,y_offset-1,4,4,
+        exception);
+      if (p == (const Quantum *) NULL)
+        {
+          status=MagickFalse;
+          break;
+        }
+      AlphaBlendPixelInfo(image,p,pixels+0,alpha+0);
+      AlphaBlendPixelInfo(image,p+GetPixelChannels(image),pixels+1,alpha+1);
+      AlphaBlendPixelInfo(image,p+2*GetPixelChannels(image),pixels+2,alpha+2);
+      AlphaBlendPixelInfo(image,p+3*GetPixelChannels(image),pixels+3,alpha+3);
+      AlphaBlendPixelInfo(image,p+4*GetPixelChannels(image),pixels+4,alpha+4);
+      AlphaBlendPixelInfo(image,p+5*GetPixelChannels(image),pixels+5,alpha+5);
+      AlphaBlendPixelInfo(image,p+6*GetPixelChannels(image),pixels+6,alpha+6);
+      AlphaBlendPixelInfo(image,p+7*GetPixelChannels(image),pixels+7,alpha+7);
+      AlphaBlendPixelInfo(image,p+8*GetPixelChannels(image),pixels+8,alpha+8);
+      AlphaBlendPixelInfo(image,p+9*GetPixelChannels(image),pixels+9,alpha+9);
+      AlphaBlendPixelInfo(image,p+10*GetPixelChannels(image),pixels+10,alpha+
+        10);
+      AlphaBlendPixelInfo(image,p+11*GetPixelChannels(image),pixels+11,alpha+
+        11);
+      AlphaBlendPixelInfo(image,p+12*GetPixelChannels(image),pixels+12,alpha+
+        12);
+      AlphaBlendPixelInfo(image,p+13*GetPixelChannels(image),pixels+13,alpha+
+        13);
+      AlphaBlendPixelInfo(image,p+14*GetPixelChannels(image),pixels+14,alpha+
+        14);
+      AlphaBlendPixelInfo(image,p+15*GetPixelChannels(image),pixels+15,alpha+
+        15);
+      delta.x=x-x_offset;
+      delta.y=y-y_offset;
+      for (i=0; i < 4L; i++)
+        BicubicInterpolate(pixels+4*i,delta.x,u+i);
+      BicubicInterpolate(u,delta.y,pixel);
+      break;
+    }
+    case BilinearInterpolatePixel:
+    default:
+    {
+      PointInfo
+        delta,
+        epsilon;
+
+      p=GetCacheViewVirtualPixels(image_view,x_offset,y_offset,2,2,exception);
+      if (p == (const Quantum *) NULL)
+        {
+          status=MagickFalse;
+          break;
+        }
+      AlphaBlendPixelInfo(image,p,pixels+0,alpha+0);
+      AlphaBlendPixelInfo(image,p+GetPixelChannels(image),pixels+1,alpha+1);
+      AlphaBlendPixelInfo(image,p+2*GetPixelChannels(image),pixels+2,alpha+2);
+      AlphaBlendPixelInfo(image,p+3*GetPixelChannels(image),pixels+3,alpha+3);
+      delta.x=x-x_offset;
+      delta.y=y-y_offset;
+      epsilon.x=1.0-delta.x;
+      epsilon.y=1.0-delta.y;
+      gamma=((epsilon.y*(epsilon.x*alpha[0]+delta.x*alpha[1])+delta.y*
+        (epsilon.x*alpha[2]+delta.x*alpha[3])));
+      gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+      pixel->red=gamma*(epsilon.y*(epsilon.x*pixels[0].red+delta.x*
+        pixels[1].red)+delta.y*(epsilon.x*pixels[2].red+delta.x*pixels[3].red));
+      pixel->green=gamma*(epsilon.y*(epsilon.x*pixels[0].green+delta.x*
+        pixels[1].green)+delta.y*(epsilon.x*pixels[2].green+delta.x*
+        pixels[3].green));
+      pixel->blue=gamma*(epsilon.y*(epsilon.x*pixels[0].blue+delta.x*
+        pixels[1].blue)+delta.y*(epsilon.x*pixels[2].blue+delta.x*
+        pixels[3].blue));
+      if (image->colorspace == CMYKColorspace)
+        pixel->black=gamma*(epsilon.y*(epsilon.x*pixels[0].black+delta.x*
+          pixels[1].black)+delta.y*(epsilon.x*pixels[2].black+delta.x*
+          pixels[3].black));
+      gamma=((epsilon.y*(epsilon.x+delta.x)+delta.y*(epsilon.x+delta.x)));
+      gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
+      pixel->alpha=(epsilon.y*(epsilon.x*pixels[0].alpha+delta.x*
+        pixels[1].alpha)+delta.y*(epsilon.x*pixels[2].alpha+delta.x*
+        pixels[3].alpha));
+      break;
+    }
+    case FilterInterpolatePixel:
+    {
+      CacheView
+        *filter_view;
+
+      Image
+        *excerpt_image,
+        *filter_image;
+
+      RectangleInfo
+        geometry;
+
+      geometry.width=4L;
+      geometry.height=4L;
+      geometry.x=x_offset-1;
+      geometry.y=y_offset-1;
+      excerpt_image=ExcerptImage(image,&geometry,exception);
+      if (excerpt_image == (Image *) NULL)
+        {
+          status=MagickFalse;
+          break;
+        }
+      filter_image=ResizeImage(excerpt_image,1,1,image->filter,image->blur,
+        exception);
+      excerpt_image=DestroyImage(excerpt_image);
+      if (filter_image == (Image *) NULL)
+        break;
+      filter_view=AcquireCacheView(filter_image);
+      p=GetCacheViewVirtualPixels(filter_view,0,0,1,1,exception);
+      if (p != (const Quantum *) NULL)
+        SetPixelInfo(image,p,pixel);
+      filter_view=DestroyCacheView(filter_view);
+      filter_image=DestroyImage(filter_image);
+      break;
+    }
+    case IntegerInterpolatePixel:
+    {
+      p=GetCacheViewVirtualPixels(image_view,x_offset,y_offset,1,1,exception);
+      if (p == (const Quantum *) NULL)
+        {
+          status=MagickFalse;
+          break;
+        }
+      SetPixelInfo(image,p,pixel);
+      break;
+    }
+    case MeshInterpolatePixel:
+    {
+      PointInfo
+        delta,
+        luminance;
+
+      p=GetCacheViewVirtualPixels(image_view,x_offset,y_offset,2,2,exception);
+      if (p == (const Quantum *) NULL)
+        {
+          status=MagickFalse;
+          break;
+        }
+      delta.x=x-x_offset;
+      delta.y=y-y_offset;
+      luminance.x=GetPixelLuminance(image,p)-(double)
+        GetPixelLuminance(image,p+3*GetPixelChannels(image));
+      luminance.y=GetPixelLuminance(image,p+GetPixelChannels(image))-(double)
+        GetPixelLuminance(image,p+2*GetPixelChannels(image));
+      AlphaBlendPixelInfo(image,p,pixels+0,alpha+0);
+      AlphaBlendPixelInfo(image,p+GetPixelChannels(image),pixels+1,alpha+1);
+      AlphaBlendPixelInfo(image,p+2*GetPixelChannels(image),pixels+2,alpha+2);
+      AlphaBlendPixelInfo(image,p+3*GetPixelChannels(image),pixels+3,alpha+3);
+      if (fabs(luminance.x) < fabs(luminance.y))
+        {
+          /*
+            Diagonal 0-3 NW-SE.
+          */
+          if (delta.x <= delta.y)
+            {
+              /*
+                Bottom-left triangle (pixel: 2, diagonal: 0-3).
               */
               delta.y=1.0-delta.y;
               gamma=MeshInterpolate(&delta,alpha[2],alpha[3],alpha[0]);
@@ -3960,13 +4903,14 @@ MagickExport MagickBooleanType InterpolatePixelInfo(const Image *image,
               if (image->colorspace == CMYKColorspace)
                 pixel->black=gamma*MeshInterpolate(&delta,pixels[2].black,
                   pixels[3].black,pixels[0].black);
+              gamma=MeshInterpolate(&delta,1.0,1.0,1.0);
               pixel->alpha=gamma*MeshInterpolate(&delta,pixels[2].alpha,
                 pixels[3].alpha,pixels[0].alpha);
             }
           else
             {
               /*
-                Top-right triangle (pixel:1, diagonal: 0-3).
+                Top-right triangle (pixel:1 , diagonal: 0-3).
               */
               delta.x=1.0-delta.x;
               gamma=MeshInterpolate(&delta,alpha[1],alpha[0],alpha[3]);
@@ -3980,6 +4924,7 @@ MagickExport MagickBooleanType InterpolatePixelInfo(const Image *image,
               if (image->colorspace == CMYKColorspace)
                 pixel->black=gamma*MeshInterpolate(&delta,pixels[1].black,
                   pixels[0].black,pixels[3].black);
+              gamma=MeshInterpolate(&delta,1.0,1.0,1.0);
               pixel->alpha=gamma*MeshInterpolate(&delta,pixels[1].alpha,
                 pixels[0].alpha,pixels[3].alpha);
             }
@@ -3992,7 +4937,7 @@ MagickExport MagickBooleanType InterpolatePixelInfo(const Image *image,
           if (delta.x <= (1.0-delta.y))
             {
               /*
-                Top-left triangle (pixel 0, diagonal: 1-2).
+                Top-left triangle (pixel: 0, diagonal: 1-2).
               */
               gamma=MeshInterpolate(&delta,alpha[0],alpha[1],alpha[2]);
               gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
@@ -4005,6 +4950,7 @@ MagickExport MagickBooleanType InterpolatePixelInfo(const Image *image,
               if (image->colorspace == CMYKColorspace)
                 pixel->black=gamma*MeshInterpolate(&delta,pixels[0].black,
                   pixels[1].black,pixels[2].black);
+              gamma=MeshInterpolate(&delta,1.0,1.0,1.0);
               pixel->alpha=gamma*MeshInterpolate(&delta,pixels[0].alpha,
                 pixels[1].alpha,pixels[2].alpha);
             }
@@ -4026,6 +4972,7 @@ MagickExport MagickBooleanType InterpolatePixelInfo(const Image *image,
               if (image->colorspace == CMYKColorspace)
                 pixel->black=gamma*MeshInterpolate(&delta,pixels[3].black,
                   pixels[2].black,pixels[1].black);
+              gamma=MeshInterpolate(&delta,1.0,1.0,1.0);
               pixel->alpha=gamma*MeshInterpolate(&delta,pixels[3].alpha,
                 pixels[2].alpha,pixels[1].alpha);
             }
@@ -4065,7 +5012,7 @@ MagickExport MagickBooleanType InterpolatePixelInfo(const Image *image,
           break;
         }
       AlphaBlendPixelInfo(image,p,pixels+0,alpha+0);
-      AlphaBlendPixelInfo(image,p+1*GetPixelChannels(image),pixels+1,alpha+1);
+      AlphaBlendPixelInfo(image,p+GetPixelChannels(image),pixels+1,alpha+1);
       AlphaBlendPixelInfo(image,p+2*GetPixelChannels(image),pixels+2,alpha+2);
       AlphaBlendPixelInfo(image,p+3*GetPixelChannels(image),pixels+3,alpha+3);
       AlphaBlendPixelInfo(image,p+4*GetPixelChannels(image),pixels+4,alpha+4);
@@ -4447,69 +5394,6 @@ MagickExport MagickBooleanType IsFuzzyEquivalencePixelPacket(const Image *image,
 %                                                                             %
 %                                                                             %
 %                                                                             %
-%   P o p P i x e l C h a n n e l M a p                                       %
-%                                                                             %
-%                                                                             %
-%                                                                             %
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%
-%  PopPixelChannelMap() pops the pixel component map.
-%
-%  The format of the PopPixelChannelMap method is:
-%
-%      void PopPixelChannelMap(Image *image)
-%
-%  A description of each parameter follows:
-%
-%    o image: the image.
-%
-*/
-MagickExport void PopPixelChannelMap(Image *image)
-{
-  image->map--;
-  if (image->map < 0)
-    ThrowFatalException(ResourceLimitFatalError,"PixelChannelMapStack");
-}
-\f
-/*
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%                                                                             %
-%                                                                             %
-%                                                                             %
-%   P u s h P i x e l C h a n n e l M a p                                     %
-%                                                                             %
-%                                                                             %
-%                                                                             %
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%
-%  PushPixelChannelMap() pushes the pixel channel map from the specified
-%  channel mask.
-%
-%  The format of the PushPixelChannelMap method is:
-%
-%      void PushPixelChannelMap(Image *image,const ChannelType channel_mask)
-%
-%  A description of each parameter follows:
-%
-%    o image: the image.
-%
-%    o channel_mask: the channel mask.
-%
-*/
-MagickExport void PushPixelChannelMap(Image *image,
-  const ChannelType channel_mask)
-{
-  image->map++;
-  if (image->map >= MaxPixelChannelMaps)
-    ThrowFatalException(ResourceLimitFatalError,"PixelChannelMapStack");
-  SetPixelChannelMap(image,channel_mask);
-}
-\f
-/*
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%                                                                             %
-%                                                                             %
-%                                                                             %
 %   S e t P i x e l C h a n n e l M a p                                       %
 %                                                                             %
 %                                                                             %
@@ -4527,22 +5411,25 @@ MagickExport void PushPixelChannelMap(Image *image,
 %
 %    o image: the image.
 %
-%    o channel_mask: the channel mask.
+%    o mask: the channel mask.
 %
 */
 MagickExport void SetPixelChannelMap(Image *image,
   const ChannelType channel_mask)
 {
-#define GetChannelBit(alpha,i)  (((size_t) (alpha) >> (size_t) (i)) & 0x01)
+#define GetChannelBit(mask,bit)  (((size_t) (mask) >> (size_t) (bit)) & 0x01)
 
   register ssize_t
     i;
 
+  image->sync=channel_mask == DefaultChannels ? MagickTrue : MagickFalse;
   for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
     SetPixelChannelMapTraits(image,(PixelChannel) i,
-      GetChannelBit(channel_mask,i) ? UpdatePixelTrait : CopyPixelTrait);
+      GetChannelBit(channel_mask,i) != 0 ? UpdatePixelTrait : CopyPixelTrait);
   for ( ; i < MaxPixelChannels; i++)
     SetPixelChannelMapTraits(image,(PixelChannel) i,UndefinedPixelTrait);
+  if (image->storage_class == PseudoClass)
+    SetPixelChannelMapTraits(image,IndexPixelChannel,CopyPixelTrait);
 }
 \f
 /*
@@ -4550,60 +5437,35 @@ MagickExport void SetPixelChannelMap(Image *image,
 %                                                                             %
 %                                                                             %
 %                                                                             %
-+   S t a n d a r d P i x e l C h a n n e l M a p                             %
+%   S e t P i x e l C h a n n e l M a s k                                     %
 %                                                                             %
 %                                                                             %
 %                                                                             %
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
-%  StandardPixelChannelMap() defines the standard pixel component map.
+%  SetPixelChannelMask() sets the pixel channel mask from the specified
+%  channel mask.
 %
-%  The format of the StandardPixelChannelMap() method is:
+%  The format of the SetPixelChannelMask method is:
 %
-%      void StandardPixelChannelMap(Image *image)
+%      ChannelType SetPixelChannelMask(Image *image,
+%        const ChannelType channel_mask)
 %
 %  A description of each parameter follows:
 %
 %    o image: the image.
 %
+%    o channel_mask: the channel mask.
+%
 */
-MagickExport void StandardPixelChannelMap(Image *image)
+MagickExport ChannelType SetPixelChannelMask(Image *image,
+  const ChannelType channel_mask)
 {
-  register ssize_t
-    i;
+  ChannelType
+    mask;
 
-  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
-    SetPixelChannelMapTraits(image,(PixelChannel) i,UndefinedPixelTrait);
-  image->number_channels=4;
-  SetPixelChannelMapComponent(image,RedPixelChannel,RedPixelChannel);
-  SetPixelChannelMapTraits(image,RedPixelChannel,(PixelTrait)
-    (UpdatePixelTrait | BlendPixelTrait));
-  SetPixelChannelMapComponent(image,GreenPixelChannel,GreenPixelChannel);
-  SetPixelChannelMapTraits(image,GreenPixelChannel,(PixelTrait)
-    (UpdatePixelTrait | BlendPixelTrait));
-  SetPixelChannelMapComponent(image,BluePixelChannel,BluePixelChannel);
-  SetPixelChannelMapTraits(image,BluePixelChannel,(PixelTrait)
-    (UpdatePixelTrait | BlendPixelTrait));
-  SetPixelChannelMapComponent(image,AlphaPixelChannel,AlphaPixelChannel);
-  SetPixelChannelMapTraits(image,AlphaPixelChannel,UpdatePixelTrait);
-  if (0 && image->colorspace == GRAYColorspace)
-    {
-      image->number_channels=2;
-      SetPixelChannelMapComponent(image,GreenPixelChannel,RedPixelChannel);
-      SetPixelChannelMapComponent(image,BluePixelChannel,RedPixelChannel);
-    }
-  if (image->colorspace == CMYKColorspace)
-    {
-      image->number_channels++;
-      SetPixelChannelMapComponent(image,BlackPixelChannel,BlackPixelChannel);
-      SetPixelChannelMapTraits(image,BlackPixelChannel,(PixelTrait)
-        (UpdatePixelTrait | BlendPixelTrait));
-    }
-  if (image->storage_class == PseudoClass)
-    {
-      image->number_channels++;
-      SetPixelChannelMapComponent(image,IndexPixelChannel,IndexPixelChannel);
-      SetPixelChannelMapTraits(image,IndexPixelChannel,CopyPixelTrait);
-    }
-  image->number_channels+=image->number_meta_channels;
+  mask=image->channel_mask;
+  image->channel_mask=channel_mask;
+  SetPixelChannelMap(image,channel_mask);
+  return(mask);
 }