]> granicus.if.org Git - imagemagick/blobdiff - MagickCore/cache.c
(no commit message)
[imagemagick] / MagickCore / cache.c
index 8e8c2d5fa5cd5f32ff9c1aaafd65822f668bec46..59b3f3d12f705ede390ee38317df159697634942 100644 (file)
@@ -17,7 +17,7 @@
 %                                 July 1999                                   %
 %                                                                             %
 %                                                                             %
-%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  Copyright 1999-2012 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  %
@@ -54,6 +54,7 @@
 #include "MagickCore/log.h"
 #include "MagickCore/magick.h"
 #include "MagickCore/memory_.h"
+#include "MagickCore/nt-base-private.h"
 #include "MagickCore/pixel.h"
 #include "MagickCore/pixel-accessor.h"
 #include "MagickCore/policy.h"
@@ -66,6 +67,7 @@
 #include "MagickCore/string-private.h"
 #include "MagickCore/thread-private.h"
 #include "MagickCore/utility.h"
+#include "MagickCore/utility-private.h"
 #if defined(MAGICKCORE_ZLIB_DELEGATE)
 #include "zlib.h"
 #endif
@@ -74,6 +76,8 @@
   Define declarations.
 */
 #define CacheTick(offset,extent)  QuantumTick((MagickOffsetType) offset,extent)
+#define IsFileDescriptorLimitExceeded() (GetMagickResource(FileResource) > \
+  GetMagickResourceLimit(FileResource) ? MagickTrue : MagickFalse)
 \f
 /*
   Typedef declarations.
@@ -114,6 +118,10 @@ struct _NexusInfo
 extern "C" {
 #endif
 
+static Cache
+  GetImagePixelCache(Image *,const MagickBooleanType,ExceptionInfo *)
+    magick_hot_spot;
+
 static const Quantum
   *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
     const ssize_t,const size_t,const size_t,ExceptionInfo *),
@@ -124,9 +132,9 @@ static const void
 
 static MagickBooleanType
   GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,
-    PixelPacket *,ExceptionInfo *),
+    Quantum *,ExceptionInfo *),
   GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
-    const ssize_t,const ssize_t,PixelPacket *,ExceptionInfo *),
+    const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
   OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
   ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
   ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
@@ -140,7 +148,7 @@ static Quantum
   *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
     const size_t,ExceptionInfo *),
   *SetPixelCacheNexusPixels(const Image *,const RectangleInfo *,NexusInfo *,
-    ExceptionInfo *);
+    ExceptionInfo *) magick_hot_spot;
 
 #if defined(__cplusplus) || defined(c_plusplus)
 }
@@ -154,9 +162,6 @@ static volatile MagickBooleanType
 
 static SemaphoreInfo
   *cache_semaphore = (SemaphoreInfo *) NULL;
-
-static SplayTreeInfo
-  *cache_resources = (SplayTreeInfo *) NULL;
 \f
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -180,12 +185,12 @@ static SplayTreeInfo
 %    o number_threads: the number of nexus threads.
 %
 */
-MagickExport Cache AcquirePixelCache(const size_t number_threads)
+MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
 {
   CacheInfo
     *cache_info;
 
-  cache_info=(CacheInfo *) AcquireMagickMemory(sizeof(*cache_info));
+  cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
   if (cache_info == (CacheInfo *) NULL)
     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
   (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
@@ -205,22 +210,6 @@ MagickExport Cache AcquirePixelCache(const size_t number_threads)
   cache_info->disk_semaphore=AllocateSemaphoreInfo();
   cache_info->debug=IsEventLogging();
   cache_info->signature=MagickSignature;
-  if ((cache_resources == (SplayTreeInfo *) NULL) &&
-      (instantiate_cache == MagickFalse))
-    {
-      if (cache_semaphore == (SemaphoreInfo *) NULL)
-        AcquireSemaphoreInfo(&cache_semaphore);
-      LockSemaphoreInfo(cache_semaphore);
-      if ((cache_resources == (SplayTreeInfo *) NULL) &&
-          (instantiate_cache == MagickFalse))
-        {
-          cache_resources=NewSplayTree((int (*)(const void *,const void *))
-            NULL,(void *(*)(void *)) NULL,(void *(*)(void *)) NULL);
-          instantiate_cache=MagickTrue;
-        }
-      UnlockSemaphoreInfo(cache_semaphore);
-    }
-  (void) AddValueToSplayTree(cache_resources,cache_info,cache_info);
   return((Cache ) cache_info);
 }
 \f
@@ -246,7 +235,7 @@ MagickExport Cache AcquirePixelCache(const size_t number_threads)
 %    o number_threads: the number of nexus threads.
 %
 */
-MagickExport NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
+MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
 {
   NexusInfo
     **nexus_info;
@@ -254,16 +243,18 @@ MagickExport NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
   register ssize_t
     i;
 
-  nexus_info=(NexusInfo **) AcquireQuantumMemory(number_threads,
+  nexus_info=(NexusInfo **) AcquireAlignedMemory(number_threads,
     sizeof(*nexus_info));
   if (nexus_info == (NexusInfo **) NULL)
     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  nexus_info[0]=(NexusInfo *) AcquireQuantumMemory(number_threads,
+    sizeof(**nexus_info));
+  if (nexus_info[0] == (NexusInfo *) NULL)
+    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+  (void) ResetMagickMemory(nexus_info[0],0,number_threads*sizeof(**nexus_info));
   for (i=0; i < (ssize_t) number_threads; i++)
   {
-    nexus_info[i]=(NexusInfo *) AcquireAlignedMemory(1,sizeof(**nexus_info));
-    if (nexus_info[i] == (NexusInfo *) NULL)
-      ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
-    (void) ResetMagickMemory(nexus_info[i],0,sizeof(*nexus_info[i]));
+    nexus_info[i]=(&nexus_info[0][i]);
     nexus_info[i]->signature=MagickSignature;
   }
   return(nexus_info);
@@ -297,7 +288,7 @@ MagickExport NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
 %    o exception: return any errors or warnings in this structure.
 %
 */
-MagickExport const void *AcquirePixelCachePixels(const Image *image,
+MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
   MagickSizeType *length,ExceptionInfo *exception)
 {
   CacheInfo
@@ -335,7 +326,7 @@ MagickExport const void *AcquirePixelCachePixels(const Image *image,
 %      MagickBooleanType CacheComponentGenesis(void)
 %
 */
-MagickExport MagickBooleanType CacheComponentGenesis(void)
+MagickPrivate MagickBooleanType CacheComponentGenesis(void)
 {
   AcquireSemaphoreInfo(&cache_semaphore);
   return(MagickTrue);
@@ -359,13 +350,11 @@ MagickExport MagickBooleanType CacheComponentGenesis(void)
 %      CacheComponentTerminus(void)
 %
 */
-MagickExport void CacheComponentTerminus(void)
+MagickPrivate void CacheComponentTerminus(void)
 {
   if (cache_semaphore == (SemaphoreInfo *) NULL)
     AcquireSemaphoreInfo(&cache_semaphore);
   LockSemaphoreInfo(cache_semaphore);
-  if (cache_resources != (SplayTreeInfo *) NULL)
-    cache_resources=DestroySplayTree(cache_resources);
   instantiate_cache=MagickFalse;
   UnlockSemaphoreInfo(cache_semaphore);
   DestroySemaphoreInfo(&cache_semaphore);
@@ -376,106 +365,6 @@ MagickExport void CacheComponentTerminus(void)
 %                                                                             %
 %                                                                             %
 %                                                                             %
-+   C l i p P i x e l C a c h e N e x u s                                     %
-%                                                                             %
-%                                                                             %
-%                                                                             %
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%
-%  ClipPixelCacheNexus() clips the cache nexus as defined by the image clip
-%  mask.  It returns MagickTrue if the pixel region is clipped, otherwise
-%  MagickFalse.
-%
-%  The format of the ClipPixelCacheNexus() method is:
-%
-%      MagickBooleanType ClipPixelCacheNexus(Image *image,NexusInfo *nexus_info,
-%        ExceptionInfo *exception)
-%
-%  A description of each parameter follows:
-%
-%    o image: the image.
-%
-%    o nexus_info: the cache nexus to clip.
-%
-%    o exception: return any errors or warnings in this structure.
-%
-*/
-static MagickBooleanType ClipPixelCacheNexus(Image *image,
-  NexusInfo *nexus_info,ExceptionInfo *exception)
-{
-  CacheInfo
-    *cache_info;
-
-  MagickSizeType
-    number_pixels;
-
-  NexusInfo
-    **clip_nexus,
-    **image_nexus;
-
-  register const Quantum
-    *restrict p,
-    *restrict r;
-
-  register Quantum
-    *restrict q;
-
-  register ssize_t
-    i;
-
-  /*
-    Apply clip mask.
-  */
-  if (image->debug != MagickFalse)
-    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
-  if (image->clip_mask == (Image *) NULL)
-    return(MagickFalse);
-  cache_info=(CacheInfo *) image->cache;
-  if (cache_info == (Cache) NULL)
-    return(MagickFalse);
-  image_nexus=AcquirePixelCacheNexus(1);
-  clip_nexus=AcquirePixelCacheNexus(1);
-  if ((image_nexus == (NexusInfo **) NULL) ||
-      (clip_nexus == (NexusInfo **) NULL))
-    ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
-  p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
-    nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
-    nexus_info->region.height,image_nexus[0],exception);
-  q=nexus_info->pixels;
-  r=GetVirtualPixelsFromNexus(image->clip_mask,MaskVirtualPixelMethod,
-    nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
-    nexus_info->region.height,clip_nexus[0],exception);
-  number_pixels=(MagickSizeType) nexus_info->region.width*
-    nexus_info->region.height;
-  for (i=0; i < (ssize_t) number_pixels; i++)
-  {
-    if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
-      break;
-    if (GetPixelIntensity(image,r) > ((Quantum) QuantumRange/2))
-      {
-        SetPixelRed(image,GetPixelRed(image,p),q);
-        SetPixelGreen(image,GetPixelGreen(image,p),q);
-        SetPixelBlue(image,GetPixelBlue(image,p),q);
-        if (cache_info->colorspace == CMYKColorspace)
-          SetPixelBlack(image,GetPixelBlack(image,p),q);
-        SetPixelAlpha(image,GetPixelAlpha(image,p),q);
-      }
-    p+=GetPixelComponents(image);
-    q+=GetPixelComponents(image);
-    r+=GetPixelComponents(image->clip_mask);
-  }
-  clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
-  image_nexus=DestroyPixelCacheNexus(image_nexus,1);
-  if (i < (ssize_t) number_pixels)
-    return(MagickFalse);
-  return(MagickTrue);
-}
-\f
-/*
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%                                                                             %
-%                                                                             %
-%                                                                             %
 +   C l o n e P i x e l C a c h e                                             %
 %                                                                             %
 %                                                                             %
@@ -493,7 +382,7 @@ static MagickBooleanType ClipPixelCacheNexus(Image *image,
 %    o cache: the pixel cache.
 %
 */
-MagickExport Cache ClonePixelCache(const Cache cache)
+MagickPrivate Cache ClonePixelCache(const Cache cache)
 {
   CacheInfo
     *clone_info;
@@ -501,7 +390,7 @@ MagickExport Cache ClonePixelCache(const Cache cache)
   const CacheInfo
     *cache_info;
 
-  assert(cache != (const Cache) NULL);
+  assert(cache != NULL);
   cache_info=(const CacheInfo *) cache;
   assert(cache_info->signature == MagickSignature);
   if (cache_info->debug != MagickFalse)
@@ -559,49 +448,6 @@ static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
   return(status == -1 ? MagickFalse : MagickTrue);
 }
 
-static void LimitPixelCacheDescriptors(void)
-{
-  register CacheInfo
-    *p,
-    *q;
-
-  /*
-    Limit # of open file descriptors.
-  */
-  if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
-    return;
-  LockSemaphoreInfo(cache_semaphore);
-  if (cache_resources == (SplayTreeInfo *) NULL)
-    {
-      UnlockSemaphoreInfo(cache_semaphore);
-      return;
-    }
-  ResetSplayTreeIterator(cache_resources);
-  p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
-  while (p != (CacheInfo *) NULL)
-  {
-    if ((p->type == DiskCache) && (p->file != -1))
-      break;
-    p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
-  }
-  for (q=p; p != (CacheInfo *) NULL; )
-  {
-    if ((p->type == DiskCache) && (p->file != -1) &&
-        (p->timestamp < q->timestamp))
-      q=p;
-    p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
-  }
-  if (q != (CacheInfo *) NULL)
-    {
-      /*
-        Close least recently used cache.
-      */
-      (void) close(q->file);
-      q->file=(-1);
-    }
-  UnlockSemaphoreInfo(cache_semaphore);
-}
-
 static inline MagickSizeType MagickMax(const MagickSizeType x,
   const MagickSizeType y)
 {
@@ -633,7 +479,6 @@ static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
       UnlockSemaphoreInfo(cache_info->disk_semaphore);
       return(MagickTrue);  /* cache already open */
     }
-  LimitPixelCacheDescriptors();
   if (*cache_info->cache_filename == '\0')
     file=AcquireUniqueFileResource(cache_info->cache_filename);
   else
@@ -641,24 +486,24 @@ static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
     {
       case ReadMode:
       {
-        file=open(cache_info->cache_filename,O_RDONLY | O_BINARY);
+        file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
         break;
       }
       case WriteMode:
       {
-        file=open(cache_info->cache_filename,O_WRONLY | O_CREAT | O_BINARY |
-          O_EXCL,S_MODE);
+        file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
+          O_BINARY | O_EXCL,S_MODE);
         if (file == -1)
-          file=open(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
+          file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
         break;
       }
       case IOMode:
       default:
       {
-        file=open(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
+        file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
           O_EXCL,S_MODE);
         if (file == -1)
-          file=open(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
+          file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
         break;
       }
     }
@@ -669,6 +514,7 @@ static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
     }
   (void) AcquireMagickResource(FileResource,1);
   cache_info->file=file;
+  cache_info->mode=mode;
   cache_info->timestamp=time(0);
   UnlockSemaphoreInfo(cache_info->disk_semaphore);
   return(MagickTrue);
@@ -835,7 +681,7 @@ static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
   return(MagickTrue);
 }
 
-static MagickBooleanType OptimizedPixelCacheClone(CacheInfo *clone_info,
+static MagickBooleanType PixelCacheCloneOptimized(CacheInfo *clone_info,
   CacheInfo *cache_info,ExceptionInfo *exception)
 {
   MagickOffsetType
@@ -906,7 +752,7 @@ static MagickBooleanType OptimizedPixelCacheClone(CacheInfo *clone_info,
   return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
 }
 
-static MagickBooleanType UnoptimizedPixelCacheClone(CacheInfo *clone_info,
+static MagickBooleanType PixelCacheCloneUnoptimized(CacheInfo *clone_info,
   CacheInfo *cache_info,ExceptionInfo *exception)
 {
   MagickBooleanType
@@ -920,6 +766,9 @@ static MagickBooleanType UnoptimizedPixelCacheClone(CacheInfo *clone_info,
   register ssize_t
     x;
 
+  register unsigned char
+    *p;
+
   size_t
     length;
 
@@ -945,8 +794,8 @@ static MagickBooleanType UnoptimizedPixelCacheClone(CacheInfo *clone_info,
          else
            (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
     }
-  length=(size_t) MagickMax(MagickMax(cache_info->pixel_components,
-    clone_info->pixel_components)*sizeof(Quantum),MagickMax(
+  length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
+    clone_info->number_channels)*sizeof(Quantum),MagickMax(
     cache_info->metacontent_extent,clone_info->metacontent_extent));
   blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
   if (blob == (unsigned char *) NULL)
@@ -972,16 +821,8 @@ static MagickBooleanType UnoptimizedPixelCacheClone(CacheInfo *clone_info,
     }
   if (clone_info->type == DiskCache)
     {
-      if ((cache_info->type == DiskCache) &&
-          (strcmp(cache_info->cache_filename,clone_info->cache_filename) == 0))
-        {
-          (void) ClosePixelCacheOnDisk(clone_info);
-          *clone_info->cache_filename='\0';
-        }
       if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
         {
-          if (cache_info->type == DiskCache)
-            (void) ClosePixelCacheOnDisk(cache_info);
           blob=(unsigned char *) RelinquishMagickMemory(blob);
           ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
             clone_info->cache_filename);
@@ -993,20 +834,23 @@ static MagickBooleanType UnoptimizedPixelCacheClone(CacheInfo *clone_info,
     Clone pixel channels.
   */
   status=MagickTrue;
+  p=blob;
   for (y=0; y < (ssize_t) cache_info->rows; y++)
   {
     for (x=0; x < (ssize_t) cache_info->columns; x++)
     {
+      register ssize_t
+        i;
+
       /*
         Read a set of pixel channels.
       */
-      length=cache_info->pixel_components*sizeof(Quantum);
+      length=cache_info->number_channels*sizeof(Quantum);
       if (cache_info->type != DiskCache)
-        (void) memcpy(blob,(unsigned char *) cache_info->pixels+cache_offset,
-          length);
+        p=(unsigned char *) cache_info->pixels+cache_offset;
       else
         {
-          count=ReadPixelCacheRegion(cache_info,cache_offset,length,blob);
+          count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
           if ((MagickSizeType) count != length)
             {
               status=MagickFalse;
@@ -1016,33 +860,50 @@ static MagickBooleanType UnoptimizedPixelCacheClone(CacheInfo *clone_info,
       cache_offset+=length;
       if ((y < (ssize_t) clone_info->rows) &&
           (x < (ssize_t) clone_info->columns))
+        for (i=0; i < (ssize_t) clone_info->number_channels; i++)
         {
+          PixelChannel
+            channel;
+
+          PixelTrait
+            traits;
+
+          ssize_t
+            offset;
+
           /*
             Write a set of pixel channels.
           */
-          length=clone_info->pixel_components*sizeof(Quantum);
+          channel=clone_info->channel_map[i].channel;
+          traits=cache_info->channel_map[channel].traits;
+          if (traits == UndefinedPixelTrait)
+            {
+              clone_offset+=sizeof(Quantum);
+              continue;
+            }
+          offset=cache_info->channel_map[channel].offset;
           if (clone_info->type != DiskCache)
-            (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
-              blob,length);
+            (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,p+
+              offset*sizeof(Quantum),sizeof(Quantum));
           else
             {
-              count=WritePixelCacheRegion(clone_info,clone_offset,length,
-                blob);
-              if ((MagickSizeType) count != length)
+              count=WritePixelCacheRegion(clone_info,clone_offset,
+                sizeof(Quantum),p+offset*sizeof(Quantum));
+              if ((MagickSizeType) count != sizeof(Quantum))
                 {
                   status=MagickFalse;
                   break;
                 }
             }
-          clone_offset+=length;
+          clone_offset+=sizeof(Quantum);
         }
     }
-    length=clone_info->pixel_components*sizeof(Quantum);
+    length=clone_info->number_channels*sizeof(Quantum);
     (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
     for ( ; x < (ssize_t) clone_info->columns; x++)
     {
       /*
-        Set remaining columns with transparent pixel channels.
+        Set remaining columns as undefined.
       */
       if (clone_info->type != DiskCache)
         (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
@@ -1059,12 +920,12 @@ static MagickBooleanType UnoptimizedPixelCacheClone(CacheInfo *clone_info,
       clone_offset+=length;
     }
   }
-  length=clone_info->pixel_components*sizeof(Quantum);
+  length=clone_info->number_channels*sizeof(Quantum);
   (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
   for ( ; y < (ssize_t) clone_info->rows; y++)
   {
     /*
-      Set remaining rows with transparent pixels.
+      Set remaining rows as undefined.
     */
     for (x=0; x < (ssize_t) clone_info->columns; x++)
     {
@@ -1083,7 +944,7 @@ static MagickBooleanType UnoptimizedPixelCacheClone(CacheInfo *clone_info,
       clone_offset+=length;
     }
   }
-  if ((cache_info->metacontent_extent != 0) &&
+  if ((cache_info->metacontent_extent != 0) ||
       (clone_info->metacontent_extent != 0))
     {
       /*
@@ -1098,11 +959,10 @@ static MagickBooleanType UnoptimizedPixelCacheClone(CacheInfo *clone_info,
           */
           length=cache_info->metacontent_extent;
           if (cache_info->type != DiskCache)
-            (void) memcpy(blob,(unsigned char *) cache_info->pixels+
-              cache_offset,length);
+            p=(unsigned char *) cache_info->pixels+cache_offset;
           else
             {
-              count=ReadPixelCacheRegion(cache_info,cache_offset,length,blob);
+              count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
               if ((MagickSizeType) count != length)
                 {
                   status=MagickFalse;
@@ -1119,11 +979,10 @@ static MagickBooleanType UnoptimizedPixelCacheClone(CacheInfo *clone_info,
               length=clone_info->metacontent_extent;
               if (clone_info->type != DiskCache)
                 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
-                  blob,length);
+                  p,length);
               else
                 {
-                  count=WritePixelCacheRegion(clone_info,clone_offset,length,
-                    blob);
+                  count=WritePixelCacheRegion(clone_info,clone_offset,length,p);
                   if ((MagickSizeType) count != length)
                     {
                       status=MagickFalse;
@@ -1138,15 +997,14 @@ static MagickBooleanType UnoptimizedPixelCacheClone(CacheInfo *clone_info,
         for ( ; x < (ssize_t) clone_info->columns; x++)
         {
           /*
-            Set remaining columns with metacontent.
+            Set remaining columns as undefined.
           */
           if (clone_info->type != DiskCache)
             (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
               blob,length);
           else
             {
-              count=WritePixelCacheRegion(clone_info,clone_offset,length,
-                blob);
+              count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
               if ((MagickSizeType) count != length)
                 {
                   status=MagickFalse;
@@ -1161,7 +1019,7 @@ static MagickBooleanType UnoptimizedPixelCacheClone(CacheInfo *clone_info,
       for ( ; y < (ssize_t) clone_info->rows; y++)
       {
         /*
-          Set remaining rows with metacontent.
+          Set remaining rows as undefined.
         */
         for (x=0; x < (ssize_t) clone_info->columns; x++)
         {
@@ -1192,14 +1050,21 @@ static MagickBooleanType UnoptimizedPixelCacheClone(CacheInfo *clone_info,
 static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
   CacheInfo *cache_info,ExceptionInfo *exception)
 {
+  PixelChannelMap
+    *p,
+    *q;
+
   if (cache_info->type == PingCache)
     return(MagickTrue);
+  p=cache_info->channel_map;
+  q=clone_info->channel_map;
   if ((cache_info->columns == clone_info->columns) &&
       (cache_info->rows == clone_info->rows) &&
-      (cache_info->pixel_components == clone_info->pixel_components) &&
+      (cache_info->number_channels == clone_info->number_channels) &&
+      (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
       (cache_info->metacontent_extent == clone_info->metacontent_extent))
-    return(OptimizedPixelCacheClone(clone_info,cache_info,exception));
-  return(UnoptimizedPixelCacheClone(clone_info,cache_info,exception));
+    return(PixelCacheCloneOptimized(clone_info,cache_info,exception));
+  return(PixelCacheCloneUnoptimized(clone_info,cache_info,exception));
 }
 \f
 /*
@@ -1227,7 +1092,7 @@ static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
 %    o cache: the pixel cache.
 %
 */
-MagickExport void ClonePixelCacheMethods(Cache clone,const Cache cache)
+MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
 {
   CacheInfo
     *cache_info,
@@ -1379,7 +1244,7 @@ static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
   cache_info->metacontent=(void *) NULL;
 }
 
-MagickExport Cache DestroyPixelCache(Cache cache)
+MagickPrivate Cache DestroyPixelCache(Cache cache)
 {
   CacheInfo
     *cache_info;
@@ -1398,8 +1263,6 @@ MagickExport Cache DestroyPixelCache(Cache cache)
       return((Cache) NULL);
     }
   UnlockSemaphoreInfo(cache_info->semaphore);
-  if (cache_resources != (SplayTreeInfo *) NULL)
-    (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
   if (cache_info->debug != MagickFalse)
     {
       char
@@ -1472,7 +1335,7 @@ static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
   nexus_info->mapped=MagickFalse;
 }
 
-MagickExport NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
+MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
   const size_t number_threads)
 {
   register ssize_t
@@ -1484,9 +1347,9 @@ MagickExport NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
     if (nexus_info[i]->cache != (Quantum *) NULL)
       RelinquishCacheNexusPixels(nexus_info[i]);
     nexus_info[i]->signature=(~MagickSignature);
-    nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
   }
-  nexus_info=(NexusInfo **) RelinquishMagickMemory(nexus_info);
+  nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
+  nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
   return(nexus_info);
 }
 \f
@@ -1638,11 +1501,11 @@ static inline MagickBooleanType IsPixelAuthentic(const CacheInfo *cache_info,
   offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
     nexus_info->region.x;
   status=nexus_info->pixels == (cache_info->pixels+offset*
-    cache_info->pixel_components) ? MagickTrue : MagickFalse;
+    cache_info->number_channels) ? MagickTrue : MagickFalse;
   return(status);
 }
 
-MagickExport Quantum *GetAuthenticPixelCacheNexus(Image *image,
+MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
   const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
   NexusInfo *nexus_info,ExceptionInfo *exception)
 {
@@ -1650,26 +1513,27 @@ MagickExport Quantum *GetAuthenticPixelCacheNexus(Image *image,
     *cache_info;
 
   Quantum
-    *pixels;
+    *q;
 
   /*
     Transfer pixels from the cache.
   */
   assert(image != (Image *) NULL);
   assert(image->signature == MagickSignature);
-  pixels=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
-  if (pixels == (Quantum *) NULL)
+  q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,nexus_info,
+    exception);
+  if (q == (Quantum *) NULL)
     return((Quantum *) NULL);
   cache_info=(CacheInfo *) image->cache;
   assert(cache_info->signature == MagickSignature);
   if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
-    return(pixels);
+    return(q);
   if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
     return((Quantum *) NULL);
   if (cache_info->metacontent_extent != 0)
     if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
       return((Quantum *) NULL);
-  return(pixels);
+  return(q);
 }
 \f
 /*
@@ -1811,7 +1675,7 @@ MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
     id = GetOpenMPThreadId();
 
   Quantum
-    *pixels;
+    *q;
 
   assert(image != (Image *) NULL);
   assert(image->signature == MagickSignature);
@@ -1821,14 +1685,14 @@ MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
   if (cache_info->methods.get_authentic_pixels_handler !=
       (GetAuthenticPixelsHandler) NULL)
     {
-      pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
-        rows,exception);
-      return(pixels);
+      q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
+        exception);
+      return(q);
     }
   assert(id < (int) cache_info->number_threads);
-  pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
+  q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
     cache_info->nexus_info[id],exception);
-  return(pixels);
+  return(q);
 }
 \f
 /*
@@ -1873,7 +1737,7 @@ static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
     id = GetOpenMPThreadId();
 
   Quantum
-    *pixels;
+    *q;
 
   assert(image != (const Image *) NULL);
   assert(image->signature == MagickSignature);
@@ -1883,9 +1747,9 @@ static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
     return((Quantum *) NULL);
   assert(cache_info->signature == MagickSignature);
   assert(id < (int) cache_info->number_threads);
-  pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
+  q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
     cache_info->nexus_info[id],exception);
-  return(pixels);
+  return(q);
 }
 \f
 /*
@@ -1959,20 +1823,30 @@ MagickExport MagickSizeType GetImageExtent(const Image *image)
 %    o exception: return any errors or warnings in this structure.
 %
 */
+
 static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
 {
   CacheInfo
     *cache_info;
 
+  PixelChannelMap
+    *p,
+    *q;
+
   /*
     Does the image match the pixel cache morphology?
   */
   cache_info=(CacheInfo *) image->cache;
+  p=image->channel_map;
+  q=cache_info->channel_map;
   if ((image->storage_class != cache_info->storage_class) ||
       (image->colorspace != cache_info->colorspace) ||
+      (image->matte != cache_info->matte) ||
+      (image->mask != cache_info->mask) ||
       (image->columns != cache_info->columns) ||
       (image->rows != cache_info->rows) ||
-      (image->pixel_components != cache_info->pixel_components) ||
+      (image->number_channels != cache_info->number_channels) ||
+      (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
       (image->metacontent_extent != cache_info->metacontent_extent) ||
       (cache_info->nexus_info == (NexusInfo **) NULL) ||
       (cache_info->number_threads < GetOpenMPMaximumThreads()))
@@ -1996,7 +1870,7 @@ static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
     time_limit = 0;
 
   static time_t
-    cache_genesis = 0;
+    cache_timestamp = 0;
 
   status=MagickTrue;
   LockSemaphoreInfo(image->semaphore);
@@ -2026,10 +1900,10 @@ static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
         Set the exire time in seconds.
       */
       time_limit=GetMagickResourceLimit(TimeResource);
-      cache_genesis=time((time_t *) NULL);
+      cache_timestamp=time((time_t *) NULL);
     }
   if ((time_limit != MagickResourceInfinity) &&
-      ((MagickSizeType) (time((time_t *) NULL)-cache_genesis) >= time_limit))
+      ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
     ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
   assert(image->cache != (Cache) NULL);
   cache_info=(CacheInfo *) image->cache;
@@ -2060,6 +1934,8 @@ static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
                 status=ClonePixelCachePixels(clone_info,cache_info,exception);
               if (status != MagickFalse)
                 {
+                  if (cache_info->mode == ReadMode)
+                    cache_info->nexus_info=(NexusInfo **) NULL;
                   destroy=MagickTrue;
                   image->cache=clone_image.cache;
                 }
@@ -2077,10 +1953,13 @@ static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
       */
       image->taint=MagickTrue;
       image->type=UndefinedType;
-      if (image->colorspace == GRAYColorspace)
-        image->colorspace=RGBColorspace;
       if (ValidatePixelCacheMorphology(image) == MagickFalse)
-        status=OpenPixelCache(image,IOMode,exception);
+        {
+          status=OpenPixelCache(image,IOMode,exception);
+          cache_info=(CacheInfo *) image->cache;
+          if (cache_info->type == DiskCache)
+            (void) ClosePixelCacheOnDisk(cache_info);
+        }
     }
   UnlockSemaphoreInfo(image->semaphore);
   if (status == MagickFalse)
@@ -2105,7 +1984,7 @@ static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
 %  The format of the GetOneAuthenticPixel() method is:
 %
 %      MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
-%        const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
+%        const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
@@ -2119,7 +1998,7 @@ static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
 %
 */
 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
-  const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
+  const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
 {
   CacheInfo
     *cache_info;
@@ -2127,20 +2006,37 @@ MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
   register Quantum
     *q;
 
+  register ssize_t
+    i;
+
   assert(image != (Image *) NULL);
   assert(image->signature == MagickSignature);
   assert(image->cache != (Cache) NULL);
   cache_info=(CacheInfo *) image->cache;
   assert(cache_info->signature == MagickSignature);
-  *pixel=image->background_color;
+  (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
   if (cache_info->methods.get_one_authentic_pixel_from_handler !=
        (GetOneAuthenticPixelFromHandler) NULL)
     return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
       pixel,exception));
   q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
   if (q == (Quantum *) NULL)
-    return(MagickFalse);
-  GetPixelPacket(image,q,pixel);
+    {
+      pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
+      pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
+      pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
+      pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
+      pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
+      return(MagickFalse);
+    }
+  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+  {
+    PixelChannel
+      channel;
+
+    channel=GetPixelChannelMapChannel(image,i);
+    pixel[channel]=q[i];
+  }
   return(MagickTrue);
 }
 \f
@@ -2161,7 +2057,7 @@ MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
 %  The format of the GetOneAuthenticPixelFromCache() method is:
 %
 %      MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
-%        const ssize_t x,const ssize_t y,PixelPacket *pixel,
+%        const ssize_t x,const ssize_t y,Quantum *pixel,
 %        ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
@@ -2176,7 +2072,7 @@ MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
 %
 */
 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
-  const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
+  const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
 {
   CacheInfo
     *cache_info;
@@ -2187,78 +2083,35 @@ static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
   register Quantum
     *q;
 
+  register ssize_t
+    i;
+
   assert(image != (const Image *) NULL);
   assert(image->signature == MagickSignature);
   assert(image->cache != (Cache) NULL);
   cache_info=(CacheInfo *) image->cache;
   assert(cache_info->signature == MagickSignature);
   assert(id < (int) cache_info->number_threads);
-  *pixel=image->background_color;
+  (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
   q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
     exception);
   if (q == (Quantum *) NULL)
-    return(MagickFalse);
-  GetPixelPacket(image,q,pixel);
-  return(MagickTrue);
-}
-\f
-/*
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%                                                                             %
-%                                                                             %
-%                                                                             %
-%   G e t O n e V i r t u a l M a g i c k P i x e l                           %
-%                                                                             %
-%                                                                             %
-%                                                                             %
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%
-%  GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
-%  location.  The image background color is returned if an error occurs.  If
-%  you plan to modify the pixel, use GetOneAuthenticPixel() instead.
-%
-%  The format of the GetOneVirtualMagickPixel() method is:
-%
-%      MagickBooleanType GetOneVirtualMagickPixel(const Image image,
-%        const ssize_t x,const ssize_t y,PixelInfo *pixel,
-%        ExceptionInfo exception)
-%
-%  A description of each parameter follows:
-%
-%    o image: the image.
-%
-%    o x,y:  these values define the location of the pixel to return.
-%
-%    o pixel: return a pixel at the specified (x,y) location.
-%
-%    o exception: return any errors or warnings in this structure.
-%
-*/
-MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
-  const ssize_t x,const ssize_t y,PixelInfo *pixel,
-  ExceptionInfo *exception)
-{
-  CacheInfo
-    *cache_info;
-
-  const int
-    id = GetOpenMPThreadId();
-
-  register const Quantum
-    *pixels;
+    {
+      pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
+      pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
+      pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
+      pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
+      pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
+      return(MagickFalse);
+    }
+  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+  {
+    PixelChannel
+      channel;
 
-  assert(image != (const Image *) NULL);
-  assert(image->signature == MagickSignature);
-  assert(image->cache != (Cache) NULL);
-  cache_info=(CacheInfo *) image->cache;
-  assert(cache_info->signature == MagickSignature);
-  assert(id < (int) cache_info->number_threads);
-  pixels=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
-    1UL,1UL,cache_info->nexus_info[id],exception);
-  GetPixelInfo(image,pixel);
-  if (pixels == (const Quantum *) NULL)
-    return(MagickFalse);
-  SetPixelInfo(image,pixels,pixel);
+    channel=GetPixelChannelMapChannel(image,i);
+    pixel[channel]=q[i];
+  }
   return(MagickTrue);
 }
 \f
@@ -2267,29 +2120,25 @@ MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
 %                                                                             %
 %                                                                             %
 %                                                                             %
-%   G e t O n e V i r t u a l M e t h o d P i x e l                           %
+%   G e t O n e V i r t u a l P i x e l                                       %
 %                                                                             %
 %                                                                             %
 %                                                                             %
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
-%  GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
-%  location as defined by specified pixel method.  The image background color
-%  is returned if an error occurs.  If you plan to modify the pixel, use
-%  GetOneAuthenticPixel() instead.
+%  GetOneVirtualPixel() returns a single virtual pixel at the specified
+%  (x,y) location.  The image background color is returned if an error occurs.
+%  If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
 %
-%  The format of the GetOneVirtualMethodPixel() method is:
+%  The format of the GetOneVirtualPixel() method is:
 %
-%      MagickBooleanType GetOneVirtualMethodPixel(const Image image,
-%        const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
-%        const ssize_t y,PixelPacket *pixel,ExceptionInfo exception)
+%      MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
+%        const ssize_t y,Quantum *pixel,ExceptionInfo exception)
 %
 %  A description of each parameter follows:
 %
 %    o image: the image.
 %
-%    o virtual_pixel_method: the virtual pixel method.
-%
 %    o x,y:  These values define the location of the pixel to return.
 %
 %    o pixel: return a pixel at the specified (x,y) location.
@@ -2297,9 +2146,8 @@ MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
 %    o exception: return any errors or warnings in this structure.
 %
 */
-MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
-  const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
-  PixelPacket *pixel,ExceptionInfo *exception)
+MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
+  const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
 {
   CacheInfo
     *cache_info;
@@ -2310,24 +2158,39 @@ MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
   const Quantum
     *p;
 
+  register ssize_t
+    i;
+
   assert(image != (const Image *) NULL);
   assert(image->signature == MagickSignature);
   assert(image->cache != (Cache) NULL);
   cache_info=(CacheInfo *) image->cache;
   assert(cache_info->signature == MagickSignature);
-  *pixel=image->background_color;
+  (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
   if (cache_info->methods.get_one_virtual_pixel_from_handler !=
        (GetOneVirtualPixelFromHandler) NULL)
     return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
-      virtual_pixel_method,x,y,pixel,exception));
+      GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
   assert(id < (int) cache_info->number_threads);
-  p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
-    cache_info->nexus_info[id],exception);
+  p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
+    1UL,1UL,cache_info->nexus_info[id],exception);
   if (p == (const Quantum *) NULL)
-    return(MagickFalse);
-  GetPixelPacket(image,p,pixel);
-  if (image->colorspace == CMYKColorspace)
-    pixel->black=GetPixelBlack(image,p);
+    {
+      pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
+      pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
+      pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
+      pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
+      pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
+      return(MagickFalse);
+    }
+  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+  {
+    PixelChannel
+      channel;
+
+    channel=GetPixelChannelMapChannel(image,i);
+    pixel[channel]=p[i];
+  }
   return(MagickTrue);
 }
 \f
@@ -2336,25 +2199,28 @@ MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
 %                                                                             %
 %                                                                             %
 %                                                                             %
-%   G e t O n e V i r t u a l P i x e l                                       %
++   G e t O n e V i r t u a l P i x e l F r o m C a c h e                     %
 %                                                                             %
 %                                                                             %
 %                                                                             %
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
-%  GetOneVirtualPixel() returns a single virtual pixel at the specified
-%  (x,y) location.  The image background color is returned if an error occurs.
-%  If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
+%  GetOneVirtualPixelFromCache() returns a single virtual pixel at the
+%  specified (x,y) location.  The image background color is returned if an
+%  error occurs.
 %
-%  The format of the GetOneVirtualPixel() method is:
+%  The format of the GetOneVirtualPixelFromCache() method is:
 %
-%      MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
-%        const ssize_t y,PixelPacket *pixel,ExceptionInfo exception)
+%      MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
+%        const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
+%        Quantum *pixel,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
 %    o image: the image.
 %
+%    o virtual_pixel_method: the virtual pixel method.
+%
 %    o x,y:  These values define the location of the pixel to return.
 %
 %    o pixel: return a pixel at the specified (x,y) location.
@@ -2362,8 +2228,9 @@ MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
 %    o exception: return any errors or warnings in this structure.
 %
 */
-MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
-  const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
+static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
+  const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
+  Quantum *pixel,ExceptionInfo *exception)
 {
   CacheInfo
     *cache_info;
@@ -2374,24 +2241,35 @@ MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
   const Quantum
     *p;
 
+  register ssize_t
+    i;
+
   assert(image != (const Image *) NULL);
   assert(image->signature == MagickSignature);
   assert(image->cache != (Cache) NULL);
   cache_info=(CacheInfo *) image->cache;
   assert(cache_info->signature == MagickSignature);
-  *pixel=image->background_color;
-  if (cache_info->methods.get_one_virtual_pixel_from_handler !=
-       (GetOneVirtualPixelFromHandler) NULL)
-    return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
-      GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
   assert(id < (int) cache_info->number_threads);
-  p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
-    1UL,1UL,cache_info->nexus_info[id],exception);
+  (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
+  p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
+    cache_info->nexus_info[id],exception);
   if (p == (const Quantum *) NULL)
-    return(MagickFalse);
-  GetPixelPacket(image,p,pixel);
-  if (image->colorspace == CMYKColorspace)
-    pixel->black=GetPixelBlack(image,p);
+    {
+      pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
+      pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
+      pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
+      pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
+      pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
+      return(MagickFalse);
+    }
+  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+  {
+    PixelChannel
+      channel;
+
+    channel=GetPixelChannelMapChannel(image,i);
+    pixel[channel]=p[i];
+  }
   return(MagickTrue);
 }
 \f
@@ -2400,21 +2278,21 @@ MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
 %                                                                             %
 %                                                                             %
 %                                                                             %
-+   G e t O n e V i r t u a l P i x e l F r o m C a c h e                     %
+%   G e t O n e V i r t u a l P i x e l I n f o                               %
 %                                                                             %
 %                                                                             %
 %                                                                             %
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
-%  GetOneVirtualPixelFromCache() returns a single virtual pixel at the
-%  specified (x,y) location.  The image background color is returned if an
-%  error occurs.
+%  GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
+%  location.  The image background color is returned if an error occurs.  If
+%  you plan to modify the pixel, use GetOneAuthenticPixel() instead.
 %
-%  The format of the GetOneVirtualPixelFromCache() method is:
+%  The format of the GetOneVirtualPixelInfo() method is:
 %
-%      MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
-%        const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
-%        PixelPacket *pixel,ExceptionInfo *exception)
+%      MagickBooleanType GetOneVirtualPixelInfo(const Image image,
+%        const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
+%        const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
 %
 %  A description of each parameter follows:
 %
@@ -2422,16 +2300,16 @@ MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
 %
 %    o virtual_pixel_method: the virtual pixel method.
 %
-%    o x,y:  These values define the location of the pixel to return.
+%    o x,y:  these values define the location of the pixel to return.
 %
 %    o pixel: return a pixel at the specified (x,y) location.
 %
 %    o exception: return any errors or warnings in this structure.
 %
 */
-static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
+MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
   const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
-  PixelPacket *pixel,ExceptionInfo *exception)
+  PixelInfo *pixel,ExceptionInfo *exception)
 {
   CacheInfo
     *cache_info;
@@ -2439,7 +2317,7 @@ static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
   const int
     id = GetOpenMPThreadId();
 
-  const Quantum
+  register const Quantum
     *p;
 
   assert(image != (const Image *) NULL);
@@ -2448,14 +2326,12 @@ static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
   cache_info=(CacheInfo *) image->cache;
   assert(cache_info->signature == MagickSignature);
   assert(id < (int) cache_info->number_threads);
-  *pixel=image->background_color;
   p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
     cache_info->nexus_info[id],exception);
+  GetPixelInfo(image,pixel);
   if (p == (const Quantum *) NULL)
     return(MagickFalse);
-  GetPixelPacket(image,p,pixel);
-  if (image->colorspace == CMYKColorspace)
-    pixel->black=GetPixelBlack(image,p);
+  GetPixelInfoPixel(image,p,pixel);
   return(MagickTrue);
 }
 \f
@@ -2481,7 +2357,7 @@ static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
 %    o cache: the pixel cache.
 %
 */
-MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
+MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
 {
   CacheInfo
     *cache_info;
@@ -2517,7 +2393,7 @@ MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
 %    o cache_methods: Specifies a pointer to a CacheMethods structure.
 %
 */
-MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
+MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
 {
   assert(cache_methods != (CacheMethods *) NULL);
   (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
@@ -2562,7 +2438,7 @@ MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
 %    o nexus_info: the nexus info.
 %
 */
-MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
+MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
   NexusInfo *nexus_info)
 {
   CacheInfo
@@ -2571,7 +2447,7 @@ MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
   MagickSizeType
     extent;
 
-  assert(cache != (const Cache) NULL);
+  assert(cache != NULL);
   cache_info=(CacheInfo *) cache;
   assert(cache_info->signature == MagickSignature);
   extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
@@ -2606,13 +2482,13 @@ MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
 %    o nexus_info: the cache nexus to return the meta-content.
 %
 */
-MagickExport void *GetPixelCacheNexusMetacontent(const Cache cache,
+MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
   NexusInfo *nexus_info)
 {
   CacheInfo
     *cache_info;
 
-  assert(cache != (const Cache) NULL);
+  assert(cache != NULL);
   cache_info=(CacheInfo *) cache;
   assert(cache_info->signature == MagickSignature);
   if (cache_info->storage_class == UndefinedClass)
@@ -2646,13 +2522,13 @@ MagickExport void *GetPixelCacheNexusMetacontent(const Cache cache,
 %    o nexus_info: the cache nexus to return the pixels.
 %
 */
-MagickExport Quantum *GetPixelCacheNexusPixels(const Cache cache,
+MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
   NexusInfo *nexus_info)
 {
   CacheInfo
     *cache_info;
 
-  assert(cache != (const Cache) NULL);
+  assert(cache != NULL);
   cache_info=(CacheInfo *) cache;
   assert(cache_info->signature == MagickSignature);
   if (cache_info->storage_class == UndefinedClass)
@@ -2687,7 +2563,7 @@ MagickExport Quantum *GetPixelCacheNexusPixels(const Cache cache,
 %    o exception: return any errors or warnings in this structure.
 %
 */
-MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
+MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
   ExceptionInfo *exception)
 {
   CacheInfo
@@ -2732,7 +2608,7 @@ MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
 %    o cache: the pixel cache.
 %
 */
-MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
+MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
 {
   CacheInfo
     *cache_info;
@@ -2773,7 +2649,7 @@ MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
 %    o height: the optimize cache tile height in pixels.
 %
 */
-MagickExport void GetPixelCacheTileSize(const Image *image,size_t *width,
+MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
   size_t *height)
 {
   CacheInfo
@@ -2785,9 +2661,9 @@ MagickExport void GetPixelCacheTileSize(const Image *image,size_t *width,
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   cache_info=(CacheInfo *) image->cache;
   assert(cache_info->signature == MagickSignature);
-  *width=2048UL/(cache_info->pixel_components*sizeof(Quantum));
+  *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
   if (GetPixelCacheType(image) == DiskCache)
-    *width=8192UL/(cache_info->pixel_components*sizeof(Quantum));
+    *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
   *height=(*width);
 }
 \f
@@ -2813,7 +2689,7 @@ MagickExport void GetPixelCacheTileSize(const Image *image,size_t *width,
 %    o image: the image.
 %
 */
-MagickExport CacheType GetPixelCacheType(const Image *image)
+MagickPrivate CacheType GetPixelCacheType(const Image *image)
 {
   CacheInfo
     *cache_info;
@@ -2850,7 +2726,7 @@ MagickExport CacheType GetPixelCacheType(const Image *image)
 %    o image: the image.
 %
 */
-MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
+MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
 {
   CacheInfo
     *cache_info;
@@ -2934,8 +2810,8 @@ static const void *GetVirtualMetacontentFromCache(const Image *image)
 %    o nexus_info: the cache nexus to return the meta-content.
 %
 */
-MagickExport const void *GetVirtualMetacontentFromNexus(
-  const Cache cache,NexusInfo *nexus_info)
+MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
+  NexusInfo *nexus_info)
 {
   CacheInfo
     *cache_info;
@@ -2988,13 +2864,9 @@ MagickExport const void *GetVirtualMetacontent(const Image *image)
   assert(image->cache != (Cache) NULL);
   cache_info=(CacheInfo *) image->cache;
   assert(cache_info->signature == MagickSignature);
-  if (cache_info->methods.get_virtual_metacontent_from_handler !=
-       (GetVirtualMetacontentFromHandler) NULL)
-    {
-      metacontent=cache_info->methods.
-        get_virtual_metacontent_from_handler(image);
-      return(metacontent);
-    }
+  metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
+  if (metacontent != (GetVirtualMetacontentFromHandler) NULL)
+    return(metacontent);
   assert(id < (int) cache_info->number_threads);
   metacontent=GetVirtualMetacontentFromNexus(cache_info,
     cache_info->nexus_info[id]);
@@ -3105,19 +2977,19 @@ static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
   return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
 }
 
-/*
-  VirtualPixelModulo() computes the remainder of dividing offset by extent.  It
-  returns not only the quotient (tile the offset falls in) but also the positive
-  remainer within that tile such that 0 <= remainder < extent.  This method is
-  essentially a ldiv() using a floored modulo division rather than the normal
-  default truncated modulo division.
-*/
 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
   const size_t extent)
 {
   MagickModulo
     modulo;
 
+  /*
+    Compute the remainder of dividing offset by extent.  It returns not only
+    the quotient (tile the offset falls in) but also the positive remainer
+    within that tile such that 0 <= remainder < extent.  This method is
+    essentially a ldiv() using a floored modulo division rather than the
+    normal default truncated modulo division.
+  */
   modulo.quotient=offset/(ssize_t) extent;
   if (offset < 0L)
     modulo.quotient--;
@@ -3125,7 +2997,7 @@ static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
   return(modulo);
 }
 
-MagickExport const Quantum *GetVirtualPixelsFromNexus(const Image *image,
+MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
   const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
   const size_t columns,const size_t rows,NexusInfo *nexus_info,
   ExceptionInfo *exception)
@@ -3145,7 +3017,7 @@ MagickExport const Quantum *GetVirtualPixelsFromNexus(const Image *image,
 
   Quantum
     *pixels,
-    *virtual_pixel;
+    virtual_pixel[CompositePixelChannel];
 
   RectangleInfo
     region;
@@ -3160,14 +3032,17 @@ MagickExport const Quantum *GetVirtualPixelsFromNexus(const Image *image,
     *restrict q;
 
   register ssize_t
-    u,
-    v;
+    i,
+    u;
 
   register unsigned char
     *restrict s;
 
+  ssize_t
+    v;
+
   void
-    *virtual_associated_pixel;
+    *virtual_metacontent;
 
   /*
     Acquire pixels.
@@ -3186,6 +3061,7 @@ MagickExport const Quantum *GetVirtualPixelsFromNexus(const Image *image,
   pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
   if (pixels == (Quantum *) NULL)
     return((const Quantum *) NULL);
+  q=pixels;
   offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
     nexus_info->region.x;
   length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
@@ -3202,7 +3078,7 @@ MagickExport const Quantum *GetVirtualPixelsFromNexus(const Image *image,
           Pixel request is inside cache extents.
         */
         if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
-          return(pixels);
+          return(q);
         status=ReadPixelCachePixels(cache_info,nexus_info,exception);
         if (status == MagickFalse)
           return((const Quantum *) NULL);
@@ -3212,12 +3088,11 @@ MagickExport const Quantum *GetVirtualPixelsFromNexus(const Image *image,
             if (status == MagickFalse)
               return((const Quantum *) NULL);
           }
-        return(pixels);
+        return(q);
       }
   /*
     Pixel request is outside cache extents.
   */
-  q=pixels;
   s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
   virtual_nexus=AcquirePixelCacheNexus(1);
   if (virtual_nexus == (NexusInfo **) NULL)
@@ -3228,8 +3103,9 @@ MagickExport const Quantum *GetVirtualPixelsFromNexus(const Image *image,
         "UnableToGetCacheNexus","`%s'",image->filename);
       return((const Quantum *) NULL);
     }
-  virtual_pixel=(Quantum *) NULL;
-  virtual_associated_pixel=(void *) NULL;
+  (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
+    sizeof(*virtual_pixel));
+  virtual_metacontent=(void *) NULL;
   switch (virtual_pixel_method)
   {
     case BackgroundVirtualPixelMethod:
@@ -3243,77 +3119,67 @@ MagickExport const Quantum *GetVirtualPixelsFromNexus(const Image *image,
     case HorizontalTileVirtualPixelMethod:
     case VerticalTileVirtualPixelMethod:
     {
-      /*
-        Acquire virtual pixel and associated channels.
-      */
-      virtual_pixel=(Quantum *) AcquireQuantumMemory(
-        cache_info->pixel_components,sizeof(*virtual_pixel));
-      if (virtual_pixel == (Quantum *) NULL)
-        {
-          virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
-          (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
-            "UnableToGetCacheNexus","`%s'",image->filename);
-          return((const Quantum *) NULL);
-        }
-      (void) ResetMagickMemory(virtual_pixel,0,cache_info->pixel_components*
-        sizeof(*virtual_pixel));
       if (cache_info->metacontent_extent != 0)
         {
-          virtual_associated_pixel=(void *) AcquireMagickMemory(
+          /*
+            Acquire a metacontent buffer.
+          */
+          virtual_metacontent=(void *) AcquireQuantumMemory(1,
             cache_info->metacontent_extent);
-          if (virtual_associated_pixel == (void *) NULL)
+          if (virtual_metacontent == (void *) NULL)
             {
-              virtual_pixel=(Quantum *) RelinquishMagickMemory(
-                virtual_pixel);
               virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
               (void) ThrowMagickException(exception,GetMagickModule(),
                 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
               return((const Quantum *) NULL);
             }
-          (void) ResetMagickMemory(virtual_associated_pixel,0,
+          (void) ResetMagickMemory(virtual_metacontent,0,
             cache_info->metacontent_extent);
         }
       switch (virtual_pixel_method)
       {
         case BlackVirtualPixelMethod:
         {
-          SetPixelRed(image,0,virtual_pixel);
-          SetPixelGreen(image,0,virtual_pixel);
-          SetPixelBlue(image,0,virtual_pixel);
+          for (i=0; i < (ssize_t) cache_info->number_channels; i++)
+            SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
           SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
           break;
         }
         case GrayVirtualPixelMethod:
         {
-          SetPixelRed(image,QuantumRange/2,virtual_pixel);
-          SetPixelGreen(image,QuantumRange/2,virtual_pixel);
-          SetPixelBlue(image,QuantumRange/2,virtual_pixel);
+          for (i=0; i < (ssize_t) cache_info->number_channels; i++)
+            SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
+              virtual_pixel);
           SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
           break;
         }
         case TransparentVirtualPixelMethod:
         {
-          SetPixelRed(image,0,virtual_pixel);
-          SetPixelGreen(image,0,virtual_pixel);
-          SetPixelBlue(image,0,virtual_pixel);
+          for (i=0; i < (ssize_t) cache_info->number_channels; i++)
+            SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
           SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
           break;
         }
         case MaskVirtualPixelMethod:
         case WhiteVirtualPixelMethod:
         {
-          SetPixelRed(image,(Quantum) QuantumRange,virtual_pixel);
-          SetPixelGreen(image,(Quantum) QuantumRange,virtual_pixel);
-          SetPixelBlue(image,(Quantum) QuantumRange,virtual_pixel);
+          for (i=0; i < (ssize_t) cache_info->number_channels; i++)
+            SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
           SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
           break;
         }
         default:
         {
-          SetPixelRed(image,image->background_color.red,virtual_pixel);
-          SetPixelGreen(image,image->background_color.green,virtual_pixel);
-          SetPixelBlue(image,image->background_color.blue,virtual_pixel);
-          SetPixelAlpha(image,image->background_color.alpha,virtual_pixel);
+          SetPixelRed(image,ClampToQuantum(image->background_color.red),
+            virtual_pixel);
+          SetPixelGreen(image,ClampToQuantum(image->background_color.green),
+            virtual_pixel);
+          SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
+            virtual_pixel);
+          SetPixelBlack(image,ClampToQuantum(image->background_color.black),
+            virtual_pixel);
+          SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
+            virtual_pixel);
           break;
         }
       }
@@ -3420,7 +3286,7 @@ MagickExport const Quantum *GetVirtualPixelsFromNexus(const Image *image,
             case WhiteVirtualPixelMethod:
             {
               p=virtual_pixel;
-              r=virtual_associated_pixel;
+              r=virtual_metacontent;
               break;
             }
             case EdgeVirtualPixelMethod:
@@ -3431,7 +3297,7 @@ MagickExport const Quantum *GetVirtualPixelsFromNexus(const Image *image,
               if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
                 {
                   p=virtual_pixel;
-                  r=virtual_associated_pixel;
+                  r=virtual_metacontent;
                   break;
                 }
               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
@@ -3445,7 +3311,7 @@ MagickExport const Quantum *GetVirtualPixelsFromNexus(const Image *image,
               if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
                 {
                   p=virtual_pixel;
-                  r=virtual_associated_pixel;
+                  r=virtual_metacontent;
                   break;
                 }
               x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
@@ -3461,7 +3327,7 @@ MagickExport const Quantum *GetVirtualPixelsFromNexus(const Image *image,
               if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
                 {
                   p=virtual_pixel;
-                  r=virtual_associated_pixel;
+                  r=virtual_metacontent;
                   break;
                 }
               x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
@@ -3475,11 +3341,10 @@ MagickExport const Quantum *GetVirtualPixelsFromNexus(const Image *image,
           }
           if (p == (const Quantum *) NULL)
             break;
-          (void) memcpy(q,p,(size_t) length*cache_info->pixel_components*
+          (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
             sizeof(*p));
-          q+=cache_info->pixel_components;
-          if ((s != (void *) NULL) &&
-              (r != (const void *) NULL))
+          q+=cache_info->number_channels;
+          if ((s != (void *) NULL) && (r != (const void *) NULL))
             {
               (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
               s+=cache_info->metacontent_extent;
@@ -3494,9 +3359,9 @@ MagickExport const Quantum *GetVirtualPixelsFromNexus(const Image *image,
       if (p == (const Quantum *) NULL)
         break;
       r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
-      (void) memcpy(q,p,(size_t) length*cache_info->pixel_components*sizeof(*p));
-      q+=length*cache_info->pixel_components;
-      if ((s != (void *) NULL) && (r != (const void *) NULL))
+      (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
+      q+=length*cache_info->number_channels;
+      if ((r != (void *) NULL) && (s != (const void *) NULL))
         {
           (void) memcpy(s,r,(size_t) length);
           s+=length*cache_info->metacontent_extent;
@@ -3506,11 +3371,8 @@ MagickExport const Quantum *GetVirtualPixelsFromNexus(const Image *image,
   /*
     Free resources.
   */
-  if (virtual_associated_pixel != (void *) NULL)
-    virtual_associated_pixel=(void *) RelinquishMagickMemory(
-      virtual_associated_pixel);
-  if (virtual_pixel != (Quantum *) NULL)
-    virtual_pixel=(Quantum *) RelinquishMagickMemory(virtual_pixel);
+  if (virtual_metacontent != (void *) NULL)
+    virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
   virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
   return(pixels);
 }
@@ -3560,7 +3422,7 @@ static const Quantum *GetVirtualPixelCache(const Image *image,
     id = GetOpenMPThreadId();
 
   const Quantum
-    *pixels;
+    *p;
 
   assert(image != (const Image *) NULL);
   assert(image->signature == MagickSignature);
@@ -3568,9 +3430,9 @@ static const Quantum *GetVirtualPixelCache(const Image *image,
   cache_info=(CacheInfo *) image->cache;
   assert(cache_info->signature == MagickSignature);
   assert(id < (int) cache_info->number_threads);
-  pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
+  p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
     cache_info->nexus_info[id],exception);
-  return(pixels);
+  return(p);
 }
 \f
 /*
@@ -3675,7 +3537,7 @@ MagickExport const Quantum *GetVirtualPixels(const Image *image,
     id = GetOpenMPThreadId();
 
   const Quantum
-    *pixels;
+    *p;
 
   assert(image != (const Image *) NULL);
   assert(image->signature == MagickSignature);
@@ -3687,9 +3549,9 @@ MagickExport const Quantum *GetVirtualPixels(const Image *image,
     return(cache_info->methods.get_virtual_pixel_handler(image,
       GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
   assert(id < (int) cache_info->number_threads);
-  pixels=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
+  p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
     columns,rows,cache_info->nexus_info[id],exception);
-  return(pixels);
+  return(p);
 }
 \f
 /*
@@ -3758,7 +3620,7 @@ static const Quantum *GetVirtualPixelsCache(const Image *image)
 %    o nexus_info: the cache nexus to return the colormap pixels.
 %
 */
-MagickExport const Quantum *GetVirtualPixelsNexus(const Cache cache,
+MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
   NexusInfo *nexus_info)
 {
   CacheInfo
@@ -3777,135 +3639,6 @@ MagickExport const Quantum *GetVirtualPixelsNexus(const Cache cache,
 %                                                                             %
 %                                                                             %
 %                                                                             %
-+   M a s k P i x e l C a c h e N e x u s                                     %
-%                                                                             %
-%                                                                             %
-%                                                                             %
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%
-%  MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
-%  The method returns MagickTrue if the pixel region is masked, otherwise
-%  MagickFalse.
-%
-%  The format of the MaskPixelCacheNexus() method is:
-%
-%      MagickBooleanType MaskPixelCacheNexus(Image *image,
-%        NexusInfo *nexus_info,ExceptionInfo *exception)
-%
-%  A description of each parameter follows:
-%
-%    o image: the image.
-%
-%    o nexus_info: the cache nexus to clip.
-%
-%    o exception: return any errors or warnings in this structure.
-%
-*/
-
-static inline void MagickPixelCompositeMask(const PixelInfo *p,
-  const MagickRealType alpha,const PixelInfo *q,
-  const MagickRealType beta,PixelInfo *composite)
-{
-  MagickRealType
-    gamma;
-
-  if (alpha == TransparentAlpha)
-    {
-      *composite=(*q);
-      return;
-    }
-  gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
-  gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
-  composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
-  composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
-  composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
-  if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
-    composite->black=gamma*MagickOver_(p->black,alpha,q->black,beta);
-}
-
-static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
-  ExceptionInfo *exception)
-{
-  CacheInfo
-    *cache_info;
-
-  PixelInfo
-    alpha,
-    beta;
-
-  MagickSizeType
-    number_pixels;
-
-  NexusInfo
-    **clip_nexus,
-    **image_nexus;
-
-  register const Quantum
-    *restrict p,
-    *restrict r;
-
-  register Quantum
-    *restrict q;
-
-  register ssize_t
-    i;
-
-  /*
-    Apply clip mask.
-  */
-  if (image->debug != MagickFalse)
-    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
-  if (image->mask == (Image *) NULL)
-    return(MagickFalse);
-  cache_info=(CacheInfo *) image->cache;
-  if (cache_info == (Cache) NULL)
-    return(MagickFalse);
-  image_nexus=AcquirePixelCacheNexus(1);
-  clip_nexus=AcquirePixelCacheNexus(1);
-  if ((image_nexus == (NexusInfo **) NULL) ||
-      (clip_nexus == (NexusInfo **) NULL))
-    ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
-  p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
-    nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
-    nexus_info->region.height,image_nexus[0],exception);
-  q=nexus_info->pixels;
-  r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
-    nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
-    nexus_info->region.height,clip_nexus[0],&image->exception);
-  GetPixelInfo(image,&alpha);
-  GetPixelInfo(image,&beta);
-  number_pixels=(MagickSizeType) nexus_info->region.width*
-    nexus_info->region.height;
-  for (i=0; i < (ssize_t) number_pixels; i++)
-  {
-    if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
-      break;
-    SetPixelInfo(image,p,&alpha);
-    SetPixelInfo(image,q,&beta);
-    MagickPixelCompositeMask(&beta,(MagickRealType) GetPixelIntensity(image,r),
-      &alpha,alpha.alpha,&beta);
-    SetPixelRed(image,ClampToQuantum(beta.red),q);
-    SetPixelGreen(image,ClampToQuantum(beta.green),q);
-    SetPixelBlue(image,ClampToQuantum(beta.blue),q);
-    if (cache_info->colorspace == CMYKColorspace)
-      SetPixelBlack(image,ClampToQuantum(beta.black),q);
-    SetPixelAlpha(image,ClampToQuantum(beta.alpha),q);
-    p++;
-    q++;
-    r++;
-  }
-  clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
-  image_nexus=DestroyPixelCacheNexus(image_nexus,1);
-  if (i < (ssize_t) number_pixels)
-    return(MagickFalse);
-  return(MagickTrue);
-}
-\f
-/*
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%                                                                             %
-%                                                                             %
-%                                                                             %
 +   O p e n P i x e l C a c h e                                               %
 %                                                                             %
 %                                                                             %
@@ -3935,7 +3668,7 @@ static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
 {
   cache_info->mapped=MagickFalse;
-  cache_info->pixels=(Quantum *) AcquireMagickMemory((size_t)
+  cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
     cache_info->length);
   if (cache_info->pixels == (Quantum *) NULL)
     {
@@ -4009,7 +3742,6 @@ static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   if ((image->columns == 0) || (image->rows == 0))
     ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
-  StandardPixelComponentMap(image);
   cache_info=(CacheInfo *) image->cache;
   assert(cache_info->signature == MagickSignature);
   source_info=(*cache_info);
@@ -4018,11 +3750,16 @@ static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
     image->filename,(double) GetImageIndexInList(image));
   cache_info->storage_class=image->storage_class;
   cache_info->colorspace=image->colorspace;
-  cache_info->mode=mode;
+  cache_info->matte=image->matte;
+  cache_info->mask=image->mask;
   cache_info->rows=image->rows;
   cache_info->columns=image->columns;
-  cache_info->pixel_components=GetPixelComponents(image);
+  InitializePixelChannelMap(image);
+  cache_info->number_channels=GetPixelChannels(image);
+  (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
+    sizeof(*image->channel_map));
   cache_info->metacontent_extent=image->metacontent_extent;
+  cache_info->mode=mode;
   if (image->ping != MagickFalse)
     {
       cache_info->type=PingCache;
@@ -4032,7 +3769,7 @@ static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
       return(MagickTrue);
     }
   number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
-  packet_size=cache_info->pixel_components*sizeof(Quantum);
+  packet_size=cache_info->number_channels*sizeof(Quantum);
   if (image->metacontent_extent != 0)
     packet_size+=cache_info->metacontent_extent;
   length=number_pixels*packet_size;
@@ -4041,24 +3778,8 @@ static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
     ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
       image->filename);
   cache_info->length=length;
-  if ((cache_info->type != UndefinedCache) &&
-      (cache_info->columns <= source_info.columns) &&
-      (cache_info->rows <= source_info.rows) &&
-      (cache_info->pixel_components <= source_info.pixel_components) &&
-      (cache_info->metacontent_extent <= source_info.metacontent_extent))
-    {
-      /*
-        Inline pixel cache clone optimization.
-      */
-      if ((cache_info->columns == source_info.columns) &&
-          (cache_info->rows == source_info.rows) &&
-          (cache_info->pixel_components == source_info.pixel_components) &&
-          (cache_info->metacontent_extent == source_info.metacontent_extent))
-        return(MagickTrue);
-      return(ClonePixelCachePixels(cache_info,&source_info,exception));
-    }
   status=AcquireMagickResource(AreaResource,cache_info->length);
-  length=number_pixels*(cache_info->pixel_components*sizeof(Quantum)+
+  length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
     cache_info->metacontent_extent);
   if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
     {
@@ -4077,13 +3798,12 @@ static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
               status=MagickTrue;
               if (image->debug != MagickFalse)
                 {
-                  (void) FormatMagickSize(cache_info->length,MagickTrue,
-                    format);
+                  (void) FormatMagickSize(cache_info->length,MagickTrue,format);
                   (void) FormatLocaleString(message,MaxTextExtent,
                     "open %s (%s memory, %.20gx%.20gx%.20g %s)",
                     cache_info->filename,cache_info->mapped != MagickFalse ?
                     "anonymous" : "heap",(double) cache_info->columns,(double)
-                    cache_info->rows,(double) cache_info->pixel_components,
+                    cache_info->rows,(double) cache_info->number_channels,
                     format);
                   (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
                     message);
@@ -4092,8 +3812,9 @@ static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
               cache_info->metacontent=(void *) NULL;
               if (cache_info->metacontent_extent != 0)
                 cache_info->metacontent=(void *) (cache_info->pixels+
-                  number_pixels*cache_info->pixel_components);
-              if (source_info.storage_class != UndefinedClass)
+                  number_pixels*cache_info->number_channels);
+              if ((source_info.storage_class != UndefinedClass) &&
+                  (mode != ReadMode))
                 {
                   status=ClonePixelCachePixels(cache_info,&source_info,
                     exception);
@@ -4114,6 +3835,11 @@ static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
         "CacheResourcesExhausted","`%s'",image->filename);
       return(MagickFalse);
     }
+  if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
+    {
+      (void) ClosePixelCacheOnDisk(cache_info);
+      *cache_info->cache_filename='\0';
+    }
   if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
     {
       RelinquishMagickResource(DiskResource,cache_info->length);
@@ -4129,10 +3855,9 @@ static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
         image->filename);
       return(MagickFalse);
     }
-  length=number_pixels*(cache_info->pixel_components*sizeof(Quantum)+
+  length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
     cache_info->metacontent_extent);
-  status=AcquireMagickResource(AreaResource,cache_info->length);
-  if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
+  if (length != (MagickSizeType) ((size_t) length))
     cache_info->type=DiskCache;
   else
     {
@@ -4161,8 +3886,9 @@ static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
               cache_info->metacontent=(void *) NULL;
               if (cache_info->metacontent_extent != 0)
                 cache_info->metacontent=(void *) (cache_info->pixels+
-                  number_pixels*cache_info->pixel_components);
-              if (source_info.storage_class != UndefinedClass)
+                  number_pixels*cache_info->number_channels);
+              if ((source_info.storage_class != UndefinedClass) &&
+                  (mode != ReadMode))
                 {
                   status=ClonePixelCachePixels(cache_info,&source_info,
                     exception);
@@ -4170,13 +3896,12 @@ static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
                 }
               if (image->debug != MagickFalse)
                 {
-                  (void) FormatMagickSize(cache_info->length,MagickTrue,
-                    format);
+                  (void) FormatMagickSize(cache_info->length,MagickTrue,format);
                   (void) FormatLocaleString(message,MaxTextExtent,
                     "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
                     cache_info->filename,cache_info->cache_filename,
                     cache_info->file,(double) cache_info->columns,(double)
-                    cache_info->rows,(double) cache_info->pixel_components,
+                    cache_info->rows,(double) cache_info->number_channels,
                     format);
                   (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
                     message);
@@ -4187,7 +3912,7 @@ static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
       RelinquishMagickResource(MapResource,cache_info->length);
     }
   status=MagickTrue;
-  if ((source_info.type != UndefinedCache) && (mode != ReadMode))
+  if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
     {
       status=ClonePixelCachePixels(cache_info,&source_info,exception);
       RelinquishPixelCachePixels(&source_info);
@@ -4199,7 +3924,7 @@ static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
         "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
         cache_info->cache_filename,cache_info->file,(double)
         cache_info->columns,(double) cache_info->rows,(double)
-        cache_info->pixel_components,format);
+        cache_info->number_channels,format);
       (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
     }
   return(status);
@@ -4290,8 +4015,7 @@ MagickExport MagickBooleanType PersistPixelCache(Image *image,
       (cache_info->reference_count == 1))
     {
       LockSemaphoreInfo(cache_info->semaphore);
-      if ((cache_info->mode != ReadMode) &&
-          (cache_info->type != MemoryCache) &&
+      if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
           (cache_info->reference_count == 1))
         {
           int
@@ -4300,7 +4024,7 @@ MagickExport MagickBooleanType PersistPixelCache(Image *image,
           /*
             Usurp existing persistent pixel cache.
           */
-          status=rename(cache_info->cache_filename,filename);
+          status=rename_utf8(cache_info->cache_filename,filename);
           if (status == 0)
             {
               (void) CopyMagickString(cache_info->cache_filename,filename,
@@ -4330,7 +4054,7 @@ MagickExport MagickBooleanType PersistPixelCache(Image *image,
   cache_info=(CacheInfo *) image->cache;
   status=OpenPixelCache(image,IOMode,exception);
   if (status != MagickFalse)
-    status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
+    status=ClonePixelCachePixels(cache_info,clone_info,exception);
   *offset+=cache_info->length+page_size-(cache_info->length % page_size);
   clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
   return(status);
@@ -4341,23 +4065,24 @@ MagickExport MagickBooleanType PersistPixelCache(Image *image,
 %                                                                             %
 %                                                                             %
 %                                                                             %
-+   Q u e u e A u t h e n t i c N e x u s                                     %
++   Q u e u e A u t h e n t i c P i x e l C a c h e N e x u s                 %
 %                                                                             %
 %                                                                             %
 %                                                                             %
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
-%  QueueAuthenticNexus() allocates an region to store image pixels as defined
-%  by the region rectangle and returns a pointer to the region.  This region is
-%  subsequently transferred from the pixel cache with
+%  QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
+%  defined by the region rectangle and returns a pointer to the region.  This
+%  region is subsequently transferred from the pixel cache with
 %  SyncAuthenticPixelsCache().  A pointer to the pixels is returned if the
 %  pixels are transferred, otherwise a NULL is returned.
 %
-%  The format of the QueueAuthenticNexus() method is:
+%  The format of the QueueAuthenticPixelCacheNexus() method is:
 %
-%      Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
+%      Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
 %        const ssize_t y,const size_t columns,const size_t rows,
-%        NexusInfo *nexus_info,ExceptionInfo *exception)
+%        const MagickBooleanType clone,NexusInfo *nexus_info,
+%        ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
@@ -4368,12 +4093,14 @@ MagickExport MagickBooleanType PersistPixelCache(Image *image,
 %
 %    o nexus_info: the cache nexus to set.
 %
+%    o clone: clone the pixel cache.
+%
 %    o exception: return any errors or warnings in this structure.
 %
 */
-MagickExport Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
-  const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
-  ExceptionInfo *exception)
+MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
+  const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
+  const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
 {
   CacheInfo
     *cache_info;
@@ -4393,10 +4120,10 @@ MagickExport Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
   assert(image != (const Image *) NULL);
   assert(image->signature == MagickSignature);
   assert(image->cache != (Cache) NULL);
-  cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
-  assert(cache_info->signature == MagickSignature);
+  cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
   if (cache_info == (Cache) NULL)
     return((Quantum *) NULL);
+  assert(cache_info->signature == MagickSignature);
   if ((cache_info->columns == 0) && (cache_info->rows == 0))
     {
       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
@@ -4471,7 +4198,7 @@ static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
     id = GetOpenMPThreadId();
 
   Quantum
-    *pixels;
+    *q;
 
   assert(image != (const Image *) NULL);
   assert(image->signature == MagickSignature);
@@ -4479,9 +4206,9 @@ static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
   cache_info=(CacheInfo *) image->cache;
   assert(cache_info->signature == MagickSignature);
   assert(id < (int) cache_info->number_threads);
-  pixels=QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
-    exception);
-  return(pixels);
+  q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
+    cache_info->nexus_info[id],exception);
+  return(q);
 }
 \f
 /*
@@ -4551,7 +4278,7 @@ MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
     id = GetOpenMPThreadId();
 
   Quantum
-    *pixels;
+    *q;
 
   assert(image != (Image *) NULL);
   assert(image->signature == MagickSignature);
@@ -4559,16 +4286,16 @@ MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
   cache_info=(CacheInfo *) image->cache;
   assert(cache_info->signature == MagickSignature);
   if (cache_info->methods.queue_authentic_pixels_handler !=
-       (QueueAuthenticPixelsHandler) NULL)
+      (QueueAuthenticPixelsHandler) NULL)
     {
-      pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
-        columns,rows,exception);
-      return(pixels);
+      q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
+        rows,exception);
+      return(q);
     }
   assert(id < (int) cache_info->number_threads);
-  pixels=QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
-    exception);
-  return(pixels);
+  q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
+    cache_info->nexus_info[id],exception);
+  return(q);
 }
 \f
 /*
@@ -4678,13 +4405,15 @@ static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
       for (y=0; y < (ssize_t) rows; y++)
       {
         count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
-          cache_info->pixel_components*sizeof(Quantum)+offset*
+          cache_info->number_channels*sizeof(Quantum)+offset*
           cache_info->metacontent_extent,length,(unsigned char *) q);
         if ((MagickSizeType) count != length)
           break;
         offset+=cache_info->columns;
         q+=cache_info->metacontent_extent*nexus_info->region.width;
       }
+      if (IsFileDescriptorLimitExceeded() != MagickFalse)
+        (void) ClosePixelCacheOnDisk(cache_info);
       if (y < (ssize_t) rows)
         {
           ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
@@ -4757,7 +4486,7 @@ static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
     return(MagickTrue);
   offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
     nexus_info->region.x;
-  length=(MagickSizeType) nexus_info->region.width*cache_info->pixel_components*
+  length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
     sizeof(Quantum);
   rows=nexus_info->region.height;
   extent=length*rows;
@@ -4779,12 +4508,12 @@ static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
           length=extent;
           rows=1UL;
         }
-      p=cache_info->pixels+offset*cache_info->pixel_components;
+      p=cache_info->pixels+offset*cache_info->number_channels;
       for (y=0; y < (ssize_t) rows; y++)
       {
         (void) memcpy(q,p,(size_t) length);
-        p+=cache_info->pixel_components*cache_info->columns;
-        q+=cache_info->pixel_components*nexus_info->region.width;
+        p+=cache_info->number_channels*cache_info->columns;
+        q+=cache_info->number_channels*nexus_info->region.width;
       }
       break;
     }
@@ -4808,12 +4537,14 @@ static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
       for (y=0; y < (ssize_t) rows; y++)
       {
         count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
-          cache_info->pixel_components*sizeof(*q),length,(unsigned char *) q);
+          cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
         if ((MagickSizeType) count != length)
           break;
         offset+=cache_info->columns;
-        q+=cache_info->pixel_components*nexus_info->region.width;
+        q+=cache_info->number_channels*nexus_info->region.width;
       }
+      if (IsFileDescriptorLimitExceeded() != MagickFalse)
+        (void) ClosePixelCacheOnDisk(cache_info);
       if (y < (ssize_t) rows)
         {
           ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
@@ -4857,7 +4588,7 @@ static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
 %    o cache_info: the pixel cache.
 %
 */
-MagickExport Cache ReferencePixelCache(Cache cache)
+MagickPrivate Cache ReferencePixelCache(Cache cache)
 {
   CacheInfo
     *cache_info;
@@ -4895,7 +4626,7 @@ MagickExport Cache ReferencePixelCache(Cache cache)
 %    o cache_methods: Specifies a pointer to a CacheMethods structure.
 %
 */
-MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
+MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
 {
   CacheInfo
     *cache_info;
@@ -5035,8 +4766,7 @@ static Quantum *SetPixelCacheNexusPixels(const Image *image,
   if (cache_info->type == UndefinedCache)
     return((Quantum *) NULL);
   nexus_info->region=(*region);
-  if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
-      (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
+  if ((cache_info->type != DiskCache) && (cache_info->type != PingCache))
     {
       ssize_t
         x,
@@ -5058,7 +4788,7 @@ static Quantum *SetPixelCacheNexusPixels(const Image *image,
           */
           offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
             nexus_info->region.x;
-          nexus_info->pixels=cache_info->pixels+cache_info->pixel_components*
+          nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
             offset;
           nexus_info->metacontent=(void *) NULL;
           if (cache_info->metacontent_extent != 0)
@@ -5072,7 +4802,7 @@ static Quantum *SetPixelCacheNexusPixels(const Image *image,
   */
   number_pixels=(MagickSizeType) nexus_info->region.width*
     nexus_info->region.height;
-  length=number_pixels*cache_info->pixel_components*sizeof(Quantum);
+  length=number_pixels*cache_info->number_channels*sizeof(Quantum);
   if (cache_info->metacontent_extent != 0)
     length+=number_pixels*cache_info->metacontent_extent;
   if (nexus_info->cache == (Quantum *) NULL)
@@ -5101,7 +4831,7 @@ static Quantum *SetPixelCacheNexusPixels(const Image *image,
   nexus_info->metacontent=(void *) NULL;
   if (cache_info->metacontent_extent != 0)
     nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
-      cache_info->pixel_components);
+      cache_info->number_channels);
   return(nexus_info->pixels);
 }
 \f
@@ -5122,8 +4852,8 @@ static Quantum *SetPixelCacheNexusPixels(const Image *image,
 %
 %  The format of the SetPixelCacheVirtualMethod() method is:
 %
-%      VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
-%        const VirtualPixelMethod virtual_pixel_method)
+%      VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
+%        const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
@@ -5131,9 +4861,67 @@ static Quantum *SetPixelCacheNexusPixels(const Image *image,
 %
 %    o virtual_pixel_method: choose the type of virtual pixel.
 %
+%    o exception: return any errors or warnings in this structure.
+%
 */
-MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
-  const VirtualPixelMethod virtual_pixel_method)
+
+static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
+  ExceptionInfo *exception)
+{
+  CacheView
+    *image_view;
+
+  CacheInfo
+    *cache_info;
+
+  MagickBooleanType
+    status;
+
+  ssize_t
+    y;
+
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(image->cache != (Cache) NULL);
+  cache_info=(CacheInfo *) image->cache;
+  assert(cache_info->signature == MagickSignature);
+  image->matte=MagickTrue;
+  status=MagickTrue;
+  image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(static,4) shared(status)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register Quantum
+      *restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      SetPixelAlpha(image,alpha,q);
+      q+=GetPixelChannels(image);
+    }
+    status=SyncCacheViewAuthenticPixels(image_view,exception);
+  }
+  image_view=DestroyCacheView(image_view);
+  return(status);
+}
+
+MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
+  const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
 {
   CacheInfo
     *cache_info;
@@ -5150,6 +4938,24 @@ MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
   assert(cache_info->signature == MagickSignature);
   method=cache_info->virtual_pixel_method;
   cache_info->virtual_pixel_method=virtual_pixel_method;
+  switch (virtual_pixel_method)
+  {
+    case BackgroundVirtualPixelMethod:
+    {
+      if ((image->background_color.matte != MagickFalse) &&
+          (image->matte == MagickFalse))
+        (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
+      break;
+    }
+    case TransparentVirtualPixelMethod:
+    {
+      if (image->matte == MagickFalse)
+        (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
+      break;
+    }
+    default:
+      break;
+  }
   return(method);
 }
 \f
@@ -5182,7 +4988,7 @@ MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
 %    o exception: return any errors or warnings in this structure.
 %
 */
-MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
+MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
   NexusInfo *nexus_info,ExceptionInfo *exception)
 {
   CacheInfo
@@ -5202,12 +5008,6 @@ MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
   assert(cache_info->signature == MagickSignature);
   if (cache_info->type == UndefinedCache)
     return(MagickFalse);
-  if ((image->clip_mask != (Image *) NULL) &&
-      (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
-    return(MagickFalse);
-  if ((image->mask != (Image *) NULL) &&
-      (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
-    return(MagickFalse);
   if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
     return(MagickTrue);
   assert(cache_info->signature == MagickSignature);
@@ -5330,6 +5130,45 @@ MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
 %                                                                             %
 %                                                                             %
 %                                                                             %
++   S y n c I m a g e P i x e l C a c h e                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
+%  The method returns MagickTrue if the pixel region is flushed, otherwise
+%  MagickFalse.
+%
+%  The format of the SyncImagePixelCache() method is:
+%
+%      MagickBooleanType SyncImagePixelCache(Image *image,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o exception: return any errors or warnings in this structure.
+%
+*/
+MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
+  ExceptionInfo *exception)
+{
+  CacheInfo
+    *cache_info;
+
+  assert(image != (Image *) NULL);
+  assert(exception != (ExceptionInfo *) NULL);
+  cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
+  return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
 +   W r i t e P i x e l C a c h e M e t a c o n t e n t                       %
 %                                                                             %
 %                                                                             %
@@ -5432,13 +5271,15 @@ static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
       for (y=0; y < (ssize_t) rows; y++)
       {
         count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
-          cache_info->pixel_components*sizeof(Quantum)+offset*
+          cache_info->number_channels*sizeof(Quantum)+offset*
           cache_info->metacontent_extent,length,(const unsigned char *) p);
         if ((MagickSizeType) count != length)
           break;
         p+=nexus_info->region.width*cache_info->metacontent_extent;
         offset+=cache_info->columns;
       }
+      if (IsFileDescriptorLimitExceeded() != MagickFalse)
+        (void) ClosePixelCacheOnDisk(cache_info);
       if (y < (ssize_t) rows)
         {
           ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
@@ -5511,7 +5352,7 @@ static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
     return(MagickTrue);
   offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
     nexus_info->region.x;
-  length=(MagickSizeType) nexus_info->region.width*cache_info->pixel_components*
+  length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
     sizeof(Quantum);
   rows=nexus_info->region.height;
   extent=length*rows;
@@ -5533,12 +5374,12 @@ static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
           length=extent;
           rows=1UL;
         }
-      q=cache_info->pixels+offset*cache_info->pixel_components;
+      q=cache_info->pixels+offset*cache_info->number_channels;
       for (y=0; y < (ssize_t) rows; y++)
       {
         (void) memcpy(q,p,(size_t) length);
-        p+=nexus_info->region.width*cache_info->pixel_components;
-        q+=cache_info->columns*cache_info->pixel_components;
+        p+=nexus_info->region.width*cache_info->number_channels;
+        q+=cache_info->columns*cache_info->number_channels;
       }
       break;
     }
@@ -5562,13 +5403,15 @@ static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
       for (y=0; y < (ssize_t) rows; y++)
       {
         count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
-          cache_info->pixel_components*sizeof(*p),length,(const unsigned char *)
+          cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
           p);
         if ((MagickSizeType) count != length)
           break;
-        p+=nexus_info->region.width*cache_info->pixel_components;
+        p+=nexus_info->region.width*cache_info->number_channels;
         offset+=cache_info->columns;
       }
+      if (IsFileDescriptorLimitExceeded() != MagickFalse)
+        (void) ClosePixelCacheOnDisk(cache_info);
       if (y < (ssize_t) rows)
         {
           ThrowFileException(exception,CacheError,"UnableToWritePixelCache",