MagickCore  6.7.5
cache.c
Go to the documentation of this file.
00001 /*
00002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00003 %                                                                             %
00004 %                                                                             %
00005 %                                                                             %
00006 %                      CCCC   AAA    CCCC  H   H  EEEEE                       %
00007 %                     C      A   A  C      H   H  E                           %
00008 %                     C      AAAAA  C      HHHHH  EEE                         %
00009 %                     C      A   A  C      H   H  E                           %
00010 %                      CCCC  A   A   CCCC  H   H  EEEEE                       %
00011 %                                                                             %
00012 %                                                                             %
00013 %                       MagickCore Pixel Cache Methods                        %
00014 %                                                                             %
00015 %                              Software Design                                %
00016 %                                John Cristy                                  %
00017 %                                 July 1999                                   %
00018 %                                                                             %
00019 %                                                                             %
00020 %  Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization      %
00021 %  dedicated to making software imaging solutions freely available.           %
00022 %                                                                             %
00023 %  You may not use this file except in compliance with the License.  You may  %
00024 %  obtain a copy of the License at                                            %
00025 %                                                                             %
00026 %    http://www.imagemagick.org/script/license.php                            %
00027 %                                                                             %
00028 %  Unless required by applicable law or agreed to in writing, software        %
00029 %  distributed under the License is distributed on an "AS IS" BASIS,          %
00030 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
00031 %  See the License for the specific language governing permissions and        %
00032 %  limitations under the License.                                             %
00033 %                                                                             %
00034 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00035 %
00036 %
00037 %
00038 */
00039 
00040 /*
00041   Include declarations.
00042 */
00043 #include "MagickCore/studio.h"
00044 #include "MagickCore/blob.h"
00045 #include "MagickCore/blob-private.h"
00046 #include "MagickCore/cache.h"
00047 #include "MagickCore/cache-private.h"
00048 #include "MagickCore/color-private.h"
00049 #include "MagickCore/composite-private.h"
00050 #include "MagickCore/exception.h"
00051 #include "MagickCore/exception-private.h"
00052 #include "MagickCore/geometry.h"
00053 #include "MagickCore/list.h"
00054 #include "MagickCore/log.h"
00055 #include "MagickCore/magick.h"
00056 #include "MagickCore/memory_.h"
00057 #include "MagickCore/pixel.h"
00058 #include "MagickCore/pixel-accessor.h"
00059 #include "MagickCore/policy.h"
00060 #include "MagickCore/quantum.h"
00061 #include "MagickCore/random_.h"
00062 #include "MagickCore/resource_.h"
00063 #include "MagickCore/semaphore.h"
00064 #include "MagickCore/splay-tree.h"
00065 #include "MagickCore/string_.h"
00066 #include "MagickCore/string-private.h"
00067 #include "MagickCore/thread-private.h"
00068 #include "MagickCore/utility.h"
00069 #include "MagickCore/utility-private.h"
00070 #if defined(MAGICKCORE_ZLIB_DELEGATE)
00071 #include "zlib.h"
00072 #endif
00073 
00074 /*
00075   Define declarations.
00076 */
00077 #define CacheTick(offset,extent)  QuantumTick((MagickOffsetType) offset,extent)
00078 #define IsFileDescriptorLimitExceeded() (GetMagickResource(FileResource) > \
00079   GetMagickResourceLimit(FileResource) ? MagickTrue : MagickFalse)
00080 
00081 /*
00082   Typedef declarations.
00083 */
00084 typedef struct _MagickModulo
00085 {
00086   ssize_t
00087     quotient,
00088     remainder;
00089 } MagickModulo;
00090 
00091 struct _NexusInfo
00092 {
00093   MagickBooleanType
00094     mapped;
00095 
00096   RectangleInfo
00097     region;
00098 
00099   MagickSizeType
00100     length;
00101 
00102   Quantum
00103     *cache,
00104     *pixels;
00105 
00106   void
00107     *metacontent;
00108 
00109   size_t
00110     signature;
00111 };
00112 
00113 /*
00114   Forward declarations.
00115 */
00116 #if defined(__cplusplus) || defined(c_plusplus)
00117 extern "C" {
00118 #endif
00119 
00120 static const Quantum
00121   *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
00122     const ssize_t,const size_t,const size_t,ExceptionInfo *),
00123   *GetVirtualPixelsCache(const Image *);
00124 
00125 static const void
00126   *GetVirtualMetacontentFromCache(const Image *);
00127 
00128 static MagickBooleanType
00129   GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,
00130     Quantum *,ExceptionInfo *),
00131   GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
00132     const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
00133   OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
00134   ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
00135   ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
00136   SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
00137   WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
00138   WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
00139 
00140 static Quantum
00141   *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
00142     const size_t,ExceptionInfo *),
00143   *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
00144     const size_t,ExceptionInfo *),
00145   *SetPixelCacheNexusPixels(const Image *,const RectangleInfo *,NexusInfo *,
00146     ExceptionInfo *);
00147 
00148 #if defined(__cplusplus) || defined(c_plusplus)
00149 }
00150 #endif
00151 
00152 /*
00153   Global declarations.
00154 */
00155 static volatile MagickBooleanType
00156   instantiate_cache = MagickFalse;
00157 
00158 static SemaphoreInfo
00159   *cache_semaphore = (SemaphoreInfo *) NULL;
00160 
00161 /*
00162 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00163 %                                                                             %
00164 %                                                                             %
00165 %                                                                             %
00166 +   A c q u i r e P i x e l C a c h e                                         %
00167 %                                                                             %
00168 %                                                                             %
00169 %                                                                             %
00170 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00171 %
00172 %  AcquirePixelCache() acquires a pixel cache.
00173 %
00174 %  The format of the AcquirePixelCache() method is:
00175 %
00176 %      Cache AcquirePixelCache(const size_t number_threads)
00177 %
00178 %  A description of each parameter follows:
00179 %
00180 %    o number_threads: the number of nexus threads.
00181 %
00182 */
00183 MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
00184 {
00185   CacheInfo
00186     *cache_info;
00187 
00188   cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
00189   if (cache_info == (CacheInfo *) NULL)
00190     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
00191   (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
00192   cache_info->type=UndefinedCache;
00193   cache_info->mode=IOMode;
00194   cache_info->colorspace=RGBColorspace;
00195   cache_info->file=(-1);
00196   cache_info->id=GetMagickThreadId();
00197   cache_info->number_threads=number_threads;
00198   if (number_threads == 0)
00199     cache_info->number_threads=GetOpenMPMaximumThreads();
00200   cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
00201   if (cache_info->nexus_info == (NexusInfo **) NULL)
00202     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
00203   cache_info->semaphore=AllocateSemaphoreInfo();
00204   cache_info->reference_count=1;
00205   cache_info->disk_semaphore=AllocateSemaphoreInfo();
00206   cache_info->debug=IsEventLogging();
00207   cache_info->signature=MagickSignature;
00208   return((Cache ) cache_info);
00209 }
00210 
00211 /*
00212 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00213 %                                                                             %
00214 %                                                                             %
00215 %                                                                             %
00216 %   A c q u i r e P i x e l C a c h e N e x u s                               %
00217 %                                                                             %
00218 %                                                                             %
00219 %                                                                             %
00220 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00221 %
00222 %  AcquirePixelCacheNexus() allocates the NexusInfo structure.
00223 %
00224 %  The format of the AcquirePixelCacheNexus method is:
00225 %
00226 %      NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
00227 %
00228 %  A description of each parameter follows:
00229 %
00230 %    o number_threads: the number of nexus threads.
00231 %
00232 */
00233 MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
00234 {
00235   NexusInfo
00236     **nexus_info;
00237 
00238   register ssize_t
00239     i;
00240 
00241   nexus_info=(NexusInfo **) AcquireQuantumMemory(number_threads,
00242     sizeof(*nexus_info));
00243   if (nexus_info == (NexusInfo **) NULL)
00244     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
00245   for (i=0; i < (ssize_t) number_threads; i++)
00246   {
00247     nexus_info[i]=(NexusInfo *) AcquireQuantumMemory(1,sizeof(**nexus_info));
00248     if (nexus_info[i] == (NexusInfo *) NULL)
00249       ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
00250     (void) ResetMagickMemory(nexus_info[i],0,sizeof(*nexus_info[i]));
00251     nexus_info[i]->signature=MagickSignature;
00252   }
00253   return(nexus_info);
00254 }
00255 
00256 /*
00257 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00258 %                                                                             %
00259 %                                                                             %
00260 %                                                                             %
00261 +   A c q u i r e P i x e l C a c h e P i x e l s                             %
00262 %                                                                             %
00263 %                                                                             %
00264 %                                                                             %
00265 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00266 %
00267 %  AcquirePixelCachePixels() returns the pixels associated with the specified
00268 %  image.
00269 %
00270 %  The format of the AcquirePixelCachePixels() method is:
00271 %
00272 %      const void *AcquirePixelCachePixels(const Image *image,
00273 %        MagickSizeType *length,ExceptionInfo *exception)
00274 %
00275 %  A description of each parameter follows:
00276 %
00277 %    o image: the image.
00278 %
00279 %    o length: the pixel cache length.
00280 %
00281 %    o exception: return any errors or warnings in this structure.
00282 %
00283 */
00284 MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
00285   MagickSizeType *length,ExceptionInfo *exception)
00286 {
00287   CacheInfo
00288     *cache_info;
00289 
00290   assert(image != (const Image *) NULL);
00291   assert(image->signature == MagickSignature);
00292   assert(exception != (ExceptionInfo *) NULL);
00293   assert(exception->signature == MagickSignature);
00294   assert(image->cache != (Cache) NULL);
00295   cache_info=(CacheInfo *) image->cache;
00296   assert(cache_info->signature == MagickSignature);
00297   *length=0;
00298   if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
00299     return((const void *) NULL);
00300   *length=cache_info->length;
00301   return((const void *) cache_info->pixels);
00302 }
00303 
00304 /*
00305 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00306 %                                                                             %
00307 %                                                                             %
00308 %                                                                             %
00309 +   C a c h e C o m p o n e n t G e n e s i s                                 %
00310 %                                                                             %
00311 %                                                                             %
00312 %                                                                             %
00313 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00314 %
00315 %  CacheComponentGenesis() instantiates the cache component.
00316 %
00317 %  The format of the CacheComponentGenesis method is:
00318 %
00319 %      MagickBooleanType CacheComponentGenesis(void)
00320 %
00321 */
00322 MagickPrivate MagickBooleanType CacheComponentGenesis(void)
00323 {
00324   AcquireSemaphoreInfo(&cache_semaphore);
00325   return(MagickTrue);
00326 }
00327 
00328 /*
00329 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00330 %                                                                             %
00331 %                                                                             %
00332 %                                                                             %
00333 +   C a c h e C o m p o n e n t T e r m i n u s                               %
00334 %                                                                             %
00335 %                                                                             %
00336 %                                                                             %
00337 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00338 %
00339 %  CacheComponentTerminus() destroys the cache component.
00340 %
00341 %  The format of the CacheComponentTerminus() method is:
00342 %
00343 %      CacheComponentTerminus(void)
00344 %
00345 */
00346 MagickPrivate void CacheComponentTerminus(void)
00347 {
00348   if (cache_semaphore == (SemaphoreInfo *) NULL)
00349     AcquireSemaphoreInfo(&cache_semaphore);
00350   LockSemaphoreInfo(cache_semaphore);
00351   instantiate_cache=MagickFalse;
00352   UnlockSemaphoreInfo(cache_semaphore);
00353   DestroySemaphoreInfo(&cache_semaphore);
00354 }
00355 
00356 /*
00357 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00358 %                                                                             %
00359 %                                                                             %
00360 %                                                                             %
00361 +   C l o n e P i x e l C a c h e                                             %
00362 %                                                                             %
00363 %                                                                             %
00364 %                                                                             %
00365 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00366 %
00367 %  ClonePixelCache() clones a pixel cache.
00368 %
00369 %  The format of the ClonePixelCache() method is:
00370 %
00371 %      Cache ClonePixelCache(const Cache cache)
00372 %
00373 %  A description of each parameter follows:
00374 %
00375 %    o cache: the pixel cache.
00376 %
00377 */
00378 MagickPrivate Cache ClonePixelCache(const Cache cache)
00379 {
00380   CacheInfo
00381     *clone_info;
00382 
00383   const CacheInfo
00384     *cache_info;
00385 
00386   assert(cache != NULL);
00387   cache_info=(const CacheInfo *) cache;
00388   assert(cache_info->signature == MagickSignature);
00389   if (cache_info->debug != MagickFalse)
00390     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
00391       cache_info->filename);
00392   clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
00393   if (clone_info == (Cache) NULL)
00394     return((Cache) NULL);
00395   clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
00396   return((Cache ) clone_info);
00397 }
00398 
00399 /*
00400 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00401 %                                                                             %
00402 %                                                                             %
00403 %                                                                             %
00404 +   C l o n e P i x e l C a c h e P i x e l s                                 %
00405 %                                                                             %
00406 %                                                                             %
00407 %                                                                             %
00408 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
00409 %  ClonePixelCachePixels() clones the source pixel cache to the destination
00410 %  cache.
00411 %
00412 %  The format of the ClonePixelCachePixels() method is:
00413 %
00414 %      MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
00415 %        CacheInfo *source_info,ExceptionInfo *exception)
00416 %
00417 %  A description of each parameter follows:
00418 %
00419 %    o cache_info: the pixel cache.
00420 %
00421 %    o source_info: the source pixel cache.
00422 %
00423 %    o exception: return any errors or warnings in this structure.
00424 %
00425 */
00426 
00427 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
00428 {
00429   int
00430     status;
00431 
00432   status=(-1);
00433   LockSemaphoreInfo(cache_info->disk_semaphore);
00434   if (cache_info->file != -1)
00435     {
00436       status=close(cache_info->file);
00437       cache_info->file=(-1);
00438       RelinquishMagickResource(FileResource,1);
00439     }
00440   UnlockSemaphoreInfo(cache_info->disk_semaphore);
00441   return(status == -1 ? MagickFalse : MagickTrue);
00442 }
00443 
00444 static inline MagickSizeType MagickMax(const MagickSizeType x,
00445   const MagickSizeType y)
00446 {
00447   if (x > y)
00448     return(x);
00449   return(y);
00450 }
00451 
00452 static inline MagickSizeType MagickMin(const MagickSizeType x,
00453   const MagickSizeType y)
00454 {
00455   if (x < y)
00456     return(x);
00457   return(y);
00458 }
00459 
00460 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
00461   const MapMode mode)
00462 {
00463   int
00464     file;
00465 
00466   /*
00467     Open pixel cache on disk.
00468   */
00469   LockSemaphoreInfo(cache_info->disk_semaphore);
00470   if (cache_info->file != -1)
00471     {
00472       UnlockSemaphoreInfo(cache_info->disk_semaphore);
00473       return(MagickTrue);  /* cache already open */
00474     }
00475   if (*cache_info->cache_filename == '\0')
00476     file=AcquireUniqueFileResource(cache_info->cache_filename);
00477   else
00478     switch (mode)
00479     {
00480       case ReadMode:
00481       {
00482         file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
00483         break;
00484       }
00485       case WriteMode:
00486       {
00487         file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
00488           O_BINARY | O_EXCL,S_MODE);
00489         if (file == -1)
00490           file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
00491         break;
00492       }
00493       case IOMode:
00494       default:
00495       {
00496         file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
00497           O_EXCL,S_MODE);
00498         if (file == -1)
00499           file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
00500         break;
00501       }
00502     }
00503   if (file == -1)
00504     {
00505       UnlockSemaphoreInfo(cache_info->disk_semaphore);
00506       return(MagickFalse);
00507     }
00508   (void) AcquireMagickResource(FileResource,1);
00509   cache_info->file=file;
00510   cache_info->mode=mode;
00511   cache_info->timestamp=time(0);
00512   UnlockSemaphoreInfo(cache_info->disk_semaphore);
00513   return(MagickTrue);
00514 }
00515 
00516 static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
00517   const MagickOffsetType offset,const MagickSizeType length,
00518   unsigned char *restrict buffer)
00519 {
00520   register MagickOffsetType
00521     i;
00522 
00523   ssize_t
00524     count;
00525 
00526   cache_info->timestamp=time(0);
00527 #if !defined(MAGICKCORE_HAVE_PREAD)
00528   LockSemaphoreInfo(cache_info->disk_semaphore);
00529   if (lseek(cache_info->file,offset,SEEK_SET) < 0)
00530     {
00531       UnlockSemaphoreInfo(cache_info->disk_semaphore);
00532       return((MagickOffsetType) -1);
00533     }
00534 #endif
00535   count=0;
00536   for (i=0; i < (MagickOffsetType) length; i+=count)
00537   {
00538 #if !defined(MAGICKCORE_HAVE_PREAD)
00539     count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
00540       (MagickSizeType) SSIZE_MAX));
00541 #else
00542     count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
00543       (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
00544 #endif
00545     if (count > 0)
00546       continue;
00547     count=0;
00548     if (errno != EINTR)
00549       {
00550         i=(-1);
00551         break;
00552       }
00553   }
00554 #if !defined(MAGICKCORE_HAVE_PREAD)
00555   UnlockSemaphoreInfo(cache_info->disk_semaphore);
00556 #endif
00557   return(i);
00558 }
00559 
00560 static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
00561   const MagickOffsetType offset,const MagickSizeType length,
00562   const unsigned char *restrict buffer)
00563 {
00564   register MagickOffsetType
00565     i;
00566 
00567   ssize_t
00568     count;
00569 
00570   cache_info->timestamp=time(0);
00571 #if !defined(MAGICKCORE_HAVE_PWRITE)
00572   LockSemaphoreInfo(cache_info->disk_semaphore);
00573   if (lseek(cache_info->file,offset,SEEK_SET) < 0)
00574     {
00575       UnlockSemaphoreInfo(cache_info->disk_semaphore);
00576       return((MagickOffsetType) -1);
00577     }
00578 #endif
00579   count=0;
00580   for (i=0; i < (MagickOffsetType) length; i+=count)
00581   {
00582 #if !defined(MAGICKCORE_HAVE_PWRITE)
00583     count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
00584       (MagickSizeType) SSIZE_MAX));
00585 #else
00586     count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
00587       (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
00588 #endif
00589     if (count > 0)
00590       continue;
00591     count=0;
00592     if (errno != EINTR)
00593       {
00594         i=(-1);
00595         break;
00596       }
00597   }
00598 #if !defined(MAGICKCORE_HAVE_PWRITE)
00599   UnlockSemaphoreInfo(cache_info->disk_semaphore);
00600 #endif
00601   return(i);
00602 }
00603 
00604 static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
00605   CacheInfo *cache_info,ExceptionInfo *exception)
00606 {
00607   MagickOffsetType
00608     count;
00609 
00610   register MagickOffsetType
00611     i;
00612 
00613   size_t
00614     length;
00615 
00616   unsigned char
00617     *blob;
00618 
00619   /*
00620     Clone pixel cache (both caches on disk).
00621   */
00622   if (cache_info->debug != MagickFalse)
00623     (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
00624   blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
00625     sizeof(*blob));
00626   if (blob == (unsigned char *) NULL)
00627     {
00628       (void) ThrowMagickException(exception,GetMagickModule(),
00629         ResourceLimitError,"MemoryAllocationFailed","`%s'",
00630         cache_info->filename);
00631       return(MagickFalse);
00632     }
00633   if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
00634     {
00635       blob=(unsigned char *) RelinquishMagickMemory(blob);
00636       ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
00637         cache_info->cache_filename);
00638       return(MagickFalse);
00639     }
00640   if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
00641     {
00642       (void) ClosePixelCacheOnDisk(cache_info);
00643       blob=(unsigned char *) RelinquishMagickMemory(blob);
00644       ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
00645         clone_info->cache_filename);
00646       return(MagickFalse);
00647     }
00648   count=0;
00649   for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
00650   {
00651     count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
00652       MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
00653       blob);
00654     if (count <= 0)
00655       {
00656         ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
00657           cache_info->cache_filename);
00658         break;
00659       }
00660     length=(size_t) count;
00661     count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
00662     if ((MagickSizeType) count != length)
00663       {
00664         ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
00665           clone_info->cache_filename);
00666         break;
00667       }
00668   }
00669   (void) ClosePixelCacheOnDisk(clone_info);
00670   (void) ClosePixelCacheOnDisk(cache_info);
00671   blob=(unsigned char *) RelinquishMagickMemory(blob);
00672   if (i < (MagickOffsetType) cache_info->length)
00673     return(MagickFalse);
00674   return(MagickTrue);
00675 }
00676 
00677 static MagickBooleanType PixelCacheCloneOptimized(CacheInfo *clone_info,
00678   CacheInfo *cache_info,ExceptionInfo *exception)
00679 {
00680   MagickOffsetType
00681     count;
00682 
00683   if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
00684     {
00685       /*
00686         Clone pixel cache (both caches in memory).
00687       */
00688       if (cache_info->debug != MagickFalse)
00689         (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
00690       (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
00691         cache_info->length);
00692       return(MagickTrue);
00693     }
00694   if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
00695     {
00696       /*
00697         Clone pixel cache (one cache on disk, one in memory).
00698       */
00699       if (cache_info->debug != MagickFalse)
00700         (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
00701       if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
00702         {
00703           ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
00704             cache_info->cache_filename);
00705           return(MagickFalse);
00706         }
00707       count=ReadPixelCacheRegion(cache_info,cache_info->offset,
00708         cache_info->length,(unsigned char *) clone_info->pixels);
00709       (void) ClosePixelCacheOnDisk(cache_info);
00710       if ((MagickSizeType) count != cache_info->length)
00711         {
00712           ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
00713             cache_info->cache_filename);
00714           return(MagickFalse);
00715         }
00716       return(MagickTrue);
00717     }
00718   if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
00719     {
00720       /*
00721         Clone pixel cache (one cache on disk, one in memory).
00722       */
00723       if (clone_info->debug != MagickFalse)
00724         (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
00725       if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
00726         {
00727           ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
00728             clone_info->cache_filename);
00729           return(MagickFalse);
00730         }
00731       count=WritePixelCacheRegion(clone_info,clone_info->offset,
00732         clone_info->length,(unsigned char *) cache_info->pixels);
00733       (void) ClosePixelCacheOnDisk(clone_info);
00734       if ((MagickSizeType) count != clone_info->length)
00735         {
00736           ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
00737             clone_info->cache_filename);
00738           return(MagickFalse);
00739         }
00740       return(MagickTrue);
00741     }
00742   /*
00743     Clone pixel cache (both caches on disk).
00744   */
00745   return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
00746 }
00747 
00748 static MagickBooleanType PixelCacheCloneUnoptimized(CacheInfo *clone_info,
00749   CacheInfo *cache_info,ExceptionInfo *exception)
00750 {
00751   MagickBooleanType
00752     status;
00753 
00754   MagickOffsetType
00755     cache_offset,
00756     clone_offset,
00757     count;
00758 
00759   register ssize_t
00760     x;
00761 
00762   register unsigned char
00763     *p;
00764 
00765   size_t
00766     length;
00767 
00768   ssize_t
00769     y;
00770 
00771   unsigned char
00772     *blob;
00773 
00774   /*
00775     Clone pixel cache (unoptimized).
00776   */
00777   if (cache_info->debug != MagickFalse)
00778     {
00779       if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
00780         (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
00781       else
00782        if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
00783          (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
00784        else
00785          if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
00786            (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
00787          else
00788            (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
00789     }
00790   length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
00791     clone_info->number_channels)*sizeof(Quantum),MagickMax(
00792     cache_info->metacontent_extent,clone_info->metacontent_extent));
00793   blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
00794   if (blob == (unsigned char *) NULL)
00795     {
00796       (void) ThrowMagickException(exception,GetMagickModule(),
00797         ResourceLimitError,"MemoryAllocationFailed","`%s'",
00798         cache_info->filename);
00799       return(MagickFalse);
00800     }
00801   (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
00802   cache_offset=0;
00803   clone_offset=0;
00804   if (cache_info->type == DiskCache)
00805     {
00806       if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
00807         {
00808           blob=(unsigned char *) RelinquishMagickMemory(blob);
00809           ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
00810             cache_info->cache_filename);
00811           return(MagickFalse);
00812         }
00813       cache_offset=cache_info->offset;
00814     }
00815   if (clone_info->type == DiskCache)
00816     {
00817       if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
00818         {
00819           blob=(unsigned char *) RelinquishMagickMemory(blob);
00820           ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
00821             clone_info->cache_filename);
00822           return(MagickFalse);
00823         }
00824       clone_offset=clone_info->offset;
00825     }
00826   /*
00827     Clone pixel channels.
00828   */
00829   status=MagickTrue;
00830   p=blob;
00831   for (y=0; y < (ssize_t) cache_info->rows; y++)
00832   {
00833     for (x=0; x < (ssize_t) cache_info->columns; x++)
00834     {
00835       register ssize_t
00836         i;
00837 
00838       /*
00839         Read a set of pixel channels.
00840       */
00841       length=cache_info->number_channels*sizeof(Quantum);
00842       if (cache_info->type != DiskCache)
00843         p=(unsigned char *) cache_info->pixels+cache_offset;
00844       else
00845         {
00846           count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
00847           if ((MagickSizeType) count != length)
00848             {
00849               status=MagickFalse;
00850               break;
00851             }
00852         }
00853       cache_offset+=length;
00854       if ((y < (ssize_t) clone_info->rows) &&
00855           (x < (ssize_t) clone_info->columns))
00856         for (i=0; i < (ssize_t) clone_info->number_channels; i++)
00857         {
00858           PixelChannel
00859             channel;
00860 
00861           PixelTrait
00862             traits;
00863 
00864           ssize_t
00865             offset;
00866 
00867           /*
00868             Write a set of pixel channels.
00869           */
00870           channel=clone_info->channel_map[i].channel;
00871           traits=cache_info->channel_map[channel].traits;
00872           if (traits == UndefinedPixelTrait)
00873             {
00874               clone_offset+=sizeof(Quantum);
00875               continue;
00876             }
00877           offset=cache_info->channel_map[channel].offset;
00878           if (clone_info->type != DiskCache)
00879             (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,p+
00880               offset*sizeof(Quantum),sizeof(Quantum));
00881           else
00882             {
00883               count=WritePixelCacheRegion(clone_info,clone_offset,
00884                 sizeof(Quantum),p+offset*sizeof(Quantum));
00885               if ((MagickSizeType) count != sizeof(Quantum))
00886                 {
00887                   status=MagickFalse;
00888                   break;
00889                 }
00890             }
00891           clone_offset+=sizeof(Quantum);
00892         }
00893     }
00894     length=clone_info->number_channels*sizeof(Quantum);
00895     (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
00896     for ( ; x < (ssize_t) clone_info->columns; x++)
00897     {
00898       /*
00899         Set remaining columns as undefined.
00900       */
00901       if (clone_info->type != DiskCache)
00902         (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
00903           length);
00904       else
00905         {
00906           count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
00907           if ((MagickSizeType) count != length)
00908             {
00909               status=MagickFalse;
00910               break;
00911             }
00912         }
00913       clone_offset+=length;
00914     }
00915   }
00916   length=clone_info->number_channels*sizeof(Quantum);
00917   (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
00918   for ( ; y < (ssize_t) clone_info->rows; y++)
00919   {
00920     /*
00921       Set remaining rows as undefined.
00922     */
00923     for (x=0; x < (ssize_t) clone_info->columns; x++)
00924     {
00925       if (clone_info->type != DiskCache)
00926         (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
00927           length);
00928       else
00929         {
00930           count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
00931           if ((MagickSizeType) count != length)
00932             {
00933               status=MagickFalse;
00934               break;
00935             }
00936         }
00937       clone_offset+=length;
00938     }
00939   }
00940   if ((cache_info->metacontent_extent != 0) ||
00941       (clone_info->metacontent_extent != 0))
00942     {
00943       /*
00944         Clone metacontent.
00945       */
00946       for (y=0; y < (ssize_t) cache_info->rows; y++)
00947       {
00948         for (x=0; x < (ssize_t) cache_info->columns; x++)
00949         {
00950           /*
00951             Read a set of metacontent.
00952           */
00953           length=cache_info->metacontent_extent;
00954           if (cache_info->type != DiskCache)
00955             p=(unsigned char *) cache_info->pixels+cache_offset;
00956           else
00957             {
00958               count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
00959               if ((MagickSizeType) count != length)
00960                 {
00961                   status=MagickFalse;
00962                   break;
00963                 }
00964             }
00965           cache_offset+=length;
00966           if ((y < (ssize_t) clone_info->rows) &&
00967               (x < (ssize_t) clone_info->columns))
00968             {
00969               /*
00970                 Write a set of metacontent.
00971               */
00972               length=clone_info->metacontent_extent;
00973               if (clone_info->type != DiskCache)
00974                 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
00975                   p,length);
00976               else
00977                 {
00978                   count=WritePixelCacheRegion(clone_info,clone_offset,length,p);
00979                   if ((MagickSizeType) count != length)
00980                     {
00981                       status=MagickFalse;
00982                       break;
00983                     }
00984                 }
00985               clone_offset+=length;
00986             }
00987         }
00988         length=clone_info->metacontent_extent;
00989         (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
00990         for ( ; x < (ssize_t) clone_info->columns; x++)
00991         {
00992           /*
00993             Set remaining columns as undefined.
00994           */
00995           if (clone_info->type != DiskCache)
00996             (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
00997               blob,length);
00998           else
00999             {
01000               count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
01001               if ((MagickSizeType) count != length)
01002                 {
01003                   status=MagickFalse;
01004                   break;
01005                 }
01006             }
01007           clone_offset+=length;
01008         }
01009       }
01010       length=clone_info->metacontent_extent;
01011       (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
01012       for ( ; y < (ssize_t) clone_info->rows; y++)
01013       {
01014         /*
01015           Set remaining rows as undefined.
01016         */
01017         for (x=0; x < (ssize_t) clone_info->columns; x++)
01018         {
01019           if (clone_info->type != DiskCache)
01020             (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
01021               blob,length);
01022           else
01023             {
01024               count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
01025               if ((MagickSizeType) count != length)
01026                 {
01027                   status=MagickFalse;
01028                   break;
01029                 }
01030             }
01031           clone_offset+=length;
01032         }
01033       }
01034     }
01035   if (clone_info->type == DiskCache)
01036     (void) ClosePixelCacheOnDisk(clone_info);
01037   if (cache_info->type == DiskCache)
01038     (void) ClosePixelCacheOnDisk(cache_info);
01039   blob=(unsigned char *) RelinquishMagickMemory(blob);
01040   return(status);
01041 }
01042 
01043 static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
01044   CacheInfo *cache_info,ExceptionInfo *exception)
01045 {
01046   PixelChannelMap
01047     *p,
01048     *q;
01049 
01050   if (cache_info->type == PingCache)
01051     return(MagickTrue);
01052   p=cache_info->channel_map;
01053   q=clone_info->channel_map;
01054   if ((cache_info->columns == clone_info->columns) &&
01055       (cache_info->rows == clone_info->rows) &&
01056       (cache_info->number_channels == clone_info->number_channels) &&
01057       (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
01058       (cache_info->metacontent_extent == clone_info->metacontent_extent))
01059     return(PixelCacheCloneOptimized(clone_info,cache_info,exception));
01060   return(PixelCacheCloneUnoptimized(clone_info,cache_info,exception));
01061 }
01062 
01063 /*
01064 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01065 %                                                                             %
01066 %                                                                             %
01067 %                                                                             %
01068 +   C l o n e P i x e l C a c h e M e t h o d s                               %
01069 %                                                                             %
01070 %                                                                             %
01071 %                                                                             %
01072 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01073 %
01074 %  ClonePixelCacheMethods() clones the pixel cache methods from one cache to
01075 %  another.
01076 %
01077 %  The format of the ClonePixelCacheMethods() method is:
01078 %
01079 %      void ClonePixelCacheMethods(Cache clone,const Cache cache)
01080 %
01081 %  A description of each parameter follows:
01082 %
01083 %    o clone: Specifies a pointer to a Cache structure.
01084 %
01085 %    o cache: the pixel cache.
01086 %
01087 */
01088 MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
01089 {
01090   CacheInfo
01091     *cache_info,
01092     *source_info;
01093 
01094   assert(clone != (Cache) NULL);
01095   source_info=(CacheInfo *) clone;
01096   assert(source_info->signature == MagickSignature);
01097   if (source_info->debug != MagickFalse)
01098     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
01099       source_info->filename);
01100   assert(cache != (Cache) NULL);
01101   cache_info=(CacheInfo *) cache;
01102   assert(cache_info->signature == MagickSignature);
01103   source_info->methods=cache_info->methods;
01104 }
01105 
01106 /*
01107 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01108 %                                                                             %
01109 %                                                                             %
01110 %                                                                             %
01111 +   D e s t r o y I m a g e P i x e l C a c h e                               %
01112 %                                                                             %
01113 %                                                                             %
01114 %                                                                             %
01115 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01116 %
01117 %  DestroyImagePixelCache() deallocates memory associated with the pixel cache.
01118 %
01119 %  The format of the DestroyImagePixelCache() method is:
01120 %
01121 %      void DestroyImagePixelCache(Image *image)
01122 %
01123 %  A description of each parameter follows:
01124 %
01125 %    o image: the image.
01126 %
01127 */
01128 static void DestroyImagePixelCache(Image *image)
01129 {
01130   assert(image != (Image *) NULL);
01131   assert(image->signature == MagickSignature);
01132   if (image->debug != MagickFalse)
01133     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01134   if (image->cache == (void *) NULL)
01135     return;
01136   image->cache=DestroyPixelCache(image->cache);
01137 }
01138 
01139 /*
01140 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01141 %                                                                             %
01142 %                                                                             %
01143 %                                                                             %
01144 +   D e s t r o y I m a g e P i x e l s                                       %
01145 %                                                                             %
01146 %                                                                             %
01147 %                                                                             %
01148 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01149 %
01150 %  DestroyImagePixels() deallocates memory associated with the pixel cache.
01151 %
01152 %  The format of the DestroyImagePixels() method is:
01153 %
01154 %      void DestroyImagePixels(Image *image)
01155 %
01156 %  A description of each parameter follows:
01157 %
01158 %    o image: the image.
01159 %
01160 */
01161 MagickExport void DestroyImagePixels(Image *image)
01162 {
01163   CacheInfo
01164     *cache_info;
01165 
01166   assert(image != (const Image *) NULL);
01167   assert(image->signature == MagickSignature);
01168   if (image->debug != MagickFalse)
01169     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01170   assert(image->cache != (Cache) NULL);
01171   cache_info=(CacheInfo *) image->cache;
01172   assert(cache_info->signature == MagickSignature);
01173   if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
01174     {
01175       cache_info->methods.destroy_pixel_handler(image);
01176       return;
01177     }
01178   image->cache=DestroyPixelCache(image->cache);
01179 }
01180 
01181 /*
01182 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01183 %                                                                             %
01184 %                                                                             %
01185 %                                                                             %
01186 +   D e s t r o y P i x e l C a c h e                                         %
01187 %                                                                             %
01188 %                                                                             %
01189 %                                                                             %
01190 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01191 %
01192 %  DestroyPixelCache() deallocates memory associated with the pixel cache.
01193 %
01194 %  The format of the DestroyPixelCache() method is:
01195 %
01196 %      Cache DestroyPixelCache(Cache cache)
01197 %
01198 %  A description of each parameter follows:
01199 %
01200 %    o cache: the pixel cache.
01201 %
01202 */
01203 
01204 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
01205 {
01206   switch (cache_info->type)
01207   {
01208     case MemoryCache:
01209     {
01210       if (cache_info->mapped == MagickFalse)
01211         cache_info->pixels=(Quantum *) RelinquishMagickMemory(
01212           cache_info->pixels);
01213       else
01214         cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
01215           (size_t) cache_info->length);
01216       RelinquishMagickResource(MemoryResource,cache_info->length);
01217       break;
01218     }
01219     case MapCache:
01220     {
01221       cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
01222         cache_info->length);
01223       RelinquishMagickResource(MapResource,cache_info->length);
01224     }
01225     case DiskCache:
01226     {
01227       if (cache_info->file != -1)
01228         (void) ClosePixelCacheOnDisk(cache_info);
01229       RelinquishMagickResource(DiskResource,cache_info->length);
01230       break;
01231     }
01232     default:
01233       break;
01234   }
01235   cache_info->type=UndefinedCache;
01236   cache_info->mapped=MagickFalse;
01237   cache_info->metacontent=(void *) NULL;
01238 }
01239 
01240 MagickPrivate Cache DestroyPixelCache(Cache cache)
01241 {
01242   CacheInfo
01243     *cache_info;
01244 
01245   assert(cache != (Cache) NULL);
01246   cache_info=(CacheInfo *) cache;
01247   assert(cache_info->signature == MagickSignature);
01248   if (cache_info->debug != MagickFalse)
01249     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
01250       cache_info->filename);
01251   LockSemaphoreInfo(cache_info->semaphore);
01252   cache_info->reference_count--;
01253   if (cache_info->reference_count != 0)
01254     {
01255       UnlockSemaphoreInfo(cache_info->semaphore);
01256       return((Cache) NULL);
01257     }
01258   UnlockSemaphoreInfo(cache_info->semaphore);
01259   if (cache_info->debug != MagickFalse)
01260     {
01261       char
01262         message[MaxTextExtent];
01263 
01264       (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
01265         cache_info->filename);
01266       (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
01267     }
01268   if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
01269       (cache_info->type != DiskCache)))
01270     RelinquishPixelCachePixels(cache_info);
01271   else
01272     {
01273       RelinquishPixelCachePixels(cache_info);
01274       (void) RelinquishUniqueFileResource(cache_info->cache_filename);
01275     }
01276   *cache_info->cache_filename='\0';
01277   if (cache_info->nexus_info != (NexusInfo **) NULL)
01278     cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
01279       cache_info->number_threads);
01280   if (cache_info->random_info != (RandomInfo *) NULL)
01281     cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
01282   if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
01283     DestroySemaphoreInfo(&cache_info->disk_semaphore);
01284   if (cache_info->semaphore != (SemaphoreInfo *) NULL)
01285     DestroySemaphoreInfo(&cache_info->semaphore);
01286   cache_info->signature=(~MagickSignature);
01287   cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
01288   cache=(Cache) NULL;
01289   return(cache);
01290 }
01291 
01292 /*
01293 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01294 %                                                                             %
01295 %                                                                             %
01296 %                                                                             %
01297 +   D e s t r o y P i x e l C a c h e N e x u s                               %
01298 %                                                                             %
01299 %                                                                             %
01300 %                                                                             %
01301 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01302 %
01303 %  DestroyPixelCacheNexus() destroys a pixel cache nexus.
01304 %
01305 %  The format of the DestroyPixelCacheNexus() method is:
01306 %
01307 %      NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
01308 %        const size_t number_threads)
01309 %
01310 %  A description of each parameter follows:
01311 %
01312 %    o nexus_info: the nexus to destroy.
01313 %
01314 %    o number_threads: the number of nexus threads.
01315 %
01316 */
01317 
01318 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
01319 {
01320   if (nexus_info->mapped == MagickFalse)
01321     (void) RelinquishAlignedMemory(nexus_info->cache);
01322   else
01323     (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
01324   nexus_info->cache=(Quantum *) NULL;
01325   nexus_info->pixels=(Quantum *) NULL;
01326   nexus_info->metacontent=(void *) NULL;
01327   nexus_info->length=0;
01328   nexus_info->mapped=MagickFalse;
01329 }
01330 
01331 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
01332   const size_t number_threads)
01333 {
01334   register ssize_t
01335     i;
01336 
01337   assert(nexus_info != (NexusInfo **) NULL);
01338   for (i=0; i < (ssize_t) number_threads; i++)
01339   {
01340     if (nexus_info[i]->cache != (Quantum *) NULL)
01341       RelinquishCacheNexusPixels(nexus_info[i]);
01342     nexus_info[i]->signature=(~MagickSignature);
01343     nexus_info[i]=(NexusInfo *) RelinquishMagickMemory(nexus_info[i]);
01344   }
01345   nexus_info=(NexusInfo **) RelinquishMagickMemory(nexus_info);
01346   return(nexus_info);
01347 }
01348 
01349 /*
01350 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01351 %                                                                             %
01352 %                                                                             %
01353 %                                                                             %
01354 %   G e t A u t h e n t i c M e t a c o n t e n t                             %
01355 %                                                                             %
01356 %                                                                             %
01357 %                                                                             %
01358 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01359 %
01360 %  GetAuthenticMetacontent() returns the authentic metacontent corresponding
01361 %  with the last call to QueueAuthenticPixels() or GetVirtualPixels().  NULL is
01362 %  returned if the associated pixels are not available.
01363 %
01364 %  The format of the GetAuthenticMetacontent() method is:
01365 %
01366 %      void *GetAuthenticMetacontent(const Image *image)
01367 %
01368 %  A description of each parameter follows:
01369 %
01370 %    o image: the image.
01371 %
01372 */
01373 MagickExport void *GetAuthenticMetacontent(const Image *image)
01374 {
01375   CacheInfo
01376     *cache_info;
01377 
01378   const int
01379     id = GetOpenMPThreadId();
01380 
01381   void
01382     *metacontent;
01383 
01384   assert(image != (const Image *) NULL);
01385   assert(image->signature == MagickSignature);
01386   assert(image->cache != (Cache) NULL);
01387   cache_info=(CacheInfo *) image->cache;
01388   assert(cache_info->signature == MagickSignature);
01389   if (cache_info->methods.get_authentic_metacontent_from_handler !=
01390       (GetAuthenticMetacontentFromHandler) NULL)
01391     {
01392       metacontent=cache_info->methods.
01393         get_authentic_metacontent_from_handler(image);
01394       return(metacontent);
01395     }
01396   assert(id < (int) cache_info->number_threads);
01397   metacontent=GetPixelCacheNexusMetacontent(cache_info,
01398     cache_info->nexus_info[id]);
01399   return(metacontent);
01400 }
01401 
01402 /*
01403 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01404 %                                                                             %
01405 %                                                                             %
01406 %                                                                             %
01407 +   G e t A u t h e n t i c M e t a c o n t e n t F r o m C a c h e           %
01408 %                                                                             %
01409 %                                                                             %
01410 %                                                                             %
01411 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01412 %
01413 %  GetAuthenticMetacontentFromCache() returns the meta-content corresponding
01414 %  with the last call to QueueAuthenticPixelsCache() or
01415 %  GetAuthenticPixelsCache().
01416 %
01417 %  The format of the GetAuthenticMetacontentFromCache() method is:
01418 %
01419 %      void *GetAuthenticMetacontentFromCache(const Image *image)
01420 %
01421 %  A description of each parameter follows:
01422 %
01423 %    o image: the image.
01424 %
01425 */
01426 static void *GetAuthenticMetacontentFromCache(const Image *image)
01427 {
01428   CacheInfo
01429     *cache_info;
01430 
01431   const int
01432     id = GetOpenMPThreadId();
01433 
01434   void
01435     *metacontent;
01436 
01437   assert(image != (const Image *) NULL);
01438   assert(image->signature == MagickSignature);
01439   assert(image->cache != (Cache) NULL);
01440   cache_info=(CacheInfo *) image->cache;
01441   assert(cache_info->signature == MagickSignature);
01442   assert(id < (int) cache_info->number_threads);
01443   metacontent=GetPixelCacheNexusMetacontent(image->cache,
01444     cache_info->nexus_info[id]);
01445   return(metacontent);
01446 }
01447 
01448 /*
01449 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01450 %                                                                             %
01451 %                                                                             %
01452 %                                                                             %
01453 +   G e t A u t h e n t i c P i x e l C a c h e N e x u s                     %
01454 %                                                                             %
01455 %                                                                             %
01456 %                                                                             %
01457 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01458 %
01459 %  GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
01460 %  disk pixel cache as defined by the geometry parameters.   A pointer to the
01461 %  pixels is returned if the pixels are transferred, otherwise a NULL is
01462 %  returned.
01463 %
01464 %  The format of the GetAuthenticPixelCacheNexus() method is:
01465 %
01466 %      Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
01467 %        const ssize_t y,const size_t columns,const size_t rows,
01468 %        NexusInfo *nexus_info,ExceptionInfo *exception)
01469 %
01470 %  A description of each parameter follows:
01471 %
01472 %    o image: the image.
01473 %
01474 %    o x,y,columns,rows:  These values define the perimeter of a region of
01475 %      pixels.
01476 %
01477 %    o nexus_info: the cache nexus to return.
01478 %
01479 %    o exception: return any errors or warnings in this structure.
01480 %
01481 */
01482 
01483 static inline MagickBooleanType IsPixelAuthentic(const CacheInfo *cache_info,
01484   NexusInfo *nexus_info)
01485 {
01486   MagickBooleanType
01487     status;
01488 
01489   MagickOffsetType
01490     offset;
01491 
01492   if (cache_info->type == PingCache)
01493     return(MagickTrue);
01494   offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
01495     nexus_info->region.x;
01496   status=nexus_info->pixels == (cache_info->pixels+offset*
01497     cache_info->number_channels) ? MagickTrue : MagickFalse;
01498   return(status);
01499 }
01500 
01501 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
01502   const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
01503   NexusInfo *nexus_info,ExceptionInfo *exception)
01504 {
01505   CacheInfo
01506     *cache_info;
01507 
01508   Quantum
01509     *q;
01510 
01511   /*
01512     Transfer pixels from the cache.
01513   */
01514   assert(image != (Image *) NULL);
01515   assert(image->signature == MagickSignature);
01516   q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,nexus_info,
01517     exception);
01518   if (q == (Quantum *) NULL)
01519     return((Quantum *) NULL);
01520   cache_info=(CacheInfo *) image->cache;
01521   assert(cache_info->signature == MagickSignature);
01522   if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
01523     return(q);
01524   if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
01525     return((Quantum *) NULL);
01526   if (cache_info->metacontent_extent != 0)
01527     if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
01528       return((Quantum *) NULL);
01529   return(q);
01530 }
01531 
01532 /*
01533 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01534 %                                                                             %
01535 %                                                                             %
01536 %                                                                             %
01537 +   G e t A u t h e n t i c P i x e l s F r o m C a c h e                     %
01538 %                                                                             %
01539 %                                                                             %
01540 %                                                                             %
01541 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01542 %
01543 %  GetAuthenticPixelsFromCache() returns the pixels associated with the last
01544 %  call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
01545 %
01546 %  The format of the GetAuthenticPixelsFromCache() method is:
01547 %
01548 %      Quantum *GetAuthenticPixelsFromCache(const Image image)
01549 %
01550 %  A description of each parameter follows:
01551 %
01552 %    o image: the image.
01553 %
01554 */
01555 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
01556 {
01557   CacheInfo
01558     *cache_info;
01559 
01560   const int
01561     id = GetOpenMPThreadId();
01562 
01563   assert(image != (const Image *) NULL);
01564   assert(image->signature == MagickSignature);
01565   assert(image->cache != (Cache) NULL);
01566   cache_info=(CacheInfo *) image->cache;
01567   assert(cache_info->signature == MagickSignature);
01568   assert(id < (int) cache_info->number_threads);
01569   return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
01570 }
01571 
01572 /*
01573 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01574 %                                                                             %
01575 %                                                                             %
01576 %                                                                             %
01577 %   G e t A u t h e n t i c P i x e l Q u e u e                               %
01578 %                                                                             %
01579 %                                                                             %
01580 %                                                                             %
01581 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01582 %
01583 %  GetAuthenticPixelQueue() returns the authentic pixels associated
01584 %  corresponding with the last call to QueueAuthenticPixels() or
01585 %  GetAuthenticPixels().
01586 %
01587 %  The format of the GetAuthenticPixelQueue() method is:
01588 %
01589 %      Quantum *GetAuthenticPixelQueue(const Image image)
01590 %
01591 %  A description of each parameter follows:
01592 %
01593 %    o image: the image.
01594 %
01595 */
01596 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
01597 {
01598   CacheInfo
01599     *cache_info;
01600 
01601   const int
01602     id = GetOpenMPThreadId();
01603 
01604   assert(image != (const Image *) NULL);
01605   assert(image->signature == MagickSignature);
01606   assert(image->cache != (Cache) NULL);
01607   cache_info=(CacheInfo *) image->cache;
01608   assert(cache_info->signature == MagickSignature);
01609   if (cache_info->methods.get_authentic_pixels_from_handler !=
01610        (GetAuthenticPixelsFromHandler) NULL)
01611     return(cache_info->methods.get_authentic_pixels_from_handler(image));
01612   assert(id < (int) cache_info->number_threads);
01613   return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
01614 }
01615 
01616 /*
01617 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01618 %                                                                             %
01619 %                                                                             %
01620 %                                                                             %
01621 %   G e t A u t h e n t i c P i x e l s                                       %
01622 %                                                                             %
01623 %                                                                             %
01624 %                                                                             % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01625 %
01626 %  GetAuthenticPixels() obtains a pixel region for read/write access. If the
01627 %  region is successfully accessed, a pointer to a Quantum array
01628 %  representing the region is returned, otherwise NULL is returned.
01629 %
01630 %  The returned pointer may point to a temporary working copy of the pixels
01631 %  or it may point to the original pixels in memory. Performance is maximized
01632 %  if the selected region is part of one row, or one or more full rows, since
01633 %  then there is opportunity to access the pixels in-place (without a copy)
01634 %  if the image is in memory, or in a memory-mapped file. The returned pointer
01635 %  must *never* be deallocated by the user.
01636 %
01637 %  Pixels accessed via the returned pointer represent a simple array of type
01638 %  Quantum.  If the image has corresponding metacontent,call
01639 %  GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
01640 %  meta-content corresponding to the region.  Once the Quantum array has
01641 %  been updated, the changes must be saved back to the underlying image using
01642 %  SyncAuthenticPixels() or they may be lost.
01643 %
01644 %  The format of the GetAuthenticPixels() method is:
01645 %
01646 %      Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
01647 %        const ssize_t y,const size_t columns,const size_t rows,
01648 %        ExceptionInfo *exception)
01649 %
01650 %  A description of each parameter follows:
01651 %
01652 %    o image: the image.
01653 %
01654 %    o x,y,columns,rows:  These values define the perimeter of a region of
01655 %      pixels.
01656 %
01657 %    o exception: return any errors or warnings in this structure.
01658 %
01659 */
01660 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
01661   const ssize_t y,const size_t columns,const size_t rows,
01662   ExceptionInfo *exception)
01663 {
01664   CacheInfo
01665     *cache_info;
01666 
01667   const int
01668     id = GetOpenMPThreadId();
01669 
01670   Quantum
01671     *q;
01672 
01673   assert(image != (Image *) NULL);
01674   assert(image->signature == MagickSignature);
01675   assert(image->cache != (Cache) NULL);
01676   cache_info=(CacheInfo *) image->cache;
01677   assert(cache_info->signature == MagickSignature);
01678   if (cache_info->methods.get_authentic_pixels_handler !=
01679       (GetAuthenticPixelsHandler) NULL)
01680     {
01681       q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
01682         exception);
01683       return(q);
01684     }
01685   assert(id < (int) cache_info->number_threads);
01686   q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
01687     cache_info->nexus_info[id],exception);
01688   return(q);
01689 }
01690 
01691 /*
01692 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01693 %                                                                             %
01694 %                                                                             %
01695 %                                                                             %
01696 +   G e t A u t h e n t i c P i x e l s C a c h e                             %
01697 %                                                                             %
01698 %                                                                             %
01699 %                                                                             %
01700 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01701 %
01702 %  GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
01703 %  as defined by the geometry parameters.   A pointer to the pixels is returned
01704 %  if the pixels are transferred, otherwise a NULL is returned.
01705 %
01706 %  The format of the GetAuthenticPixelsCache() method is:
01707 %
01708 %      Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
01709 %        const ssize_t y,const size_t columns,const size_t rows,
01710 %        ExceptionInfo *exception)
01711 %
01712 %  A description of each parameter follows:
01713 %
01714 %    o image: the image.
01715 %
01716 %    o x,y,columns,rows:  These values define the perimeter of a region of
01717 %      pixels.
01718 %
01719 %    o exception: return any errors or warnings in this structure.
01720 %
01721 */
01722 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
01723   const ssize_t y,const size_t columns,const size_t rows,
01724   ExceptionInfo *exception)
01725 {
01726   CacheInfo
01727     *cache_info;
01728 
01729   const int
01730     id = GetOpenMPThreadId();
01731 
01732   Quantum
01733     *q;
01734 
01735   assert(image != (const Image *) NULL);
01736   assert(image->signature == MagickSignature);
01737   assert(image->cache != (Cache) NULL);
01738   cache_info=(CacheInfo *) image->cache;
01739   if (cache_info == (Cache) NULL)
01740     return((Quantum *) NULL);
01741   assert(cache_info->signature == MagickSignature);
01742   assert(id < (int) cache_info->number_threads);
01743   q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
01744     cache_info->nexus_info[id],exception);
01745   return(q);
01746 }
01747 
01748 /*
01749 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01750 %                                                                             %
01751 %                                                                             %
01752 %                                                                             %
01753 +   G e t I m a g e E x t e n t                                               %
01754 %                                                                             %
01755 %                                                                             %
01756 %                                                                             %
01757 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01758 %
01759 %  GetImageExtent() returns the extent of the pixels associated corresponding
01760 %  with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
01761 %
01762 %  The format of the GetImageExtent() method is:
01763 %
01764 %      MagickSizeType GetImageExtent(const Image *image)
01765 %
01766 %  A description of each parameter follows:
01767 %
01768 %    o image: the image.
01769 %
01770 */
01771 MagickExport MagickSizeType GetImageExtent(const Image *image)
01772 {
01773   CacheInfo
01774     *cache_info;
01775 
01776   const int
01777     id = GetOpenMPThreadId();
01778 
01779   assert(image != (Image *) NULL);
01780   assert(image->signature == MagickSignature);
01781   if (image->debug != MagickFalse)
01782     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01783   assert(image->cache != (Cache) NULL);
01784   cache_info=(CacheInfo *) image->cache;
01785   assert(cache_info->signature == MagickSignature);
01786   assert(id < (int) cache_info->number_threads);
01787   return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
01788 }
01789 
01790 /*
01791 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01792 %                                                                             %
01793 %                                                                             %
01794 %                                                                             %
01795 +   G e t I m a g e P i x e l C a c h e                                       %
01796 %                                                                             %
01797 %                                                                             %
01798 %                                                                             %
01799 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01800 %
01801 %  GetImagePixelCache() ensures that there is only a single reference to the
01802 %  pixel cache to be modified, updating the provided cache pointer to point to
01803 %  a clone of the original pixel cache if necessary.
01804 %
01805 %  The format of the GetImagePixelCache method is:
01806 %
01807 %      Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
01808 %        ExceptionInfo *exception)
01809 %
01810 %  A description of each parameter follows:
01811 %
01812 %    o image: the image.
01813 %
01814 %    o clone: any value other than MagickFalse clones the cache pixels.
01815 %
01816 %    o exception: return any errors or warnings in this structure.
01817 %
01818 */
01819 
01820 static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
01821 {
01822   CacheInfo
01823     *cache_info;
01824 
01825   PixelChannelMap
01826     *p,
01827     *q;
01828 
01829   /*
01830     Does the image match the pixel cache morphology?
01831   */
01832   cache_info=(CacheInfo *) image->cache;
01833   p=image->channel_map;
01834   q=cache_info->channel_map;
01835   if ((image->storage_class != cache_info->storage_class) ||
01836       (image->colorspace != cache_info->colorspace) ||
01837       (image->matte != cache_info->matte) ||
01838       (image->mask != cache_info->mask) ||
01839       (image->columns != cache_info->columns) ||
01840       (image->rows != cache_info->rows) ||
01841       (image->number_channels != cache_info->number_channels) ||
01842       (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
01843       (image->metacontent_extent != cache_info->metacontent_extent) ||
01844       (cache_info->nexus_info == (NexusInfo **) NULL) ||
01845       (cache_info->number_threads < GetOpenMPMaximumThreads()))
01846     return(MagickFalse);
01847   return(MagickTrue);
01848 }
01849 
01850 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
01851   ExceptionInfo *exception)
01852 {
01853   CacheInfo
01854     *cache_info;
01855 
01856   MagickBooleanType
01857     destroy,
01858     status;
01859 
01860   static MagickSizeType
01861     cpu_throttle = 0,
01862     cycles = 0,
01863     time_limit = 0;
01864 
01865   static time_t
01866     cache_timestamp = 0;
01867 
01868   status=MagickTrue;
01869   LockSemaphoreInfo(image->semaphore);
01870   if (cpu_throttle == 0)
01871     {
01872       char
01873         *limit;
01874 
01875       /*
01876         Set CPU throttle in milleseconds.
01877       */
01878       cpu_throttle=MagickResourceInfinity;
01879       limit=GetEnvironmentValue("MAGICK_THROTTLE");
01880       if (limit == (char *) NULL)
01881         limit=GetPolicyValue("throttle");
01882       if (limit != (char *) NULL)
01883         {
01884           cpu_throttle=(MagickSizeType) StringToInteger(limit);
01885           limit=DestroyString(limit);
01886         }
01887     }
01888   if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
01889     MagickDelay(cpu_throttle);
01890   if (time_limit == 0)
01891     {
01892       /*
01893         Set the exire time in seconds.
01894       */
01895       time_limit=GetMagickResourceLimit(TimeResource);
01896       cache_timestamp=time((time_t *) NULL);
01897     }
01898   if ((time_limit != MagickResourceInfinity) &&
01899       ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
01900     ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
01901   assert(image->cache != (Cache) NULL);
01902   cache_info=(CacheInfo *) image->cache;
01903   destroy=MagickFalse;
01904   if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
01905     {
01906       LockSemaphoreInfo(cache_info->semaphore);
01907       if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
01908         {
01909           Image
01910             clone_image;
01911 
01912           CacheInfo
01913             *clone_info;
01914 
01915           /*
01916             Clone pixel cache.
01917           */
01918           clone_image=(*image);
01919           clone_image.semaphore=AllocateSemaphoreInfo();
01920           clone_image.reference_count=1;
01921           clone_image.cache=ClonePixelCache(cache_info);
01922           clone_info=(CacheInfo *) clone_image.cache;
01923           status=OpenPixelCache(&clone_image,IOMode,exception);
01924           if (status != MagickFalse)
01925             {
01926               if (clone != MagickFalse)
01927                 status=ClonePixelCachePixels(clone_info,cache_info,exception);
01928               if (status != MagickFalse)
01929                 {
01930                   if (cache_info->mode == ReadMode)
01931                     cache_info->nexus_info=(NexusInfo **) NULL;
01932                   destroy=MagickTrue;
01933                   image->cache=clone_image.cache;
01934                 }
01935             }
01936           DestroySemaphoreInfo(&clone_image.semaphore);
01937         }
01938       UnlockSemaphoreInfo(cache_info->semaphore);
01939     }
01940   if (destroy != MagickFalse)
01941     cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
01942   if (status != MagickFalse)
01943     {
01944       /*
01945         Ensure the image matches the pixel cache morphology.
01946       */
01947       image->taint=MagickTrue;
01948       image->type=UndefinedType;
01949       if (ValidatePixelCacheMorphology(image) == MagickFalse)
01950         {
01951           status=OpenPixelCache(image,IOMode,exception);
01952           cache_info=(CacheInfo *) image->cache;
01953           if (cache_info->type == DiskCache)
01954             (void) ClosePixelCacheOnDisk(cache_info);
01955         }
01956     }
01957   UnlockSemaphoreInfo(image->semaphore);
01958   if (status == MagickFalse)
01959     return((Cache) NULL);
01960   return(image->cache);
01961 }
01962 
01963 /*
01964 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01965 %                                                                             %
01966 %                                                                             %
01967 %                                                                             %
01968 %   G e t O n e A u t h e n t i c P i x e l                                   %
01969 %                                                                             %
01970 %                                                                             %
01971 %                                                                             %
01972 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01973 %
01974 %  GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
01975 %  location.  The image background color is returned if an error occurs.
01976 %
01977 %  The format of the GetOneAuthenticPixel() method is:
01978 %
01979 %      MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
01980 %        const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
01981 %
01982 %  A description of each parameter follows:
01983 %
01984 %    o image: the image.
01985 %
01986 %    o x,y:  These values define the location of the pixel to return.
01987 %
01988 %    o pixel: return a pixel at the specified (x,y) location.
01989 %
01990 %    o exception: return any errors or warnings in this structure.
01991 %
01992 */
01993 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
01994   const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
01995 {
01996   CacheInfo
01997     *cache_info;
01998 
01999   register Quantum
02000     *q;
02001 
02002   register ssize_t
02003     i;
02004 
02005   assert(image != (Image *) NULL);
02006   assert(image->signature == MagickSignature);
02007   assert(image->cache != (Cache) NULL);
02008   cache_info=(CacheInfo *) image->cache;
02009   assert(cache_info->signature == MagickSignature);
02010   (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
02011   if (cache_info->methods.get_one_authentic_pixel_from_handler !=
02012        (GetOneAuthenticPixelFromHandler) NULL)
02013     return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
02014       pixel,exception));
02015   q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
02016   if (q == (Quantum *) NULL)
02017     {
02018       pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
02019       pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
02020       pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
02021       pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
02022       pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
02023       return(MagickFalse);
02024     }
02025   for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
02026   {
02027     PixelChannel
02028       channel;
02029 
02030     channel=GetPixelChannelMapChannel(image,i);
02031     pixel[channel]=q[i];
02032   }
02033   return(MagickTrue);
02034 }
02035 
02036 /*
02037 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02038 %                                                                             %
02039 %                                                                             %
02040 %                                                                             %
02041 +   G e t O n e A u t h e n t i c P i x e l F r o m C a c h e                 %
02042 %                                                                             %
02043 %                                                                             %
02044 %                                                                             %
02045 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02046 %
02047 %  GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
02048 %  location.  The image background color is returned if an error occurs.
02049 %
02050 %  The format of the GetOneAuthenticPixelFromCache() method is:
02051 %
02052 %      MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
02053 %        const ssize_t x,const ssize_t y,Quantum *pixel,
02054 %        ExceptionInfo *exception)
02055 %
02056 %  A description of each parameter follows:
02057 %
02058 %    o image: the image.
02059 %
02060 %    o x,y:  These values define the location of the pixel to return.
02061 %
02062 %    o pixel: return a pixel at the specified (x,y) location.
02063 %
02064 %    o exception: return any errors or warnings in this structure.
02065 %
02066 */
02067 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
02068   const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
02069 {
02070   CacheInfo
02071     *cache_info;
02072 
02073   const int
02074     id = GetOpenMPThreadId();
02075 
02076   register Quantum
02077     *q;
02078 
02079   register ssize_t
02080     i;
02081 
02082   assert(image != (const Image *) NULL);
02083   assert(image->signature == MagickSignature);
02084   assert(image->cache != (Cache) NULL);
02085   cache_info=(CacheInfo *) image->cache;
02086   assert(cache_info->signature == MagickSignature);
02087   assert(id < (int) cache_info->number_threads);
02088   (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
02089   q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
02090     exception);
02091   if (q == (Quantum *) NULL)
02092     {
02093       pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
02094       pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
02095       pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
02096       pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
02097       pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
02098       return(MagickFalse);
02099     }
02100   for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
02101   {
02102     PixelChannel
02103       channel;
02104 
02105     channel=GetPixelChannelMapChannel(image,i);
02106     pixel[channel]=q[i];
02107   }
02108   return(MagickTrue);
02109 }
02110 
02111 /*
02112 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02113 %                                                                             %
02114 %                                                                             %
02115 %                                                                             %
02116 %   G e t O n e V i r t u a l P i x e l                                       %
02117 %                                                                             %
02118 %                                                                             %
02119 %                                                                             %
02120 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02121 %
02122 %  GetOneVirtualPixel() returns a single virtual pixel at the specified
02123 %  (x,y) location.  The image background color is returned if an error occurs.
02124 %  If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
02125 %
02126 %  The format of the GetOneVirtualPixel() method is:
02127 %
02128 %      MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
02129 %        const ssize_t y,Quantum *pixel,ExceptionInfo exception)
02130 %
02131 %  A description of each parameter follows:
02132 %
02133 %    o image: the image.
02134 %
02135 %    o x,y:  These values define the location of the pixel to return.
02136 %
02137 %    o pixel: return a pixel at the specified (x,y) location.
02138 %
02139 %    o exception: return any errors or warnings in this structure.
02140 %
02141 */
02142 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
02143   const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
02144 {
02145   CacheInfo
02146     *cache_info;
02147 
02148   const int
02149     id = GetOpenMPThreadId();
02150 
02151   const Quantum
02152     *p;
02153 
02154   register ssize_t
02155     i;
02156 
02157   assert(image != (const Image *) NULL);
02158   assert(image->signature == MagickSignature);
02159   assert(image->cache != (Cache) NULL);
02160   cache_info=(CacheInfo *) image->cache;
02161   assert(cache_info->signature == MagickSignature);
02162   (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
02163   if (cache_info->methods.get_one_virtual_pixel_from_handler !=
02164        (GetOneVirtualPixelFromHandler) NULL)
02165     return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
02166       GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
02167   assert(id < (int) cache_info->number_threads);
02168   p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
02169     1UL,1UL,cache_info->nexus_info[id],exception);
02170   if (p == (const Quantum *) NULL)
02171     {
02172       pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
02173       pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
02174       pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
02175       pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
02176       pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
02177       return(MagickFalse);
02178     }
02179   for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
02180   {
02181     PixelChannel
02182       channel;
02183 
02184     channel=GetPixelChannelMapChannel(image,i);
02185     pixel[channel]=p[i];
02186   }
02187   return(MagickTrue);
02188 }
02189 
02190 /*
02191 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02192 %                                                                             %
02193 %                                                                             %
02194 %                                                                             %
02195 +   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                     %
02196 %                                                                             %
02197 %                                                                             %
02198 %                                                                             %
02199 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02200 %
02201 %  GetOneVirtualPixelFromCache() returns a single virtual pixel at the
02202 %  specified (x,y) location.  The image background color is returned if an
02203 %  error occurs.
02204 %
02205 %  The format of the GetOneVirtualPixelFromCache() method is:
02206 %
02207 %      MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
02208 %        const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
02209 %        Quantum *pixel,ExceptionInfo *exception)
02210 %
02211 %  A description of each parameter follows:
02212 %
02213 %    o image: the image.
02214 %
02215 %    o virtual_pixel_method: the virtual pixel method.
02216 %
02217 %    o x,y:  These values define the location of the pixel to return.
02218 %
02219 %    o pixel: return a pixel at the specified (x,y) location.
02220 %
02221 %    o exception: return any errors or warnings in this structure.
02222 %
02223 */
02224 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
02225   const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
02226   Quantum *pixel,ExceptionInfo *exception)
02227 {
02228   CacheInfo
02229     *cache_info;
02230 
02231   const int
02232     id = GetOpenMPThreadId();
02233 
02234   const Quantum
02235     *p;
02236 
02237   register ssize_t
02238     i;
02239 
02240   assert(image != (const Image *) NULL);
02241   assert(image->signature == MagickSignature);
02242   assert(image->cache != (Cache) NULL);
02243   cache_info=(CacheInfo *) image->cache;
02244   assert(cache_info->signature == MagickSignature);
02245   assert(id < (int) cache_info->number_threads);
02246   (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
02247   p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
02248     cache_info->nexus_info[id],exception);
02249   if (p == (const Quantum *) NULL)
02250     {
02251       pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
02252       pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
02253       pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
02254       pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
02255       pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
02256       return(MagickFalse);
02257     }
02258   for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
02259   {
02260     PixelChannel
02261       channel;
02262 
02263     channel=GetPixelChannelMapChannel(image,i);
02264     pixel[channel]=p[i];
02265   }
02266   return(MagickTrue);
02267 }
02268 
02269 /*
02270 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02271 %                                                                             %
02272 %                                                                             %
02273 %                                                                             %
02274 %   G e t O n e V i r t u a l P i x e l I n f o                               %
02275 %                                                                             %
02276 %                                                                             %
02277 %                                                                             %
02278 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02279 %
02280 %  GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
02281 %  location.  The image background color is returned if an error occurs.  If
02282 %  you plan to modify the pixel, use GetOneAuthenticPixel() instead.
02283 %
02284 %  The format of the GetOneVirtualPixelInfo() method is:
02285 %
02286 %      MagickBooleanType GetOneVirtualPixelInfo(const Image image,
02287 %        const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
02288 %        const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
02289 %
02290 %  A description of each parameter follows:
02291 %
02292 %    o image: the image.
02293 %
02294 %    o virtual_pixel_method: the virtual pixel method.
02295 %
02296 %    o x,y:  these values define the location of the pixel to return.
02297 %
02298 %    o pixel: return a pixel at the specified (x,y) location.
02299 %
02300 %    o exception: return any errors or warnings in this structure.
02301 %
02302 */
02303 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
02304   const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
02305   PixelInfo *pixel,ExceptionInfo *exception)
02306 {
02307   CacheInfo
02308     *cache_info;
02309 
02310   const int
02311     id = GetOpenMPThreadId();
02312 
02313   register const Quantum
02314     *p;
02315 
02316   assert(image != (const Image *) NULL);
02317   assert(image->signature == MagickSignature);
02318   assert(image->cache != (Cache) NULL);
02319   cache_info=(CacheInfo *) image->cache;
02320   assert(cache_info->signature == MagickSignature);
02321   assert(id < (int) cache_info->number_threads);
02322   p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
02323     cache_info->nexus_info[id],exception);
02324   GetPixelInfo(image,pixel);
02325   if (p == (const Quantum *) NULL)
02326     return(MagickFalse);
02327   GetPixelInfoPixel(image,p,pixel);
02328   return(MagickTrue);
02329 }
02330 
02331 /*
02332 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02333 %                                                                             %
02334 %                                                                             %
02335 %                                                                             %
02336 +   G e t P i x e l C a c h e C o l o r s p a c e                             %
02337 %                                                                             %
02338 %                                                                             %
02339 %                                                                             %
02340 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02341 %
02342 %  GetPixelCacheColorspace() returns the class type of the pixel cache.
02343 %
02344 %  The format of the GetPixelCacheColorspace() method is:
02345 %
02346 %      Colorspace GetPixelCacheColorspace(Cache cache)
02347 %
02348 %  A description of each parameter follows:
02349 %
02350 %    o cache: the pixel cache.
02351 %
02352 */
02353 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
02354 {
02355   CacheInfo
02356     *cache_info;
02357 
02358   assert(cache != (Cache) NULL);
02359   cache_info=(CacheInfo *) cache;
02360   assert(cache_info->signature == MagickSignature);
02361   if (cache_info->debug != MagickFalse)
02362     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
02363       cache_info->filename);
02364   return(cache_info->colorspace);
02365 }
02366 
02367 /*
02368 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02369 %                                                                             %
02370 %                                                                             %
02371 %                                                                             %
02372 +   G e t P i x e l C a c h e M e t h o d s                                   %
02373 %                                                                             %
02374 %                                                                             %
02375 %                                                                             %
02376 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02377 %
02378 %  GetPixelCacheMethods() initializes the CacheMethods structure.
02379 %
02380 %  The format of the GetPixelCacheMethods() method is:
02381 %
02382 %      void GetPixelCacheMethods(CacheMethods *cache_methods)
02383 %
02384 %  A description of each parameter follows:
02385 %
02386 %    o cache_methods: Specifies a pointer to a CacheMethods structure.
02387 %
02388 */
02389 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
02390 {
02391   assert(cache_methods != (CacheMethods *) NULL);
02392   (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
02393   cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
02394   cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
02395   cache_methods->get_virtual_metacontent_from_handler=
02396     GetVirtualMetacontentFromCache;
02397   cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
02398   cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
02399   cache_methods->get_authentic_metacontent_from_handler=
02400     GetAuthenticMetacontentFromCache;
02401   cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
02402   cache_methods->get_one_authentic_pixel_from_handler=
02403     GetOneAuthenticPixelFromCache;
02404   cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
02405   cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
02406   cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
02407 }
02408 
02409 /*
02410 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02411 %                                                                             %
02412 %                                                                             %
02413 %                                                                             %
02414 +   G e t P i x e l C a c h e N e x u s E x t e n t                           %
02415 %                                                                             %
02416 %                                                                             %
02417 %                                                                             %
02418 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02419 %
02420 %  GetPixelCacheNexusExtent() returns the extent of the pixels associated
02421 %  corresponding with the last call to SetPixelCacheNexusPixels() or
02422 %  GetPixelCacheNexusPixels().
02423 %
02424 %  The format of the GetPixelCacheNexusExtent() method is:
02425 %
02426 %      MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
02427 %        NexusInfo *nexus_info)
02428 %
02429 %  A description of each parameter follows:
02430 %
02431 %    o nexus_info: the nexus info.
02432 %
02433 */
02434 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
02435   NexusInfo *nexus_info)
02436 {
02437   CacheInfo
02438     *cache_info;
02439 
02440   MagickSizeType
02441     extent;
02442 
02443   assert(cache != NULL);
02444   cache_info=(CacheInfo *) cache;
02445   assert(cache_info->signature == MagickSignature);
02446   extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
02447   if (extent == 0)
02448     return((MagickSizeType) cache_info->columns*cache_info->rows);
02449   return(extent);
02450 }
02451 
02452 /*
02453 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02454 %                                                                             %
02455 %                                                                             %
02456 %                                                                             %
02457 +   G e t P i x e l C a c h e N e x u s M e t a c o n t e n t                 %
02458 %                                                                             %
02459 %                                                                             %
02460 %                                                                             %
02461 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02462 %
02463 %  GetPixelCacheNexusMetacontent() returns the meta-content for the specified
02464 %  cache nexus.
02465 %
02466 %  The format of the GetPixelCacheNexusMetacontent() method is:
02467 %
02468 %      void *GetPixelCacheNexusMetacontent(const Cache cache,
02469 %        NexusInfo *nexus_info)
02470 %
02471 %  A description of each parameter follows:
02472 %
02473 %    o cache: the pixel cache.
02474 %
02475 %    o nexus_info: the cache nexus to return the meta-content.
02476 %
02477 */
02478 MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
02479   NexusInfo *nexus_info)
02480 {
02481   CacheInfo
02482     *cache_info;
02483 
02484   assert(cache != NULL);
02485   cache_info=(CacheInfo *) cache;
02486   assert(cache_info->signature == MagickSignature);
02487   if (cache_info->storage_class == UndefinedClass)
02488     return((void *) NULL);
02489   return(nexus_info->metacontent);
02490 }
02491 
02492 /*
02493 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02494 %                                                                             %
02495 %                                                                             %
02496 %                                                                             %
02497 +   G e t P i x e l C a c h e N e x u s P i x e l s                           %
02498 %                                                                             %
02499 %                                                                             %
02500 %                                                                             %
02501 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02502 %
02503 %  GetPixelCacheNexusPixels() returns the pixels associated with the specified
02504 %  cache nexus.
02505 %
02506 %  The format of the GetPixelCacheNexusPixels() method is:
02507 %
02508 %      Quantum *GetPixelCacheNexusPixels(const Cache cache,
02509 %        NexusInfo *nexus_info)
02510 %
02511 %  A description of each parameter follows:
02512 %
02513 %    o cache: the pixel cache.
02514 %
02515 %    o nexus_info: the cache nexus to return the pixels.
02516 %
02517 */
02518 MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
02519   NexusInfo *nexus_info)
02520 {
02521   CacheInfo
02522     *cache_info;
02523 
02524   assert(cache != NULL);
02525   cache_info=(CacheInfo *) cache;
02526   assert(cache_info->signature == MagickSignature);
02527   if (cache_info->storage_class == UndefinedClass)
02528     return((Quantum *) NULL);
02529   return(nexus_info->pixels);
02530 }
02531 
02532 /*
02533 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02534 %                                                                             %
02535 %                                                                             %
02536 %                                                                             %
02537 +   G e t P i x e l C a c h e P i x e l s                                     %
02538 %                                                                             %
02539 %                                                                             %
02540 %                                                                             %
02541 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02542 %
02543 %  GetPixelCachePixels() returns the pixels associated with the specified image.
02544 %
02545 %  The format of the GetPixelCachePixels() method is:
02546 %
02547 %      void *GetPixelCachePixels(Image *image,MagickSizeType *length,
02548 %        ExceptionInfo *exception)
02549 %
02550 %  A description of each parameter follows:
02551 %
02552 %    o image: the image.
02553 %
02554 %    o length: the pixel cache length.
02555 %
02556 %    o exception: return any errors or warnings in this structure.
02557 %
02558 */
02559 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
02560   ExceptionInfo *exception)
02561 {
02562   CacheInfo
02563     *cache_info;
02564 
02565   assert(image != (const Image *) NULL);
02566   assert(image->signature == MagickSignature);
02567   assert(image->cache != (Cache) NULL);
02568   assert(length != (MagickSizeType *) NULL);
02569   assert(exception != (ExceptionInfo *) NULL);
02570   assert(exception->signature == MagickSignature);
02571   cache_info=(CacheInfo *) image->cache;
02572   assert(cache_info->signature == MagickSignature);
02573   *length=0;
02574   if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
02575     return((void *) NULL);
02576   *length=cache_info->length;
02577   return((void *) cache_info->pixels);
02578 }
02579 
02580 /*
02581 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02582 %                                                                             %
02583 %                                                                             %
02584 %                                                                             %
02585 +   G e t P i x e l C a c h e S t o r a g e C l a s s                         %
02586 %                                                                             %
02587 %                                                                             %
02588 %                                                                             %
02589 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02590 %
02591 %  GetPixelCacheStorageClass() returns the class type of the pixel cache.
02592 %
02593 %  The format of the GetPixelCacheStorageClass() method is:
02594 %
02595 %      ClassType GetPixelCacheStorageClass(Cache cache)
02596 %
02597 %  A description of each parameter follows:
02598 %
02599 %    o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
02600 %
02601 %    o cache: the pixel cache.
02602 %
02603 */
02604 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
02605 {
02606   CacheInfo
02607     *cache_info;
02608 
02609   assert(cache != (Cache) NULL);
02610   cache_info=(CacheInfo *) cache;
02611   assert(cache_info->signature == MagickSignature);
02612   if (cache_info->debug != MagickFalse)
02613     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
02614       cache_info->filename);
02615   return(cache_info->storage_class);
02616 }
02617 
02618 /*
02619 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02620 %                                                                             %
02621 %                                                                             %
02622 %                                                                             %
02623 +   G e t P i x e l C a c h e T i l e S i z e                                 %
02624 %                                                                             %
02625 %                                                                             %
02626 %                                                                             %
02627 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02628 %
02629 %  GetPixelCacheTileSize() returns the pixel cache tile size.
02630 %
02631 %  The format of the GetPixelCacheTileSize() method is:
02632 %
02633 %      void GetPixelCacheTileSize(const Image *image,size_t *width,
02634 %        size_t *height)
02635 %
02636 %  A description of each parameter follows:
02637 %
02638 %    o image: the image.
02639 %
02640 %    o width: the optimize cache tile width in pixels.
02641 %
02642 %    o height: the optimize cache tile height in pixels.
02643 %
02644 */
02645 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
02646   size_t *height)
02647 {
02648   CacheInfo
02649     *cache_info;
02650 
02651   assert(image != (Image *) NULL);
02652   assert(image->signature == MagickSignature);
02653   if (image->debug != MagickFalse)
02654     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
02655   cache_info=(CacheInfo *) image->cache;
02656   assert(cache_info->signature == MagickSignature);
02657   *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
02658   if (GetPixelCacheType(image) == DiskCache)
02659     *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
02660   *height=(*width);
02661 }
02662 
02663 /*
02664 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02665 %                                                                             %
02666 %                                                                             %
02667 %                                                                             %
02668 +   G e t P i x e l C a c h e T y p e                                         %
02669 %                                                                             %
02670 %                                                                             %
02671 %                                                                             %
02672 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02673 %
02674 %  GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
02675 %
02676 %  The format of the GetPixelCacheType() method is:
02677 %
02678 %      CacheType GetPixelCacheType(const Image *image)
02679 %
02680 %  A description of each parameter follows:
02681 %
02682 %    o image: the image.
02683 %
02684 */
02685 MagickPrivate CacheType GetPixelCacheType(const Image *image)
02686 {
02687   CacheInfo
02688     *cache_info;
02689 
02690   assert(image != (Image *) NULL);
02691   assert(image->signature == MagickSignature);
02692   assert(image->cache != (Cache) NULL);
02693   cache_info=(CacheInfo *) image->cache;
02694   assert(cache_info->signature == MagickSignature);
02695   return(cache_info->type);
02696 }
02697 
02698 /*
02699 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02700 %                                                                             %
02701 %                                                                             %
02702 %                                                                             %
02703 +   G e t P i x e l C a c h e V i r t u a l M e t h o d                       %
02704 %                                                                             %
02705 %                                                                             %
02706 %                                                                             %
02707 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02708 %
02709 %  GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
02710 %  pixel cache.  A virtual pixel is any pixel access that is outside the
02711 %  boundaries of the image cache.
02712 %
02713 %  The format of the GetPixelCacheVirtualMethod() method is:
02714 %
02715 %      VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
02716 %
02717 %  A description of each parameter follows:
02718 %
02719 %    o image: the image.
02720 %
02721 */
02722 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
02723 {
02724   CacheInfo
02725     *cache_info;
02726 
02727   assert(image != (Image *) NULL);
02728   assert(image->signature == MagickSignature);
02729   assert(image->cache != (Cache) NULL);
02730   cache_info=(CacheInfo *) image->cache;
02731   assert(cache_info->signature == MagickSignature);
02732   return(cache_info->virtual_pixel_method);
02733 }
02734 
02735 /*
02736 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02737 %                                                                             %
02738 %                                                                             %
02739 %                                                                             %
02740 +   G e t V i r t u a l M e t a c o n t e n t F r o m C a c h e               %
02741 %                                                                             %
02742 %                                                                             %
02743 %                                                                             %
02744 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02745 %
02746 %  GetVirtualMetacontentFromCache() returns the meta-content corresponding with
02747 %  the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
02748 %
02749 %  The format of the GetVirtualMetacontentFromCache() method is:
02750 %
02751 %      void *GetVirtualMetacontentFromCache(const Image *image)
02752 %
02753 %  A description of each parameter follows:
02754 %
02755 %    o image: the image.
02756 %
02757 */
02758 static const void *GetVirtualMetacontentFromCache(const Image *image)
02759 {
02760   CacheInfo
02761     *cache_info;
02762 
02763   const int
02764     id = GetOpenMPThreadId();
02765 
02766   const void
02767     *metacontent;
02768 
02769   assert(image != (const Image *) NULL);
02770   assert(image->signature == MagickSignature);
02771   assert(image->cache != (Cache) NULL);
02772   cache_info=(CacheInfo *) image->cache;
02773   assert(cache_info->signature == MagickSignature);
02774   assert(id < (int) cache_info->number_threads);
02775   metacontent=GetVirtualMetacontentFromNexus(cache_info,
02776     cache_info->nexus_info[id]);
02777   return(metacontent);
02778 }
02779 
02780 /*
02781 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02782 %                                                                             %
02783 %                                                                             %
02784 %                                                                             %
02785 +   G e t V i r t u a l M e t a c o n t e n t F r o m N e x u s               %
02786 %                                                                             %
02787 %                                                                             %
02788 %                                                                             %
02789 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02790 %
02791 %  GetVirtualMetacontentFromNexus() returns the meta-content for the specified
02792 %  cache nexus.
02793 %
02794 %  The format of the GetVirtualMetacontentFromNexus() method is:
02795 %
02796 %      const void *GetVirtualMetacontentFromNexus(const Cache cache,
02797 %        NexusInfo *nexus_info)
02798 %
02799 %  A description of each parameter follows:
02800 %
02801 %    o cache: the pixel cache.
02802 %
02803 %    o nexus_info: the cache nexus to return the meta-content.
02804 %
02805 */
02806 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
02807   NexusInfo *nexus_info)
02808 {
02809   CacheInfo
02810     *cache_info;
02811 
02812   assert(cache != (Cache) NULL);
02813   cache_info=(CacheInfo *) cache;
02814   assert(cache_info->signature == MagickSignature);
02815   if (cache_info->storage_class == UndefinedClass)
02816     return((void *) NULL);
02817   return(nexus_info->metacontent);
02818 }
02819 
02820 /*
02821 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02822 %                                                                             %
02823 %                                                                             %
02824 %                                                                             %
02825 %   G e t V i r t u a l M e t a c o n t e n t                                 %
02826 %                                                                             %
02827 %                                                                             %
02828 %                                                                             %
02829 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02830 %
02831 %  GetVirtualMetacontent() returns the virtual metacontent corresponding with
02832 %  the last call to QueueAuthenticPixels() or GetVirtualPixels().  NULL is
02833 %  returned if the meta-content are not available.
02834 %
02835 %  The format of the GetVirtualMetacontent() method is:
02836 %
02837 %      const void *GetVirtualMetacontent(const Image *image)
02838 %
02839 %  A description of each parameter follows:
02840 %
02841 %    o image: the image.
02842 %
02843 */
02844 MagickExport const void *GetVirtualMetacontent(const Image *image)
02845 {
02846   CacheInfo
02847     *cache_info;
02848 
02849   const int
02850     id = GetOpenMPThreadId();
02851 
02852   const void
02853     *metacontent;
02854 
02855   assert(image != (const Image *) NULL);
02856   assert(image->signature == MagickSignature);
02857   assert(image->cache != (Cache) NULL);
02858   cache_info=(CacheInfo *) image->cache;
02859   assert(cache_info->signature == MagickSignature);
02860   if (cache_info->methods.get_virtual_metacontent_from_handler !=
02861        (GetVirtualMetacontentFromHandler) NULL)
02862     {
02863       metacontent=cache_info->methods.
02864         get_virtual_metacontent_from_handler(image);
02865       return(metacontent);
02866     }
02867   assert(id < (int) cache_info->number_threads);
02868   metacontent=GetVirtualMetacontentFromNexus(cache_info,
02869     cache_info->nexus_info[id]);
02870   return(metacontent);
02871 }
02872 
02873 /*
02874 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02875 %                                                                             %
02876 %                                                                             %
02877 %                                                                             %
02878 +   G e t V i r t u a l P i x e l s F r o m N e x u s                         %
02879 %                                                                             %
02880 %                                                                             %
02881 %                                                                             %
02882 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02883 %
02884 %  GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
02885 %  pixel cache as defined by the geometry parameters.   A pointer to the pixels
02886 %  is returned if the pixels are transferred, otherwise a NULL is returned.
02887 %
02888 %  The format of the GetVirtualPixelsFromNexus() method is:
02889 %
02890 %      Quantum *GetVirtualPixelsFromNexus(const Image *image,
02891 %        const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
02892 %        const size_t columns,const size_t rows,NexusInfo *nexus_info,
02893 %        ExceptionInfo *exception)
02894 %
02895 %  A description of each parameter follows:
02896 %
02897 %    o image: the image.
02898 %
02899 %    o virtual_pixel_method: the virtual pixel method.
02900 %
02901 %    o x,y,columns,rows:  These values define the perimeter of a region of
02902 %      pixels.
02903 %
02904 %    o nexus_info: the cache nexus to acquire.
02905 %
02906 %    o exception: return any errors or warnings in this structure.
02907 %
02908 */
02909 
02910 static ssize_t
02911   DitherMatrix[64] =
02912   {
02913      0,  48,  12,  60,   3,  51,  15,  63,
02914     32,  16,  44,  28,  35,  19,  47,  31,
02915      8,  56,   4,  52,  11,  59,   7,  55,
02916     40,  24,  36,  20,  43,  27,  39,  23,
02917      2,  50,  14,  62,   1,  49,  13,  61,
02918     34,  18,  46,  30,  33,  17,  45,  29,
02919     10,  58,   6,  54,   9,  57,   5,  53,
02920     42,  26,  38,  22,  41,  25,  37,  21
02921   };
02922 
02923 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
02924 {
02925   ssize_t
02926     index;
02927 
02928   index=x+DitherMatrix[x & 0x07]-32L;
02929   if (index < 0L)
02930     return(0L);
02931   if (index >= (ssize_t) columns)
02932     return((ssize_t) columns-1L);
02933   return(index);
02934 }
02935 
02936 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
02937 {
02938   ssize_t
02939     index;
02940 
02941   index=y+DitherMatrix[y & 0x07]-32L;
02942   if (index < 0L)
02943     return(0L);
02944   if (index >= (ssize_t) rows)
02945     return((ssize_t) rows-1L);
02946   return(index);
02947 }
02948 
02949 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
02950 {
02951   if (x < 0L)
02952     return(0L);
02953   if (x >= (ssize_t) columns)
02954     return((ssize_t) (columns-1));
02955   return(x);
02956 }
02957 
02958 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
02959 {
02960   if (y < 0L)
02961     return(0L);
02962   if (y >= (ssize_t) rows)
02963     return((ssize_t) (rows-1));
02964   return(y);
02965 }
02966 
02967 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
02968 {
02969   return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
02970 }
02971 
02972 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
02973 {
02974   return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
02975 }
02976 
02977 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
02978   const size_t extent)
02979 {
02980   MagickModulo
02981     modulo;
02982 
02983   /*
02984     Compute the remainder of dividing offset by extent.  It returns not only
02985     the quotient (tile the offset falls in) but also the positive remainer
02986     within that tile such that 0 <= remainder < extent.  This method is
02987     essentially a ldiv() using a floored modulo division rather than the
02988     normal default truncated modulo division.
02989   */
02990   modulo.quotient=offset/(ssize_t) extent;
02991   if (offset < 0L)
02992     modulo.quotient--;
02993   modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
02994   return(modulo);
02995 }
02996 
02997 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
02998   const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
02999   const size_t columns,const size_t rows,NexusInfo *nexus_info,
03000   ExceptionInfo *exception)
03001 {
03002   CacheInfo
03003     *cache_info;
03004 
03005   MagickOffsetType
03006     offset;
03007 
03008   MagickSizeType
03009     length,
03010     number_pixels;
03011 
03012   NexusInfo
03013     **virtual_nexus;
03014 
03015   Quantum
03016     *pixels,
03017     virtual_pixel[CompositePixelChannel];
03018 
03019   RectangleInfo
03020     region;
03021 
03022   register const Quantum
03023     *restrict p;
03024 
03025   register const void
03026     *restrict r;
03027 
03028   register Quantum
03029     *restrict q;
03030 
03031   register ssize_t
03032     i,
03033     u;
03034 
03035   register unsigned char
03036     *restrict s;
03037 
03038   ssize_t
03039     v;
03040 
03041   void
03042     *virtual_metacontent;
03043 
03044   /*
03045     Acquire pixels.
03046   */
03047   assert(image != (const Image *) NULL);
03048   assert(image->signature == MagickSignature);
03049   assert(image->cache != (Cache) NULL);
03050   cache_info=(CacheInfo *) image->cache;
03051   assert(cache_info->signature == MagickSignature);
03052   if (cache_info->type == UndefinedCache)
03053     return((const Quantum *) NULL);
03054   region.x=x;
03055   region.y=y;
03056   region.width=columns;
03057   region.height=rows;
03058   pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
03059   if (pixels == (Quantum *) NULL)
03060     return((const Quantum *) NULL);
03061   q=pixels;
03062   offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
03063     nexus_info->region.x;
03064   length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
03065     nexus_info->region.width-1L;
03066   number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
03067   if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
03068     if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
03069         (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
03070       {
03071         MagickBooleanType
03072           status;
03073 
03074         /*
03075           Pixel request is inside cache extents.
03076         */
03077         if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
03078           return(q);
03079         status=ReadPixelCachePixels(cache_info,nexus_info,exception);
03080         if (status == MagickFalse)
03081           return((const Quantum *) NULL);
03082         if (cache_info->metacontent_extent != 0)
03083           {
03084             status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
03085             if (status == MagickFalse)
03086               return((const Quantum *) NULL);
03087           }
03088         return(q);
03089       }
03090   /*
03091     Pixel request is outside cache extents.
03092   */
03093   s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
03094   virtual_nexus=AcquirePixelCacheNexus(1);
03095   if (virtual_nexus == (NexusInfo **) NULL)
03096     {
03097       if (virtual_nexus != (NexusInfo **) NULL)
03098         virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
03099       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
03100         "UnableToGetCacheNexus","`%s'",image->filename);
03101       return((const Quantum *) NULL);
03102     }
03103   (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
03104     sizeof(*virtual_pixel));
03105   virtual_metacontent=(void *) NULL;
03106   switch (virtual_pixel_method)
03107   {
03108     case BackgroundVirtualPixelMethod:
03109     case BlackVirtualPixelMethod:
03110     case GrayVirtualPixelMethod:
03111     case TransparentVirtualPixelMethod:
03112     case MaskVirtualPixelMethod:
03113     case WhiteVirtualPixelMethod:
03114     case EdgeVirtualPixelMethod:
03115     case CheckerTileVirtualPixelMethod:
03116     case HorizontalTileVirtualPixelMethod:
03117     case VerticalTileVirtualPixelMethod:
03118     {
03119       if (cache_info->metacontent_extent != 0)
03120         {
03121           /*
03122             Acquire a metacontent buffer.
03123           */
03124           virtual_metacontent=(void *) AcquireQuantumMemory(1,
03125             cache_info->metacontent_extent);
03126           if (virtual_metacontent == (void *) NULL)
03127             {
03128               virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
03129               (void) ThrowMagickException(exception,GetMagickModule(),
03130                 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
03131               return((const Quantum *) NULL);
03132             }
03133           (void) ResetMagickMemory(virtual_metacontent,0,
03134             cache_info->metacontent_extent);
03135         }
03136       switch (virtual_pixel_method)
03137       {
03138         case BlackVirtualPixelMethod:
03139         {
03140           for (i=0; i < (ssize_t) cache_info->number_channels; i++)
03141             SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
03142           SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
03143           break;
03144         }
03145         case GrayVirtualPixelMethod:
03146         {
03147           for (i=0; i < (ssize_t) cache_info->number_channels; i++)
03148             SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
03149               virtual_pixel);
03150           SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
03151           break;
03152         }
03153         case TransparentVirtualPixelMethod:
03154         {
03155           for (i=0; i < (ssize_t) cache_info->number_channels; i++)
03156             SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
03157           SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
03158           break;
03159         }
03160         case MaskVirtualPixelMethod:
03161         case WhiteVirtualPixelMethod:
03162         {
03163           for (i=0; i < (ssize_t) cache_info->number_channels; i++)
03164             SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
03165           SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
03166           break;
03167         }
03168         default:
03169         {
03170           SetPixelRed(image,ClampToQuantum(image->background_color.red),
03171             virtual_pixel);
03172           SetPixelGreen(image,ClampToQuantum(image->background_color.green),
03173             virtual_pixel);
03174           SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
03175             virtual_pixel);
03176           SetPixelBlack(image,ClampToQuantum(image->background_color.black),
03177             virtual_pixel);
03178           SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
03179             virtual_pixel);
03180           break;
03181         }
03182       }
03183       break;
03184     }
03185     default:
03186       break;
03187   }
03188   for (v=0; v < (ssize_t) rows; v++)
03189   {
03190     for (u=0; u < (ssize_t) columns; u+=length)
03191     {
03192       length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
03193       if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
03194           (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
03195           (length == 0))
03196         {
03197           MagickModulo
03198             x_modulo,
03199             y_modulo;
03200 
03201           /*
03202             Transfer a single pixel.
03203           */
03204           length=(MagickSizeType) 1;
03205           switch (virtual_pixel_method)
03206           {
03207             default:
03208             {
03209               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
03210                 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
03211                 1UL,1UL,*virtual_nexus,exception);
03212               r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
03213               break;
03214             }
03215             case RandomVirtualPixelMethod:
03216             {
03217               if (cache_info->random_info == (RandomInfo *) NULL)
03218                 cache_info->random_info=AcquireRandomInfo();
03219               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
03220                 RandomX(cache_info->random_info,cache_info->columns),
03221                 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
03222                 *virtual_nexus,exception);
03223               r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
03224               break;
03225             }
03226             case DitherVirtualPixelMethod:
03227             {
03228               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
03229                 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
03230                 1UL,1UL,*virtual_nexus,exception);
03231               r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
03232               break;
03233             }
03234             case TileVirtualPixelMethod:
03235             {
03236               x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
03237               y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
03238               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
03239                 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
03240                 exception);
03241               r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
03242               break;
03243             }
03244             case MirrorVirtualPixelMethod:
03245             {
03246               x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
03247               if ((x_modulo.quotient & 0x01) == 1L)
03248                 x_modulo.remainder=(ssize_t) cache_info->columns-
03249                   x_modulo.remainder-1L;
03250               y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
03251               if ((y_modulo.quotient & 0x01) == 1L)
03252                 y_modulo.remainder=(ssize_t) cache_info->rows-
03253                   y_modulo.remainder-1L;
03254               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
03255                 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
03256                 exception);
03257               r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
03258               break;
03259             }
03260             case HorizontalTileEdgeVirtualPixelMethod:
03261             {
03262               x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
03263               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
03264                 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
03265                 *virtual_nexus,exception);
03266               r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
03267               break;
03268             }
03269             case VerticalTileEdgeVirtualPixelMethod:
03270             {
03271               y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
03272               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
03273                 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
03274                 *virtual_nexus,exception);
03275               r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
03276               break;
03277             }
03278             case BackgroundVirtualPixelMethod:
03279             case BlackVirtualPixelMethod:
03280             case GrayVirtualPixelMethod:
03281             case TransparentVirtualPixelMethod:
03282             case MaskVirtualPixelMethod:
03283             case WhiteVirtualPixelMethod:
03284             {
03285               p=virtual_pixel;
03286               r=virtual_metacontent;
03287               break;
03288             }
03289             case EdgeVirtualPixelMethod:
03290             case CheckerTileVirtualPixelMethod:
03291             {
03292               x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
03293               y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
03294               if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
03295                 {
03296                   p=virtual_pixel;
03297                   r=virtual_metacontent;
03298                   break;
03299                 }
03300               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
03301                 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
03302                 exception);
03303               r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
03304               break;
03305             }
03306             case HorizontalTileVirtualPixelMethod:
03307             {
03308               if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
03309                 {
03310                   p=virtual_pixel;
03311                   r=virtual_metacontent;
03312                   break;
03313                 }
03314               x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
03315               y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
03316               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
03317                 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
03318                 exception);
03319               r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
03320               break;
03321             }
03322             case VerticalTileVirtualPixelMethod:
03323             {
03324               if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
03325                 {
03326                   p=virtual_pixel;
03327                   r=virtual_metacontent;
03328                   break;
03329                 }
03330               x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
03331               y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
03332               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
03333                 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
03334                 exception);
03335               r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
03336               break;
03337             }
03338           }
03339           if (p == (const Quantum *) NULL)
03340             break;
03341           (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
03342             sizeof(*p));
03343           q+=cache_info->number_channels;
03344           if ((s != (void *) NULL) && (r != (const void *) NULL))
03345             {
03346               (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
03347               s+=cache_info->metacontent_extent;
03348             }
03349           continue;
03350         }
03351       /*
03352         Transfer a run of pixels.
03353       */
03354       p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
03355         length,1UL,*virtual_nexus,exception);
03356       if (p == (const Quantum *) NULL)
03357         break;
03358       r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
03359       (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
03360       q+=length*cache_info->number_channels;
03361       if ((r != (void *) NULL) && (s != (const void *) NULL))
03362         {
03363           (void) memcpy(s,r,(size_t) length);
03364           s+=length*cache_info->metacontent_extent;
03365         }
03366     }
03367   }
03368   /*
03369     Free resources.
03370   */
03371   if (virtual_metacontent != (void *) NULL)
03372     virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
03373   virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
03374   return(pixels);
03375 }
03376 
03377 /*
03378 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
03379 %                                                                             %
03380 %                                                                             %
03381 %                                                                             %
03382 +   G e t V i r t u a l P i x e l C a c h e                                   %
03383 %                                                                             %
03384 %                                                                             %
03385 %                                                                             %
03386 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
03387 %
03388 %  GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
03389 %  cache as defined by the geometry parameters.   A pointer to the pixels
03390 %  is returned if the pixels are transferred, otherwise a NULL is returned.
03391 %
03392 %  The format of the GetVirtualPixelCache() method is:
03393 %
03394 %      const Quantum *GetVirtualPixelCache(const Image *image,
03395 %        const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
03396 %        const ssize_t y,const size_t columns,const size_t rows,
03397 %        ExceptionInfo *exception)
03398 %
03399 %  A description of each parameter follows:
03400 %
03401 %    o image: the image.
03402 %
03403 %    o virtual_pixel_method: the virtual pixel method.
03404 %
03405 %    o x,y,columns,rows:  These values define the perimeter of a region of
03406 %      pixels.
03407 %
03408 %    o exception: return any errors or warnings in this structure.
03409 %
03410 */
03411 static const Quantum *GetVirtualPixelCache(const Image *image,
03412   const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
03413   const size_t columns,const size_t rows,ExceptionInfo *exception)
03414 {
03415   CacheInfo
03416     *cache_info;
03417 
03418   const int
03419     id = GetOpenMPThreadId();
03420 
03421   const Quantum
03422     *p;
03423 
03424   assert(image != (const Image *) NULL);
03425   assert(image->signature == MagickSignature);
03426   assert(image->cache != (Cache) NULL);
03427   cache_info=(CacheInfo *) image->cache;
03428   assert(cache_info->signature == MagickSignature);
03429   assert(id < (int) cache_info->number_threads);
03430   p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
03431     cache_info->nexus_info[id],exception);
03432   return(p);
03433 }
03434 
03435 /*
03436 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
03437 %                                                                             %
03438 %                                                                             %
03439 %                                                                             %
03440 %   G e t V i r t u a l P i x e l Q u e u e                                   %
03441 %                                                                             %
03442 %                                                                             %
03443 %                                                                             %
03444 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
03445 %
03446 %  GetVirtualPixelQueue() returns the virtual pixels associated corresponding
03447 %  with the last call to QueueAuthenticPixels() or GetVirtualPixels().
03448 %
03449 %  The format of the GetVirtualPixelQueue() method is:
03450 %
03451 %      const Quantum *GetVirtualPixelQueue(const Image image)
03452 %
03453 %  A description of each parameter follows:
03454 %
03455 %    o image: the image.
03456 %
03457 */
03458 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
03459 {
03460   CacheInfo
03461     *cache_info;
03462 
03463   const int
03464     id = GetOpenMPThreadId();
03465 
03466   assert(image != (const Image *) NULL);
03467   assert(image->signature == MagickSignature);
03468   assert(image->cache != (Cache) NULL);
03469   cache_info=(CacheInfo *) image->cache;
03470   assert(cache_info->signature == MagickSignature);
03471   if (cache_info->methods.get_virtual_pixels_handler !=
03472        (GetVirtualPixelsHandler) NULL)
03473     return(cache_info->methods.get_virtual_pixels_handler(image));
03474   assert(id < (int) cache_info->number_threads);
03475   return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
03476 }
03477 
03478 /*
03479 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
03480 %                                                                             %
03481 %                                                                             %
03482 %                                                                             %
03483 %   G e t V i r t u a l P i x e l s                                           %
03484 %                                                                             %
03485 %                                                                             %
03486 %                                                                             %
03487 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
03488 %
03489 %  GetVirtualPixels() returns an immutable pixel region. If the
03490 %  region is successfully accessed, a pointer to it is returned, otherwise
03491 %  NULL is returned.  The returned pointer may point to a temporary working
03492 %  copy of the pixels or it may point to the original pixels in memory.
03493 %  Performance is maximized if the selected region is part of one row, or one
03494 %  or more full rows, since there is opportunity to access the pixels in-place
03495 %  (without a copy) if the image is in memory, or in a memory-mapped file.  The
03496 %  returned pointer must *never* be deallocated by the user.
03497 %
03498 %  Pixels accessed via the returned pointer represent a simple array of type
03499 %  Quantum.  If the image type is CMYK or the storage class is PseudoClass,
03500 %  call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
03501 %  access the meta-content (of type void) corresponding to the the
03502 %  region.
03503 %
03504 %  If you plan to modify the pixels, use GetAuthenticPixels() instead.
03505 %
03506 %  Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
03507 %  safe.  In a threaded environment, use GetCacheViewVirtualPixels() or
03508 %  GetCacheViewAuthenticPixels() instead.
03509 %
03510 %  The format of the GetVirtualPixels() method is:
03511 %
03512 %      const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
03513 %        const ssize_t y,const size_t columns,const size_t rows,
03514 %        ExceptionInfo *exception)
03515 %
03516 %  A description of each parameter follows:
03517 %
03518 %    o image: the image.
03519 %
03520 %    o x,y,columns,rows:  These values define the perimeter of a region of
03521 %      pixels.
03522 %
03523 %    o exception: return any errors or warnings in this structure.
03524 %
03525 */
03526 MagickExport const Quantum *GetVirtualPixels(const Image *image,
03527   const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
03528   ExceptionInfo *exception)
03529 {
03530   CacheInfo
03531     *cache_info;
03532 
03533   const int
03534     id = GetOpenMPThreadId();
03535 
03536   const Quantum
03537     *p;
03538 
03539   assert(image != (const Image *) NULL);
03540   assert(image->signature == MagickSignature);
03541   assert(image->cache != (Cache) NULL);
03542   cache_info=(CacheInfo *) image->cache;
03543   assert(cache_info->signature == MagickSignature);
03544   if (cache_info->methods.get_virtual_pixel_handler !=
03545        (GetVirtualPixelHandler) NULL)
03546     return(cache_info->methods.get_virtual_pixel_handler(image,
03547       GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
03548   assert(id < (int) cache_info->number_threads);
03549   p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
03550     columns,rows,cache_info->nexus_info[id],exception);
03551   return(p);
03552 }
03553 
03554 /*
03555 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
03556 %                                                                             %
03557 %                                                                             %
03558 %                                                                             %
03559 +   G e t V i r t u a l P i x e l s F r o m C a c h e                         %
03560 %                                                                             %
03561 %                                                                             %
03562 %                                                                             %
03563 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
03564 %
03565 %  GetVirtualPixelsCache() returns the pixels associated corresponding with the
03566 %  last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
03567 %
03568 %  The format of the GetVirtualPixelsCache() method is:
03569 %
03570 %      Quantum *GetVirtualPixelsCache(const Image *image)
03571 %
03572 %  A description of each parameter follows:
03573 %
03574 %    o image: the image.
03575 %
03576 */
03577 static const Quantum *GetVirtualPixelsCache(const Image *image)
03578 {
03579   CacheInfo
03580     *cache_info;
03581 
03582   const int
03583     id = GetOpenMPThreadId();
03584 
03585   assert(image != (const Image *) NULL);
03586   assert(image->signature == MagickSignature);
03587   assert(image->cache != (Cache) NULL);
03588   cache_info=(CacheInfo *) image->cache;
03589   assert(cache_info->signature == MagickSignature);
03590   assert(id < (int) cache_info->number_threads);
03591   return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
03592 }
03593 
03594 /*
03595 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
03596 %                                                                             %
03597 %                                                                             %
03598 %                                                                             %
03599 +   G e t V i r t u a l P i x e l s N e x u s                                 %
03600 %                                                                             %
03601 %                                                                             %
03602 %                                                                             %
03603 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
03604 %
03605 %  GetVirtualPixelsNexus() returns the pixels associated with the specified
03606 %  cache nexus.
03607 %
03608 %  The format of the GetVirtualPixelsNexus() method is:
03609 %
03610 %      const Quantum *GetVirtualPixelsNexus(const Cache cache,
03611 %        NexusInfo *nexus_info)
03612 %
03613 %  A description of each parameter follows:
03614 %
03615 %    o cache: the pixel cache.
03616 %
03617 %    o nexus_info: the cache nexus to return the colormap pixels.
03618 %
03619 */
03620 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
03621   NexusInfo *nexus_info)
03622 {
03623   CacheInfo
03624     *cache_info;
03625 
03626   assert(cache != (Cache) NULL);
03627   cache_info=(CacheInfo *) cache;
03628   assert(cache_info->signature == MagickSignature);
03629   if (cache_info->storage_class == UndefinedClass)
03630     return((Quantum *) NULL);
03631   return((const Quantum *) nexus_info->pixels);
03632 }
03633 
03634 /*
03635 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
03636 %                                                                             %
03637 %                                                                             %
03638 %                                                                             %
03639 +   O p e n P i x e l C a c h e                                               %
03640 %                                                                             %
03641 %                                                                             %
03642 %                                                                             %
03643 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
03644 %
03645 %  OpenPixelCache() allocates the pixel cache.  This includes defining the cache
03646 %  dimensions, allocating space for the image pixels and optionally the
03647 %  metacontent, and memory mapping the cache if it is disk based.  The cache
03648 %  nexus array is initialized as well.
03649 %
03650 %  The format of the OpenPixelCache() method is:
03651 %
03652 %      MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
03653 %        ExceptionInfo *exception)
03654 %
03655 %  A description of each parameter follows:
03656 %
03657 %    o image: the image.
03658 %
03659 %    o mode: ReadMode, WriteMode, or IOMode.
03660 %
03661 %    o exception: return any errors or warnings in this structure.
03662 %
03663 */
03664 
03665 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
03666 {
03667   cache_info->mapped=MagickFalse;
03668   cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
03669     cache_info->length);
03670   if (cache_info->pixels == (Quantum *) NULL)
03671     {
03672       cache_info->mapped=MagickTrue;
03673       cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
03674         cache_info->length);
03675     }
03676 }
03677 
03678 static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
03679 {
03680   CacheInfo
03681     *cache_info;
03682 
03683   MagickOffsetType
03684     count,
03685     extent,
03686     offset;
03687 
03688   cache_info=(CacheInfo *) image->cache;
03689   if (image->debug != MagickFalse)
03690     {
03691       char
03692         format[MaxTextExtent],
03693         message[MaxTextExtent];
03694 
03695       (void) FormatMagickSize(length,MagickFalse,format);
03696       (void) FormatLocaleString(message,MaxTextExtent,
03697         "extend %s (%s[%d], disk, %s)",cache_info->filename,
03698         cache_info->cache_filename,cache_info->file,format);
03699       (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
03700     }
03701   if (length != (MagickSizeType) ((MagickOffsetType) length))
03702     return(MagickFalse);
03703   extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
03704   if (extent < 0)
03705     return(MagickFalse);
03706   if ((MagickSizeType) extent >= length)
03707     return(MagickTrue);
03708   offset=(MagickOffsetType) length-1;
03709   count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
03710   return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
03711 }
03712 
03713 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
03714   ExceptionInfo *exception)
03715 {
03716   CacheInfo
03717     *cache_info,
03718     source_info;
03719 
03720   char
03721     format[MaxTextExtent],
03722     message[MaxTextExtent];
03723 
03724   MagickBooleanType
03725     status;
03726 
03727   MagickSizeType
03728     length,
03729     number_pixels;
03730 
03731   PixelChannelMap
03732     *p,
03733     *q;
03734 
03735   size_t
03736     columns,
03737     packet_size;
03738 
03739   assert(image != (const Image *) NULL);
03740   assert(image->signature == MagickSignature);
03741   assert(image->cache != (Cache) NULL);
03742   if (image->debug != MagickFalse)
03743     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
03744   if ((image->columns == 0) || (image->rows == 0))
03745     ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
03746   cache_info=(CacheInfo *) image->cache;
03747   assert(cache_info->signature == MagickSignature);
03748   source_info=(*cache_info);
03749   source_info.file=(-1);
03750   (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
03751     image->filename,(double) GetImageIndexInList(image));
03752   cache_info->storage_class=image->storage_class;
03753   cache_info->colorspace=image->colorspace;
03754   cache_info->matte=image->matte;
03755   cache_info->mask=image->mask;
03756   cache_info->rows=image->rows;
03757   cache_info->columns=image->columns;
03758   InitializePixelChannelMap(image);
03759   cache_info->number_channels=GetPixelChannels(image);
03760   (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
03761     sizeof(*image->channel_map));
03762   cache_info->metacontent_extent=image->metacontent_extent;
03763   cache_info->mode=mode;
03764   if (image->ping != MagickFalse)
03765     {
03766       cache_info->type=PingCache;
03767       cache_info->pixels=(Quantum *) NULL;
03768       cache_info->metacontent=(void *) NULL;
03769       cache_info->length=0;
03770       return(MagickTrue);
03771     }
03772   number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
03773   packet_size=cache_info->number_channels*sizeof(Quantum);
03774   if (image->metacontent_extent != 0)
03775     packet_size+=cache_info->metacontent_extent;
03776   length=number_pixels*packet_size;
03777   columns=(size_t) (length/cache_info->rows/packet_size);
03778   if (cache_info->columns != columns)
03779     ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
03780       image->filename);
03781   cache_info->length=length;
03782   p=cache_info->channel_map;
03783   q=source_info.channel_map;
03784   if ((cache_info->type != UndefinedCache) &&
03785       (cache_info->columns <= source_info.columns) &&
03786       (cache_info->rows <= source_info.rows) &&
03787       (cache_info->number_channels <= source_info.number_channels) &&
03788       (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
03789       (cache_info->metacontent_extent <= source_info.metacontent_extent))
03790     {
03791       /*
03792         Inline pixel cache clone optimization.
03793       */
03794       if ((cache_info->columns == source_info.columns) &&
03795           (cache_info->rows == source_info.rows) &&
03796           (cache_info->number_channels == source_info.number_channels) &&
03797           (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
03798           (cache_info->metacontent_extent == source_info.metacontent_extent))
03799         return(MagickTrue);
03800       return(ClonePixelCachePixels(cache_info,&source_info,exception));
03801     }
03802   status=AcquireMagickResource(AreaResource,cache_info->length);
03803   length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
03804     cache_info->metacontent_extent);
03805   if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
03806     {
03807       status=AcquireMagickResource(MemoryResource,cache_info->length);
03808       if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
03809           (cache_info->type == MemoryCache))
03810         {
03811           AllocatePixelCachePixels(cache_info);
03812           if (cache_info->pixels == (Quantum *) NULL)
03813             cache_info->pixels=source_info.pixels;
03814           else
03815             {
03816               /*
03817                 Create memory pixel cache.
03818               */
03819               status=MagickTrue;
03820               if (image->debug != MagickFalse)
03821                 {
03822                   (void) FormatMagickSize(cache_info->length,MagickTrue,format);
03823                   (void) FormatLocaleString(message,MaxTextExtent,
03824                     "open %s (%s memory, %.20gx%.20gx%.20g %s)",
03825                     cache_info->filename,cache_info->mapped != MagickFalse ?
03826                     "anonymous" : "heap",(double) cache_info->columns,(double)
03827                     cache_info->rows,(double) cache_info->number_channels,
03828                     format);
03829                   (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
03830                     message);
03831                 }
03832               cache_info->type=MemoryCache;
03833               cache_info->metacontent=(void *) NULL;
03834               if (cache_info->metacontent_extent != 0)
03835                 cache_info->metacontent=(void *) (cache_info->pixels+
03836                   number_pixels*cache_info->number_channels);
03837               if ((source_info.storage_class != UndefinedClass) &&
03838                   (mode != ReadMode))
03839                 {
03840                   status=ClonePixelCachePixels(cache_info,&source_info,
03841                     exception);
03842                   RelinquishPixelCachePixels(&source_info);
03843                 }
03844               return(status);
03845             }
03846         }
03847       RelinquishMagickResource(MemoryResource,cache_info->length);
03848     }
03849   /*
03850     Create pixel cache on disk.
03851   */
03852   status=AcquireMagickResource(DiskResource,cache_info->length);
03853   if (status == MagickFalse)
03854     {
03855       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
03856         "CacheResourcesExhausted","`%s'",image->filename);
03857       return(MagickFalse);
03858     }
03859   if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
03860     {
03861       (void) ClosePixelCacheOnDisk(cache_info);
03862       *cache_info->cache_filename='\0';
03863     }
03864   if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
03865     {
03866       RelinquishMagickResource(DiskResource,cache_info->length);
03867       ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
03868         image->filename);
03869       return(MagickFalse);
03870     }
03871   status=ExtendCache(image,(MagickSizeType) cache_info->offset+
03872     cache_info->length);
03873   if (status == MagickFalse)
03874     {
03875       ThrowFileException(exception,CacheError,"UnableToExtendCache",
03876         image->filename);
03877       return(MagickFalse);
03878     }
03879   length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
03880     cache_info->metacontent_extent);
03881   if (length != (MagickSizeType) ((size_t) length))
03882     cache_info->type=DiskCache;
03883   else
03884     {
03885       status=AcquireMagickResource(MapResource,cache_info->length);
03886       if ((status == MagickFalse) && (cache_info->type != MapCache) &&
03887           (cache_info->type != MemoryCache))
03888         cache_info->type=DiskCache;
03889       else
03890         {
03891           cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
03892             cache_info->offset,(size_t) cache_info->length);
03893           if (cache_info->pixels == (Quantum *) NULL)
03894             {
03895               cache_info->type=DiskCache;
03896               cache_info->pixels=source_info.pixels;
03897             }
03898           else
03899             {
03900               /*
03901                 Create file-backed memory-mapped pixel cache.
03902               */
03903               status=MagickTrue;
03904               (void) ClosePixelCacheOnDisk(cache_info);
03905               cache_info->type=MapCache;
03906               cache_info->mapped=MagickTrue;
03907               cache_info->metacontent=(void *) NULL;
03908               if (cache_info->metacontent_extent != 0)
03909                 cache_info->metacontent=(void *) (cache_info->pixels+
03910                   number_pixels*cache_info->number_channels);
03911               if ((source_info.storage_class != UndefinedClass) &&
03912                   (mode != ReadMode))
03913                 {
03914                   status=ClonePixelCachePixels(cache_info,&source_info,
03915                     exception);
03916                   RelinquishPixelCachePixels(&source_info);
03917                 }
03918               if (image->debug != MagickFalse)
03919                 {
03920                   (void) FormatMagickSize(cache_info->length,<