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