]> granicus.if.org Git - imagemagick/blobdiff - MagickCore/cache.c
(no commit message)
[imagemagick] / MagickCore / cache.c
index 8f02a6dca3785f573879d1fe8bbe914442db5c2f..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"
@@ -75,6 +76,8 @@
   Define declarations.
 */
 #define CacheTick(offset,extent)  QuantumTick((MagickOffsetType) offset,extent)
+#define IsFileDescriptorLimitExceeded() (GetMagickResource(FileResource) > \
+  GetMagickResourceLimit(FileResource) ? MagickTrue : MagickFalse)
 \f
 /*
   Typedef declarations.
@@ -115,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 *),
@@ -125,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 *),
@@ -141,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)
 }
@@ -155,9 +162,6 @@ static volatile MagickBooleanType
 
 static SemaphoreInfo
   *cache_semaphore = (SemaphoreInfo *) NULL;
-
-static SplayTreeInfo
-  *cache_resources = (SplayTreeInfo *) NULL;
 \f
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -206,22 +210,6 @@ MagickPrivate 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
@@ -255,16 +243,18 @@ MagickPrivate 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);
@@ -365,8 +355,6 @@ 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);
@@ -377,106 +365,6 @@ MagickPrivate 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+=GetPixelChannels(image);
-    q+=GetPixelChannels(image);
-    r+=GetPixelChannels(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                                             %
 %                                                                             %
 %                                                                             %
@@ -560,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)
 {
@@ -634,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
@@ -670,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);
@@ -836,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
@@ -907,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
@@ -921,6 +766,9 @@ static MagickBooleanType UnoptimizedPixelCacheClone(CacheInfo *clone_info,
   register ssize_t
     x;
 
+  register unsigned char
+    *p;
+
   size_t
     length;
 
@@ -973,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);
@@ -994,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->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;
@@ -1017,24 +860,42 @@ 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->number_channels*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->number_channels*sizeof(Quantum);
@@ -1042,7 +903,7 @@ static MagickBooleanType UnoptimizedPixelCacheClone(CacheInfo *clone_info,
     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,
@@ -1064,7 +925,7 @@ static MagickBooleanType UnoptimizedPixelCacheClone(CacheInfo *clone_info,
   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,7 +997,7 @@ 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,
@@ -1160,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++)
         {
@@ -1191,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->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
 /*
@@ -1397,8 +1263,6 @@ MagickPrivate 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
@@ -1483,9 +1347,9 @@ MagickPrivate 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
@@ -1656,7 +1520,8 @@ MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
   */
   assert(image != (Image *) NULL);
   assert(image->signature == MagickSignature);
-  q=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
+  q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,nexus_info,
+    exception);
   if (q == (Quantum *) NULL)
     return((Quantum *) NULL);
   cache_info=(CacheInfo *) image->cache;
@@ -1964,16 +1829,24 @@ 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->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()))
@@ -2081,7 +1954,12 @@ static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
       image->taint=MagickTrue;
       image->type=UndefinedType;
       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)
@@ -2106,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:
 %
@@ -2120,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;
@@ -2128,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
@@ -2162,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:
@@ -2177,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;
@@ -2188,18 +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);
+    {
+      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
@@ -2208,36 +2120,34 @@ static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
 %                                                                             %
 %                                                                             %
 %                                                                             %
-%   G e t O n e V i r t u a l M a g i c k P i x e l                           %
+%   G e t O n e V i r t u a l 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.
+%  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 GetOneVirtualMagickPixel() method is:
+%  The format of the GetOneVirtualPixel() method is:
 %
-%      MagickBooleanType GetOneVirtualMagickPixel(const Image image,
-%        const ssize_t x,const ssize_t y,PixelInfo *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 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.
 %
 */
-MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
-  const ssize_t x,const ssize_t y,PixelInfo *pixel,
-  ExceptionInfo *exception)
+MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
+  const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
 {
   CacheInfo
     *cache_info;
@@ -2245,21 +2155,42 @@ MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
   const int
     id = GetOpenMPThreadId();
 
-  register const Quantum
+  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);
+  (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,
+      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);
-  GetPixelInfo(image,pixel);
   if (p == (const Quantum *) NULL)
-    return(MagickFalse);
-  SetPixelInfo(image,p,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]=p[i];
+  }
   return(MagickTrue);
 }
 \f
@@ -2268,22 +2199,21 @@ 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 F r o m C a c h e                     %
 %                                                                             %
 %                                                                             %
 %                                                                             %
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
-%  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.
+%  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 GetOneVirtualMethodPixel() method is:
+%  The format of the GetOneVirtualPixelFromCache() 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 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:
 %
@@ -2298,9 +2228,9 @@ MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
 %    o exception: return any errors or warnings in this structure.
 %
 */
-MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
+static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
   const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
-  PixelPacket *pixel,ExceptionInfo *exception)
+  Quantum *pixel,ExceptionInfo *exception)
 {
   CacheInfo
     *cache_info;
@@ -2311,88 +2241,35 @@ 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;
-  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));
   assert(id < (int) cache_info->number_threads);
+  (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);
-  return(MagickTrue);
-}
-\f
-/*
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%                                                                             %
-%                                                                             %
-%                                                                             %
-%   G e t O n e V i r t u a l P i x e l                                       %
-%                                                                             %
-%                                                                             %
-%                                                                             %
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%
-%  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 GetOneVirtualPixel() method is:
-%
-%      MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
-%        const ssize_t y,PixelPacket *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 GetOneVirtualPixel(const Image *image,
-  const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
-{
-  CacheInfo
-    *cache_info;
-
-  const int
-    id = GetOpenMPThreadId();
-
-  const Quantum
-    *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;
 
-  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);
-  if (p == (const Quantum *) NULL)
-    return(MagickFalse);
-  GetPixelPacket(image,p,pixel);
-  if (image->colorspace == CMYKColorspace)
-    pixel->black=GetPixelBlack(image,p);
+    channel=GetPixelChannelMapChannel(image,i);
+    pixel[channel]=p[i];
+  }
   return(MagickTrue);
 }
 \f
@@ -2401,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:
 %
@@ -2423,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;
@@ -2440,7 +2317,7 @@ static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
   const int
     id = GetOpenMPThreadId();
 
-  const Quantum
+  register const Quantum
     *p;
 
   assert(image != (const Image *) NULL);
@@ -2449,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
@@ -2989,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]);
@@ -3146,7 +3017,7 @@ MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
 
   Quantum
     *pixels,
-    virtual_pixel[MaxPixelChannels];
+    virtual_pixel[CompositePixelChannel];
 
   RectangleInfo
     region;
@@ -3299,12 +3170,16 @@ MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
         }
         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);
-          if (image->colorspace == CMYKColorspace)
-            SetPixelBlack(image,image->background_color.black,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;
         }
       }
@@ -3764,135 +3639,6 @@ MagickPrivate 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 (fabs(alpha-TransparentAlpha) < MagickEpsilon)
-    {
-      *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                                               %
 %                                                                             %
 %                                                                             %
@@ -4005,10 +3751,13 @@ static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
   cache_info->storage_class=image->storage_class;
   cache_info->colorspace=image->colorspace;
   cache_info->matte=image->matte;
+  cache_info->mask=image->mask;
   cache_info->rows=image->rows;
   cache_info->columns=image->columns;
   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)
@@ -4029,22 +3778,6 @@ 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->number_channels <= source_info.number_channels) &&
-      (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->number_channels == source_info.number_channels) &&
-          (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->number_channels*sizeof(Quantum)+
     cache_info->metacontent_extent);
@@ -4065,8 +3798,7 @@ 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 ?
@@ -4081,7 +3813,8 @@ static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
               if (cache_info->metacontent_extent != 0)
                 cache_info->metacontent=(void *) (cache_info->pixels+
                   number_pixels*cache_info->number_channels);
-              if (source_info.storage_class != UndefinedClass)
+              if ((source_info.storage_class != UndefinedClass) &&
+                  (mode != ReadMode))
                 {
                   status=ClonePixelCachePixels(cache_info,&source_info,
                     exception);
@@ -4102,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);
@@ -4119,8 +3857,7 @@ static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
     }
   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
     {
@@ -4150,7 +3887,8 @@ static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
               if (cache_info->metacontent_extent != 0)
                 cache_info->metacontent=(void *) (cache_info->pixels+
                   number_pixels*cache_info->number_channels);
-              if (source_info.storage_class != UndefinedClass)
+              if ((source_info.storage_class != UndefinedClass) &&
+                  (mode != ReadMode))
                 {
                   status=ClonePixelCachePixels(cache_info,&source_info,
                     exception);
@@ -4158,8 +3896,7 @@ 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,
@@ -4175,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);
@@ -4287,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,
@@ -4317,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);
@@ -4328,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:
 %
@@ -4355,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.
 %
 */
-MagickPrivate 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;
@@ -4380,7 +4120,7 @@ MagickPrivate 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);
+  cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
   if (cache_info == (Cache) NULL)
     return((Quantum *) NULL);
   assert(cache_info->signature == MagickSignature);
@@ -4466,8 +4206,8 @@ 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);
-  q=QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
-    exception);
+  q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
+    cache_info->nexus_info[id],exception);
   return(q);
 }
 \f
@@ -4546,15 +4286,15 @@ 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)
     {
-      q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
-        columns,rows,exception);
+      q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
+        rows,exception);
       return(q);
     }
   assert(id < (int) cache_info->number_threads);
-  q=QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
-    exception);
+  q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
+    cache_info->nexus_info[id],exception);
   return(q);
 }
 \f
@@ -4672,6 +4412,8 @@ static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
         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",
@@ -4801,6 +4543,8 @@ static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
         offset+=cache_info->columns;
         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",
@@ -4986,7 +4730,7 @@ static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
   if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
     return(MagickFalse);
   nexus_info->mapped=MagickFalse;
-  nexus_info->cache=(Quantum *) AcquireQuantumMemory(1,(size_t)
+  nexus_info->cache=(Quantum *) AcquireMagickMemory((size_t)
     nexus_info->length);
   if (nexus_info->cache == (Quantum *) NULL)
     {
@@ -5022,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,
@@ -5109,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:
 %
@@ -5118,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.
+%
 */
-MagickPrivate 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;
@@ -5137,6 +4938,24 @@ MagickPrivate 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
@@ -5189,12 +5008,6 @@ MagickPrivate 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);
@@ -5465,6 +5278,8 @@ static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
         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",
@@ -5595,6 +5410,8 @@ static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
         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",