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-2010 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 I n f o                                 %
00161 %                                                                             %
00162 %                                                                             %
00163 %                                                                             %
00164 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00165 %
00166 %  AcquirePixelCacheInfo() acquires a pixel cache.
00167 %
00168 %  The format of the AcquirePixelCacheInfo() method is:
00169 %
00170 %      Cache AcquirePixelCacheInfo(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 AcquirePixelCacheInfo(const unsigned long number_threads)
00178 {
00179   CacheInfo
00180     *cache_info;
00181 
00182   cache_info=(CacheInfo *) AcquireCachelineMemory(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->colorspace=RGBColorspace;
00188   cache_info->file=(-1);
00189   cache_info->id=GetMagickThreadId();
00190   cache_info->number_threads=number_threads;
00191   if (number_threads == 0)
00192     cache_info->number_threads=GetOpenMPMaximumThreads();
00193   cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
00194   if (cache_info->nexus_info == (NexusInfo **) NULL)
00195     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
00196   GetPixelCacheMethods(&cache_info->methods);
00197   cache_info->reference_count=1;
00198   cache_info->semaphore=AllocateSemaphoreInfo();
00199   cache_info->disk_semaphore=AllocateSemaphoreInfo();
00200   cache_info->debug=IsEventLogging();
00201   cache_info->signature=MagickSignature;
00202   if ((cache_resources == (SplayTreeInfo *) NULL) &&
00203       (instantiate_cache == MagickFalse))
00204     {
00205       AcquireSemaphoreInfo(&cache_semaphore);
00206       if ((cache_resources == (SplayTreeInfo *) NULL) &&
00207           (instantiate_cache == MagickFalse))
00208         {
00209           cache_resources=NewSplayTree((int (*)(const void *,const void *))
00210             NULL,(void *(*)(void *)) NULL,(void *(*)(void *)) NULL);
00211           instantiate_cache=MagickTrue;
00212         }
00213       RelinquishSemaphoreInfo(cache_semaphore);
00214     }
00215   (void) AddValueToSplayTree(cache_resources,cache_info,cache_info);
00216   return((Cache ) cache_info);
00217 }
00218 
00219 /*
00220 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00221 %                                                                             %
00222 %                                                                             %
00223 %                                                                             %
00224 %   A c q u i r e P i x e l C a c h e N e x u s                               %
00225 %                                                                             %
00226 %                                                                             %
00227 %                                                                             %
00228 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00229 %
00230 %  AcquirePixelCacheNexus() allocates the NexusInfo structure.
00231 %
00232 %  The format of the AcquirePixelCacheNexus method is:
00233 %
00234 %      NexusInfo **AcquirePixelCacheNexus(const unsigned long number_threads)
00235 %
00236 %  A description of each parameter follows:
00237 %
00238 %    o number_threads: the number of nexus threads.
00239 %
00240 */
00241 MagickExport NexusInfo **AcquirePixelCacheNexus(
00242   const unsigned long number_threads)
00243 {
00244   register long
00245     i;
00246 
00247   NexusInfo
00248     **nexus_info;
00249 
00250   nexus_info=(NexusInfo **) AcquireCachelineMemory(number_threads*
00251     sizeof(*nexus_info));
00252   if (nexus_info == (NexusInfo **) NULL)
00253     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
00254   for (i=0; i < (long) number_threads; i++)
00255   {
00256     nexus_info[i]=(NexusInfo *) AcquireCachelineMemory(sizeof(**nexus_info));
00257     if (nexus_info[i] == (NexusInfo *) NULL)
00258       ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
00259     (void) ResetMagickMemory(nexus_info[i],0,sizeof(*nexus_info[i]));
00260     nexus_info[i]->signature=MagickSignature;
00261   }
00262   return(nexus_info);
00263 }
00264 
00265 /*
00266 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00267 %                                                                             %
00268 %                                                                             %
00269 %                                                                             %
00270 +   C l i p P i x e l C a c h e N e x u s                                     %
00271 %                                                                             %
00272 %                                                                             %
00273 %                                                                             %
00274 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00275 %
00276 %  ClipPixelCacheNexus() clips the cache nexus as defined by the image clip
00277 %  mask.  The method returns MagickTrue if the pixel region is clipped,
00278 %  otherwise MagickFalse.
00279 %
00280 %  The format of the ClipPixelCacheNexus() method is:
00281 %
00282 %      MagickBooleanType ClipPixelCacheNexus(Image *image,NexusInfo *nexus_info,
00283 %        ExceptionInfo *exception)
00284 %
00285 %  A description of each parameter follows:
00286 %
00287 %    o image: the image.
00288 %
00289 %    o nexus_info: the cache nexus to clip.
00290 %
00291 %    o exception: return any errors or warnings in this structure.
00292 %
00293 */
00294 static MagickBooleanType ClipPixelCacheNexus(Image *image,
00295   NexusInfo *nexus_info,ExceptionInfo *exception)
00296 {
00297   CacheInfo
00298     *cache_info;
00299 
00300   MagickSizeType
00301     number_pixels;
00302 
00303   NexusInfo
00304     **clip_nexus,
00305     **image_nexus;
00306 
00307   register const PixelPacket
00308     *__restrict r;
00309 
00310   register IndexPacket
00311     *__restrict nexus_indexes,
00312     *__restrict indexes;
00313 
00314   register long
00315     i;
00316 
00317   register PixelPacket
00318     *__restrict p,
00319     *__restrict q;
00320 
00321   /*
00322     Apply clip mask.
00323   */
00324   if (image->debug != MagickFalse)
00325     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00326   if (image->clip_mask == (Image *) NULL)
00327     return(MagickFalse);
00328   cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
00329   if (cache_info == (Cache) NULL)
00330     return(MagickFalse);
00331   image_nexus=AcquirePixelCacheNexus(1);
00332   clip_nexus=AcquirePixelCacheNexus(1);
00333   if ((image_nexus == (NexusInfo **) NULL) ||
00334       (clip_nexus == (NexusInfo **) NULL))
00335     ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
00336   p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,nexus_info->region.y,
00337     nexus_info->region.width,nexus_info->region.height,image_nexus[0],
00338     exception);
00339   indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
00340   q=nexus_info->pixels;
00341   nexus_indexes=nexus_info->indexes;
00342   r=GetVirtualPixelsFromNexus(image->clip_mask,MaskVirtualPixelMethod,
00343     nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
00344     nexus_info->region.height,clip_nexus[0],exception);
00345   number_pixels=(MagickSizeType) nexus_info->region.width*
00346     nexus_info->region.height;
00347   for (i=0; i < (long) number_pixels; i++)
00348   {
00349     if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
00350       break;
00351     if (PixelIntensityToQuantum(r) > ((Quantum) QuantumRange/2))
00352       {
00353         q->red=p->red;
00354         q->green=p->green;
00355         q->blue=p->blue;
00356         q->opacity=p->opacity;
00357         if (cache_info->active_index_channel != MagickFalse)
00358           nexus_indexes[i]=indexes[i];
00359       }
00360     p++;
00361     q++;
00362     r++;
00363   }
00364   clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
00365   image_nexus=DestroyPixelCacheNexus(image_nexus,1);
00366   if (i < (long) number_pixels)
00367     return(MagickFalse);
00368   return(MagickTrue);
00369 }
00370 
00371 /*
00372 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00373 %                                                                             %
00374 %                                                                             %
00375 %                                                                             %
00376 +   C l o n e P i x e l C a c h e N e x u s                                   %
00377 %                                                                             %
00378 %                                                                             %
00379 %                                                                             %
00380 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00381 %
00382 %  ClonePixelCacheNexus() clones the source cache nexus to the destination
00383 %  nexus.
00384 %
00385 %  The format of the ClonePixelCacheNexus() method is:
00386 %
00387 %      MagickBooleanType ClonePixelCacheNexus(CacheInfo *destination,
00388 %        CacheInfo *source,ExceptionInfo *exception)
00389 %
00390 %  A description of each parameter follows:
00391 %
00392 %    o destination: the destination cache nexus.
00393 %
00394 %    o source: the source cache nexus.
00395 %
00396 %    o exception: return any errors or warnings in this structure.
00397 %
00398 */
00399 
00400 static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
00401   NexusInfo *nexus_info,ExceptionInfo *exception)
00402 {
00403   if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
00404     return(MagickFalse);
00405   nexus_info->mapped=MagickFalse;
00406   nexus_info->cache=(PixelPacket *) AcquireMagickMemory((size_t)
00407     nexus_info->length);
00408   if (nexus_info->cache == (PixelPacket *) NULL)
00409     {
00410       nexus_info->mapped=MagickTrue;
00411       nexus_info->cache=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
00412         nexus_info->length);
00413     }
00414   if (nexus_info->cache == (PixelPacket *) NULL)
00415     {
00416       (void) ThrowMagickException(exception,GetMagickModule(),
00417         ResourceLimitError,"MemoryAllocationFailed","`%s'",
00418         cache_info->filename);
00419       return(MagickFalse);
00420     }
00421   return(MagickTrue);
00422 }
00423 
00424 static MagickBooleanType ClonePixelCacheNexus(CacheInfo *destination,
00425   CacheInfo *source,ExceptionInfo *exception)
00426 {
00427   MagickBooleanType
00428     status;
00429 
00430   MagickSizeType
00431     number_pixels;
00432 
00433   register long
00434     i;
00435 
00436   register const NexusInfo
00437     *p;
00438 
00439   register NexusInfo
00440     *q;
00441 
00442   status=MagickTrue;
00443   for (i=0; i < (long) source->number_threads; i++)
00444   {
00445     p=source->nexus_info[i];
00446     q=destination->nexus_info[i];
00447     q->mapped=p->mapped;
00448     q->region=p->region;
00449     q->length=p->length;
00450     q->cache=p->cache;
00451     q->pixels=p->pixels;
00452     q->indexes=p->indexes;
00453     if (p->cache != (PixelPacket *) NULL)
00454       {
00455         status=AcquireCacheNexusPixels(source,q,exception);
00456         if (status != MagickFalse)
00457           {
00458             (void) CopyMagickMemory(q->cache,p->cache,(size_t) p->length);
00459             q->pixels=q->cache;
00460             q->indexes=(IndexPacket *) NULL;
00461             number_pixels=(MagickSizeType) q->region.width*q->region.height;
00462             if (p->indexes != (IndexPacket *) NULL)
00463               q->indexes=(IndexPacket *) (q->pixels+number_pixels);
00464           }
00465       }
00466   }
00467   return(status);
00468 }
00469 
00470 /*
00471 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00472 %                                                                             %
00473 %                                                                             %
00474 %                                                                             %
00475 +   C l o n e P i x e l C a c h e                                             %
00476 %                                                                             %
00477 %                                                                             %
00478 %                                                                             %
00479 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
00480 %  ClonePixelCache() clones the source pixel cache to the destination cache.
00481 %
00482 %  The format of the ClonePixelCache() method is:
00483 %
00484 %      MagickBooleanType ClonePixelCache(CacheInfo *cache_info,
00485 %        CacheInfo *source_info,ExceptionInfo *exception)
00486 %
00487 %  A description of each parameter follows:
00488 %
00489 %    o cache_info: the pixel cache.
00490 %
00491 %    o source_info: the source pixel cache.
00492 %
00493 %    o exception: return any errors or warnings in this structure.
00494 %
00495 */
00496 
00497 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
00498 {
00499   int
00500     status;
00501 
00502   AcquireSemaphoreInfo(&cache_info->disk_semaphore);
00503   status=close(cache_info->file);
00504   cache_info->file=(-1);
00505   RelinquishMagickResource(FileResource,1);
00506   RelinquishSemaphoreInfo(cache_info->disk_semaphore);
00507   return(status == -1 ? MagickFalse : MagickTrue);
00508 }
00509 
00510 static void LimitPixelCacheDescriptors(void)
00511 {
00512   register CacheInfo
00513     *p,
00514     *q;
00515 
00516   /*
00517     Limit # of open file descriptors.
00518   */
00519   if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
00520     return;
00521   AcquireSemaphoreInfo(&cache_semaphore);
00522   if (cache_resources == (SplayTreeInfo *) NULL)
00523     {
00524       RelinquishSemaphoreInfo(cache_semaphore);
00525       return;
00526     }
00527   ResetSplayTreeIterator(cache_resources);
00528   p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
00529   while (p != (CacheInfo *) NULL)
00530   {
00531     if ((p->type == DiskCache) && (p->file != -1))
00532       {
00533         if (IsMagickThreadEqual(p->id) != MagickFalse)
00534           break;
00535       }
00536     p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
00537   }
00538   for (q=p; p != (CacheInfo *) NULL; )
00539   {
00540     if ((p->type == DiskCache) && (p->file != -1) &&
00541         (p->timestamp < q->timestamp))
00542       {
00543         if (IsMagickThreadEqual(p->id) != MagickFalse)
00544           q=p;
00545       }
00546     p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
00547   }
00548   if (q != (CacheInfo *) NULL)
00549     (void) ClosePixelCacheOnDisk(q);  /* relinquish least recently used cache */
00550   RelinquishSemaphoreInfo(cache_semaphore);
00551 }
00552 
00553 static inline MagickSizeType MagickMax(const MagickSizeType x,
00554   const MagickSizeType y)
00555 {
00556   if (x > y)
00557     return(x);
00558   return(y);
00559 }
00560 
00561 static inline MagickSizeType MagickMin(const MagickSizeType x,
00562   const MagickSizeType y)
00563 {
00564   if (x < y)
00565     return(x);
00566   return(y);
00567 }
00568 
00569 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
00570   const MapMode mode)
00571 {
00572   int
00573     file;
00574 
00575   /*
00576     Open pixel cache on disk.
00577   */
00578   AcquireSemaphoreInfo(&cache_info->disk_semaphore);
00579   if (cache_info->file != -1)
00580     {
00581       RelinquishSemaphoreInfo(cache_info->disk_semaphore);
00582       return(MagickTrue);  /* cache already open */
00583     }
00584   LimitPixelCacheDescriptors();
00585   if (*cache_info->cache_filename == '\0')
00586     file=AcquireUniqueFileResource(cache_info->cache_filename);
00587   else
00588     switch (mode)
00589     {
00590       case ReadMode:
00591       {
00592         file=open(cache_info->cache_filename,O_RDONLY | O_BINARY);
00593         break;
00594       }
00595       case WriteMode:
00596       {
00597         file=open(cache_info->cache_filename,O_WRONLY | O_CREAT | O_BINARY |
00598           O_EXCL,S_MODE);
00599         if (file == -1)
00600           file=open(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
00601         break;
00602       }
00603       case IOMode:
00604       default:
00605       {
00606         file=open(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
00607           O_EXCL,S_MODE);
00608         if (file == -1)
00609           file=open(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
00610         break;
00611       }
00612     }
00613   if (file == -1)
00614     {
00615       RelinquishSemaphoreInfo(cache_info->disk_semaphore);
00616       return(MagickFalse);
00617     }
00618   (void) AcquireMagickResource(FileResource,1);
00619   cache_info->file=file;
00620   cache_info->timestamp=time(0);
00621   RelinquishSemaphoreInfo(cache_info->disk_semaphore);
00622   return(MagickTrue);
00623 }
00624 
00625 static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
00626   const MagickOffsetType offset,const MagickSizeType length,
00627   unsigned char *__restrict buffer)
00628 {
00629   register MagickOffsetType
00630     i;
00631 
00632   ssize_t
00633     count;
00634 
00635 #if !defined(MAGICKCORE_HAVE_PREAD)
00636   (void) LockSemaphoreInfo(cache_info->disk_semaphore);
00637   cache_info->timestamp=time(0);
00638   if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
00639     {
00640       (void) UnlockSemaphoreInfo(cache_info->disk_semaphore);
00641       return((MagickOffsetType) -1);
00642     }
00643 #endif
00644   count=0;
00645   for (i=0; i < (MagickOffsetType) length; i+=count)
00646   {
00647 #if !defined(MAGICKCORE_HAVE_PREAD)
00648     count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
00649       (MagickSizeType) SSIZE_MAX));
00650 #else
00651     count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
00652       (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
00653 #endif
00654     if (count > 0)
00655       continue;
00656     count=0;
00657     if (errno != EINTR)
00658       {
00659         i=(-1);
00660         break;
00661       }
00662   }
00663 #if !defined(MAGICKCORE_HAVE_PREAD)
00664   (void) UnlockSemaphoreInfo(cache_info->disk_semaphore);
00665 #endif
00666   return(i);
00667 }
00668 
00669 static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
00670   const MagickOffsetType offset,const MagickSizeType length,
00671   const unsigned char *__restrict buffer)
00672 {
00673   register MagickOffsetType
00674     i;
00675 
00676   ssize_t
00677     count;
00678 
00679 #if !defined(MAGICKCORE_HAVE_PWRITE)
00680   (void) LockSemaphoreInfo(cache_info->disk_semaphore);
00681   cache_info->timestamp=time(0);
00682   if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
00683     {
00684       (void) UnlockSemaphoreInfo(cache_info->disk_semaphore);
00685       return((MagickOffsetType) -1);
00686     }
00687 #endif
00688   count=0;
00689   for (i=0; i < (MagickOffsetType) length; i+=count)
00690   {
00691 #if !defined(MAGICKCORE_HAVE_PWRITE)
00692     count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
00693       (MagickSizeType) SSIZE_MAX));
00694 #else
00695     count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
00696       (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
00697 #endif
00698     if (count > 0)
00699       continue;
00700     count=0;
00701     if (errno != EINTR)
00702       {
00703         i=(-1);
00704         break;
00705       }
00706   }
00707 #if !defined(MAGICKCORE_HAVE_PWRITE)
00708   (void) UnlockSemaphoreInfo(cache_info->disk_semaphore);
00709 #endif
00710   return(i);
00711 }
00712 
00713 static MagickBooleanType CloneDiskToDiskPixelCache(CacheInfo *clone_info,
00714   CacheInfo *cache_info,ExceptionInfo *exception)
00715 {
00716   MagickOffsetType
00717     count,
00718     offset,
00719     source_offset;
00720 
00721   MagickSizeType
00722     length;
00723 
00724   register long
00725     y;
00726 
00727   register PixelPacket
00728     *__restrict pixels;
00729 
00730   unsigned long
00731     columns,
00732     rows;
00733 
00734   if (cache_info->debug != MagickFalse)
00735     (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
00736   if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
00737     {
00738       ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
00739         clone_info->cache_filename);
00740       return(MagickFalse);
00741     }
00742   if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
00743     {
00744       ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
00745         cache_info->cache_filename);
00746       return(MagickFalse);
00747     }
00748   columns=(unsigned long) MagickMin(clone_info->columns,cache_info->columns);
00749   rows=(unsigned long) MagickMin(clone_info->rows,cache_info->rows);
00750   if ((clone_info->active_index_channel != MagickFalse) &&
00751       (cache_info->active_index_channel != MagickFalse))
00752     {
00753       register IndexPacket
00754         *indexes;
00755 
00756       /*
00757         Clone cache indexes.
00758       */
00759       length=MagickMax(clone_info->columns,cache_info->columns)*
00760         sizeof(*indexes);
00761       indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
00762       if (indexes == (IndexPacket *) NULL)
00763         {
00764           (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
00765             "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
00766           return(MagickFalse);
00767         }
00768       (void) ResetMagickMemory(indexes,0,(size_t) length);
00769       length=columns*sizeof(*indexes);
00770       source_offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
00771         sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
00772       offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
00773         sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
00774       for (y=0; y < (long) rows; y++)
00775       {
00776         source_offset-=cache_info->columns*sizeof(*indexes);
00777         count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
00778           length,(unsigned char *) indexes);
00779         if ((MagickSizeType) count != length)
00780           break;
00781         offset-=clone_info->columns*sizeof(*indexes);
00782         count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
00783           (unsigned char *) indexes);
00784         if ((MagickSizeType) count != length)
00785           break;
00786       }
00787       if (y < (long) rows)
00788         {
00789           indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
00790           ThrowFileException(exception,CacheError,"UnableToCloneCache",
00791             cache_info->cache_filename);
00792           return(MagickFalse);
00793         }
00794       if (clone_info->columns > cache_info->columns)
00795         {
00796           length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
00797           (void) ResetMagickMemory(indexes,0,(size_t) length);
00798           offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
00799             sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
00800           for (y=0; y < (long) rows; y++)
00801           {
00802             offset-=clone_info->columns*sizeof(*indexes);
00803             count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
00804               length,(unsigned char *) indexes);
00805             if ((MagickSizeType) count != length)
00806               break;
00807           }
00808           if (y < (long) rows)
00809             {
00810               indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
00811               ThrowFileException(exception,CacheError,"UnableToCloneCache",
00812                 cache_info->cache_filename);
00813               return(MagickFalse);
00814             }
00815         }
00816       indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
00817     }
00818   /*
00819     Clone cache pixels.
00820   */
00821   length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
00822   pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
00823   if (pixels == (PixelPacket *) NULL)
00824     {
00825       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
00826         "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
00827       return(MagickFalse);
00828     }
00829   (void) ResetMagickMemory(pixels,0,(size_t) length);
00830   length=columns*sizeof(*pixels);
00831   source_offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
00832   offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
00833   for (y=0; y < (long) rows; y++)
00834   {
00835     source_offset-=cache_info->columns*sizeof(*pixels);
00836     count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
00837       length,(unsigned char *) pixels);
00838     if ((MagickSizeType) count != length)
00839       break;
00840     offset-=clone_info->columns*sizeof(*pixels);
00841     count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
00842       (unsigned char *) pixels);
00843     if ((MagickSizeType) count != length)
00844       break;
00845   }
00846   if (y < (long) rows)
00847     {
00848       pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
00849       ThrowFileException(exception,CacheError,"UnableToCloneCache",
00850         cache_info->cache_filename);
00851       return(MagickFalse);
00852     }
00853   if (clone_info->columns > cache_info->columns)
00854     {
00855       offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
00856         sizeof(*pixels);
00857       length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
00858       (void) ResetMagickMemory(pixels,0,(size_t) length);
00859       for (y=0; y < (long) rows; y++)
00860       {
00861         offset-=clone_info->columns*sizeof(*pixels);
00862         count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
00863           (unsigned char *) pixels);
00864         if ((MagickSizeType) count != length)
00865           break;
00866       }
00867       if (y < (long) rows)
00868         {
00869           pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
00870           ThrowFileException(exception,CacheError,"UnableToCloneCache",
00871             cache_info->cache_filename);
00872           return(MagickFalse);
00873         }
00874     }
00875   pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
00876   return(MagickTrue);
00877 }
00878 
00879 static MagickBooleanType CloneDiskToMemoryPixelCache(CacheInfo *clone_info,
00880   CacheInfo *cache_info,ExceptionInfo *exception)
00881 {
00882   MagickOffsetType
00883     count,
00884     offset;
00885 
00886   MagickSizeType
00887     length;
00888 
00889   register long
00890     y;
00891 
00892   register PixelPacket
00893     *__restrict pixels,
00894     *__restrict q;
00895 
00896   unsigned long
00897     columns,
00898     rows;
00899 
00900   if (cache_info->debug != MagickFalse)
00901     (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
00902   if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
00903     {
00904       ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
00905         cache_info->cache_filename);
00906       return(MagickFalse);
00907     }
00908   columns=(unsigned long) MagickMin(clone_info->columns,cache_info->columns);
00909   rows=(unsigned long) MagickMin(clone_info->rows,cache_info->rows);
00910   if ((clone_info->active_index_channel != MagickFalse) &&
00911       (cache_info->active_index_channel != MagickFalse))
00912     {
00913       register IndexPacket
00914         *indexes,
00915         *q;
00916 
00917       /*
00918         Clone cache indexes.
00919       */
00920       length=MagickMax(clone_info->columns,cache_info->columns)*
00921         sizeof(*indexes);
00922       indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
00923       if (indexes == (IndexPacket *) NULL)
00924         {
00925           (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
00926             "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
00927           return(MagickFalse);
00928         }
00929       (void) ResetMagickMemory(indexes,0,(size_t) length);
00930       length=columns*sizeof(IndexPacket);
00931       offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
00932         sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
00933       q=clone_info->indexes+clone_info->columns*rows;
00934       for (y=0; y < (long) rows; y++)
00935       {
00936         offset-=cache_info->columns*sizeof(IndexPacket);
00937         count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,
00938           length,(unsigned char *) indexes);
00939         if ((MagickSizeType) count != length)
00940           break;
00941         q-=clone_info->columns;
00942         (void) CopyMagickMemory(q,indexes,(size_t) length);
00943         if ((MagickSizeType) count != length)
00944           break;
00945       }
00946       if (y < (long) rows)
00947         {
00948           indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
00949           ThrowFileException(exception,CacheError,"UnableToCloneCache",
00950             cache_info->cache_filename);
00951           return(MagickFalse);
00952         }
00953       indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
00954     }
00955   /*
00956     Clone cache pixels.
00957   */
00958   length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
00959   pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
00960   if (pixels == (PixelPacket *) NULL)
00961     {
00962       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
00963         "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
00964       return(MagickFalse);
00965     }
00966   (void) ResetMagickMemory(pixels,0,(size_t) length);
00967   length=columns*sizeof(*pixels);
00968   offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
00969   q=clone_info->pixels+clone_info->columns*rows;
00970   for (y=0; y < (long) rows; y++)
00971   {
00972     offset-=cache_info->columns*sizeof(*pixels);
00973     count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,length,
00974       (unsigned char *) pixels);
00975     if ((MagickSizeType) count != length)
00976       break;
00977     q-=clone_info->columns;
00978     (void) CopyMagickMemory(q,pixels,(size_t) length);
00979   }
00980   if (y < (long) rows)
00981     {
00982       pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
00983       ThrowFileException(exception,CacheError,"UnableToCloneCache",
00984         cache_info->cache_filename);
00985       return(MagickFalse);
00986     }
00987   pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
00988   return(MagickTrue);
00989 }
00990 
00991 static MagickBooleanType CloneMemoryToDiskPixelCache(CacheInfo *clone_info,
00992   CacheInfo *cache_info,ExceptionInfo *exception)
00993 {
00994   MagickOffsetType
00995     count,
00996     offset;
00997 
00998   MagickSizeType
00999     length;
01000 
01001   register long
01002     y;
01003 
01004   register PixelPacket
01005     *__restrict p,
01006     *__restrict pixels;
01007 
01008   unsigned long
01009     columns,
01010     rows;
01011 
01012   if (cache_info->debug != MagickFalse)
01013     (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
01014   if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
01015     {
01016       ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
01017         clone_info->cache_filename);
01018       return(MagickFalse);
01019     }
01020   columns=(unsigned long) MagickMin(clone_info->columns,cache_info->columns);
01021   rows=(unsigned long) MagickMin(clone_info->rows,cache_info->rows);
01022   if ((clone_info->active_index_channel != MagickFalse) &&
01023       (cache_info->active_index_channel != MagickFalse))
01024     {
01025       register IndexPacket
01026         *p,
01027         *indexes;
01028 
01029       /*
01030         Clone cache indexes.
01031       */
01032       length=MagickMax(clone_info->columns,cache_info->columns)*
01033         sizeof(*indexes);
01034       indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
01035       if (indexes == (IndexPacket *) NULL)
01036         {
01037           (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
01038             "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
01039           return(MagickFalse);
01040         }
01041       (void) ResetMagickMemory(indexes,0,(size_t) length);
01042       length=columns*sizeof(*indexes);
01043       p=cache_info->indexes+cache_info->columns*rows;
01044       offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
01045         sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
01046       for (y=0; y < (long) rows; y++)
01047       {
01048         p-=cache_info->columns;
01049         (void) CopyMagickMemory(indexes,p,(size_t) length);
01050         offset-=clone_info->columns*sizeof(*indexes);
01051         count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
01052           (unsigned char *) indexes);
01053         if ((MagickSizeType) count != length)
01054           break;
01055       }
01056       if (y < (long) rows)
01057         {
01058           indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
01059           ThrowFileException(exception,CacheError,"UnableToCloneCache",
01060             cache_info->cache_filename);
01061           return(MagickFalse);
01062         }
01063       if (clone_info->columns > cache_info->columns)
01064         {
01065           length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
01066           (void) ResetMagickMemory(indexes,0,(size_t) length);
01067           offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
01068             sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
01069           for (y=0; y < (long) rows; y++)
01070           {
01071             offset-=clone_info->columns*sizeof(*indexes);
01072             count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
01073               length,(unsigned char *) indexes);
01074             if ((MagickSizeType) count != length)
01075               break;
01076           }
01077           if (y < (long) rows)
01078             {
01079               indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
01080               ThrowFileException(exception,CacheError,"UnableToCloneCache",
01081                 cache_info->cache_filename);
01082               return(MagickFalse);
01083             }
01084         }
01085       indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
01086     }
01087   /*
01088     Clone cache pixels.
01089   */
01090   length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
01091   pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
01092   if (pixels == (PixelPacket *) NULL)
01093     {
01094       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
01095         "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
01096       return(MagickFalse);
01097     }
01098   (void) ResetMagickMemory(pixels,0,(size_t) length);
01099   length=columns*sizeof(*pixels);
01100   p=cache_info->pixels+cache_info->columns*rows;
01101   offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
01102   for (y=0; y < (long) rows; y++)
01103   {
01104     p-=cache_info->columns;
01105     (void) CopyMagickMemory(pixels,p,(size_t) length);
01106     offset-=clone_info->columns*sizeof(*pixels);
01107     count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
01108       (unsigned char *) pixels);
01109     if ((MagickSizeType) count != length)
01110       break;
01111   }
01112   if (y < (long) rows)
01113     {
01114       pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
01115       ThrowFileException(exception,CacheError,"UnableToCloneCache",
01116         cache_info->cache_filename);
01117       return(MagickFalse);
01118     }
01119   if (clone_info->columns > cache_info->columns)
01120     {
01121       offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
01122         sizeof(*pixels);
01123       length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
01124       (void) ResetMagickMemory(pixels,0,(size_t) length);
01125       for (y=0; y < (long) rows; y++)
01126       {
01127         offset-=clone_info->columns*sizeof(*pixels);
01128         count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
01129           (unsigned char *) pixels);
01130         if ((MagickSizeType) count != length)
01131           break;
01132       }
01133       if (y < (long) rows)
01134         {
01135           pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
01136           ThrowFileException(exception,CacheError,"UnableToCloneCache",
01137             cache_info->cache_filename);
01138           return(MagickFalse);
01139         }
01140     }
01141   pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
01142   return(MagickTrue);
01143 }
01144 
01145 static MagickBooleanType CloneMemoryToMemoryPixelCache(CacheInfo *clone_info,
01146   CacheInfo *cache_info,ExceptionInfo *magick_unused(exception))
01147 {
01148   register long
01149     y;
01150 
01151   register PixelPacket
01152     *__restrict pixels,
01153     *__restrict source_pixels;
01154 
01155   size_t
01156     length;
01157 
01158   unsigned long
01159     columns,
01160     rows;
01161 
01162   if (cache_info->debug != MagickFalse)
01163     (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
01164   columns=(unsigned long) MagickMin(clone_info->columns,cache_info->columns);
01165   rows=(unsigned long) MagickMin(clone_info->rows,cache_info->rows);
01166   if ((clone_info->active_index_channel != MagickFalse) &&
01167       (cache_info->active_index_channel != MagickFalse))
01168     {
01169       register IndexPacket
01170         *indexes,
01171         *source_indexes;
01172 
01173       /*
01174         Clone cache indexes.
01175       */
01176       length=columns*sizeof(*indexes);
01177       if (clone_info->columns == cache_info->columns)
01178         (void) CopyMagickMemory(clone_info->indexes,cache_info->indexes,
01179           length*rows);
01180       else
01181         {
01182           source_indexes=cache_info->indexes+cache_info->columns*rows;
01183           indexes=clone_info->indexes+clone_info->columns*rows;
01184           for (y=0; y < (long) rows; y++)
01185           {
01186             source_indexes-=cache_info->columns;
01187             indexes-=clone_info->columns;
01188             (void) CopyMagickMemory(indexes,source_indexes,length);
01189           }
01190           if (clone_info->columns > cache_info->columns)
01191             {
01192               length=(clone_info->columns-cache_info->columns)*
01193                 sizeof(*indexes);
01194               indexes=clone_info->indexes+clone_info->columns*rows+
01195                 cache_info->columns;
01196               for (y=0; y < (long) rows; y++)
01197               {
01198                 indexes-=clone_info->columns;
01199                 (void) ResetMagickMemory(indexes,0,length);
01200               }
01201             }
01202         }
01203     }
01204   /*
01205     Clone cache pixels.
01206   */
01207   length=columns*sizeof(*pixels);
01208   if (clone_info->columns == cache_info->columns)
01209     (void) CopyMagickMemory(clone_info->pixels,cache_info->pixels,length*rows);
01210   else
01211     {
01212       source_pixels=cache_info->pixels+cache_info->columns*rows;
01213       pixels=clone_info->pixels+clone_info->columns*rows;
01214       for (y=0; y < (long) rows; y++)
01215       {
01216         source_pixels-=cache_info->columns;
01217         pixels-=clone_info->columns;
01218         (void) CopyMagickMemory(pixels,source_pixels,length);
01219       }
01220       if (clone_info->columns > cache_info->columns)
01221         {
01222           length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
01223           pixels=clone_info->pixels+clone_info->columns*rows+
01224             cache_info->columns;
01225           for (y=0; y < (long) rows; y++)
01226           {
01227             pixels-=clone_info->columns;
01228             (void) ResetMagickMemory(pixels,0,length);
01229           }
01230         }
01231     }
01232   return(MagickTrue);
01233 }
01234 
01235 static MagickBooleanType ClonePixelCache(CacheInfo *clone_info,
01236   CacheInfo *cache_info,ExceptionInfo *exception)
01237 {
01238   if ((clone_info->type != DiskCache) && (cache_info->type != DiskCache))
01239     return(CloneMemoryToMemoryPixelCache(clone_info,cache_info,exception));
01240   if ((clone_info->type == DiskCache) && (cache_info->type == DiskCache))
01241     return(CloneDiskToDiskPixelCache(clone_info,cache_info,exception));
01242   if (cache_info->type == DiskCache)
01243     return(CloneDiskToMemoryPixelCache(clone_info,cache_info,exception));
01244   return(CloneMemoryToDiskPixelCache(clone_info,cache_info,exception));
01245 }
01246 
01247 /*
01248 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01249 %                                                                             %
01250 %                                                                             %
01251 %                                                                             %
01252 +   C l o n e P i x e l C a c h e M e t h o d s                               %
01253 %                                                                             %
01254 %                                                                             %
01255 %                                                                             %
01256 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01257 %
01258 %  ClonePixelCacheMethods() clones the pixel cache methods from one cache to
01259 %  another.
01260 %
01261 %  The format of the ClonePixelCacheMethods() method is:
01262 %
01263 %      void ClonePixelCacheMethods(Cache clone,const Cache cache)
01264 %
01265 %  A description of each parameter follows:
01266 %
01267 %    o clone: Specifies a pointer to a Cache structure.
01268 %
01269 %    o cache: the pixel cache.
01270 %
01271 */
01272 MagickExport void ClonePixelCacheMethods(Cache clone,const Cache cache)
01273 {
01274   CacheInfo
01275     *cache_info,
01276     *source_info;
01277 
01278   assert(clone != (Cache) NULL);
01279   source_info=(CacheInfo *) clone;
01280   assert(source_info->signature == MagickSignature);
01281   if (source_info->debug != MagickFalse)
01282     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
01283       source_info->filename);
01284   assert(cache != (Cache) NULL);
01285   cache_info=(CacheInfo *) cache;
01286   assert(cache_info->signature == MagickSignature);
01287   source_info->methods=cache_info->methods;
01288 }
01289 
01290 /*
01291 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01292 %                                                                             %
01293 %                                                                             %
01294 %                                                                             %
01295 +   D e s t r o y I m a g e P i x e l s                                       %
01296 %                                                                             %
01297 %                                                                             %
01298 %                                                                             %
01299 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01300 %
01301 %  DestroyImagePixels() deallocates memory associated with the pixel cache.
01302 %
01303 %  The format of the DestroyImagePixels() method is:
01304 %
01305 %      void DestroyImagePixels(Image *image)
01306 %
01307 %  A description of each parameter follows:
01308 %
01309 %    o image: the image.
01310 %
01311 */
01312 MagickExport void DestroyImagePixels(Image *image)
01313 {
01314   CacheInfo
01315     *cache_info;
01316 
01317   assert(image != (const Image *) NULL);
01318   assert(image->signature == MagickSignature);
01319   if (image->debug != MagickFalse)
01320     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01321   assert(image->cache != (Cache) NULL);
01322   cache_info=(CacheInfo *) image->cache;
01323   assert(cache_info->signature == MagickSignature);
01324   if (cache_info->methods.destroy_pixel_handler == (DestroyPixelHandler) NULL)
01325     return;
01326   cache_info->methods.destroy_pixel_handler(image);
01327 }
01328 
01329 /*
01330 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01331 %                                                                             %
01332 %                                                                             %
01333 %                                                                             %
01334 +   D e s t r o y P i x e l C a c h e                                         %
01335 %                                                                             %
01336 %                                                                             %
01337 %                                                                             %
01338 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01339 %
01340 %  DestroyPixelCache() deallocates memory associated with the pixel cache.
01341 %
01342 %  The format of the DestroyPixelCache() method is:
01343 %
01344 %      void DestroyPixelCache(Image *image)
01345 %
01346 %  A description of each parameter follows:
01347 %
01348 %    o image: the image.
01349 %
01350 */
01351 static void DestroyPixelCache(Image *image)
01352 {
01353   assert(image != (Image *) NULL);
01354   assert(image->signature == MagickSignature);
01355   if (image->debug != MagickFalse)
01356     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01357   if (image->cache == (void *) NULL)
01358     return;
01359   image->cache=DestroyPixelCacheInfo(image->cache);
01360 }
01361 
01362 /*
01363 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01364 %                                                                             %
01365 %                                                                             %
01366 %                                                                             %
01367 +   D e s t r o y P i x e l C a c h e I n f o                                 %
01368 %                                                                             %
01369 %                                                                             %
01370 %                                                                             %
01371 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01372 %
01373 %  DestroyPixelCacheInfo() deallocates memory associated with the pixel cache.
01374 %
01375 %  The format of the DestroyPixelCacheInfo() method is:
01376 %
01377 %      Cache DestroyPixelCacheInfo(Cache cache)
01378 %
01379 %  A description of each parameter follows:
01380 %
01381 %    o cache: the pixel cache.
01382 %
01383 */
01384 
01385 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
01386 {
01387   switch (cache_info->type)
01388   {
01389     case MemoryCache:
01390     {
01391       if (cache_info->mapped == MagickFalse)
01392         cache_info->pixels=(PixelPacket *) RelinquishMagickMemory(
01393           cache_info->pixels);
01394       else
01395         cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,
01396           (size_t) cache_info->length);
01397       RelinquishMagickResource(MemoryResource,cache_info->length);
01398       break;
01399     }
01400     case MapCache:
01401     {
01402       cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,(size_t)
01403         cache_info->length);
01404       RelinquishMagickResource(MapResource,cache_info->length);
01405     }
01406     case DiskCache:
01407     {
01408       if (cache_info->file != -1)
01409         (void) ClosePixelCacheOnDisk(cache_info);
01410       RelinquishMagickResource(DiskResource,cache_info->length);
01411       break;
01412     }
01413     default:
01414       break;
01415   }
01416   cache_info->type=UndefinedCache;
01417   cache_info->mapped=MagickFalse;
01418   cache_info->indexes=(IndexPacket *) NULL;
01419 }
01420 
01421 MagickExport Cache DestroyPixelCacheInfo(Cache cache)
01422 {
01423   CacheInfo
01424     *cache_info;
01425 
01426   CacheType
01427     type;
01428 
01429   assert(cache != (Cache) NULL);
01430   cache_info=(CacheInfo *) cache;
01431   assert(cache_info->signature == MagickSignature);
01432   if (cache_info->debug != MagickFalse)
01433     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
01434       cache_info->filename);
01435   (void) LockSemaphoreInfo(cache_info->semaphore);
01436   cache_info->reference_count--;
01437   if (cache_info->reference_count != 0)
01438     {
01439       (void) UnlockSemaphoreInfo(cache_info->semaphore);
01440       return((Cache) NULL);
01441     }
01442   (void) UnlockSemaphoreInfo(cache_info->semaphore);
01443   if (cache_resources != (SplayTreeInfo *) NULL)
01444     (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
01445   type=cache_info->type;
01446   RelinquishPixelCachePixels(cache_info);
01447   if ((type == MapCache) || (type == DiskCache))
01448     (void) RelinquishUniqueFileResource(cache_info->cache_filename);
01449   *cache_info->cache_filename='\0';
01450   if (cache_info->nexus_info != (NexusInfo **) NULL)
01451     cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
01452       cache_info->number_threads);
01453   if (cache_info->debug != MagickFalse)
01454     {
01455       char
01456         message[MaxTextExtent];
01457 
01458       (void) FormatMagickString(message,MaxTextExtent,"destroy %s",
01459         cache_info->filename);
01460       (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
01461     }
01462   if (cache_info->random_info != (RandomInfo *) NULL)
01463     cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
01464   cache_info->signature=(~MagickSignature);
01465   if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
01466     DestroySemaphoreInfo(&cache_info->disk_semaphore);
01467   if (cache_info->semaphore != (SemaphoreInfo *) NULL)
01468     DestroySemaphoreInfo(&cache_info->semaphore);
01469   cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
01470   cache=(Cache) NULL;
01471   return(cache);
01472 }
01473 
01474 /*
01475 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01476 %                                                                             %
01477 %                                                                             %
01478 %                                                                             %
01479 +   D e s t r o y P i x e l C a c h e N e x u s                               %
01480 %                                                                             %
01481 %                                                                             %
01482 %                                                                             %
01483 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01484 %
01485 %  DestroyPixelCacheNexus() destroys a pixel cache nexus.
01486 %
01487 %  The format of the DestroyPixelCacheNexus() method is:
01488 %
01489 %      NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
01490 %        const unsigned long number_threads)
01491 %
01492 %  A description of each parameter follows:
01493 %
01494 %    o nexus_info: the nexus to destroy.
01495 %
01496 %    o number_threads: the number of nexus threads.
01497 %
01498 */
01499 
01500 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
01501 {
01502   if (nexus_info->mapped == MagickFalse)
01503     (void) RelinquishMagickMemory(nexus_info->cache);
01504   else
01505     (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
01506   nexus_info->cache=(PixelPacket *) NULL;
01507   nexus_info->pixels=(PixelPacket *) NULL;
01508   nexus_info->indexes=(IndexPacket *) NULL;
01509   nexus_info->length=0;
01510   nexus_info->mapped=MagickFalse;
01511 }
01512 
01513 MagickExport NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
01514   const unsigned long number_threads)
01515 {
01516   register long
01517     i;
01518 
01519   assert(nexus_info != (NexusInfo **) NULL);
01520   for (i=0; i < (long) number_threads; i++)
01521   {
01522     if (nexus_info[i]->cache != (PixelPacket *) NULL)
01523       RelinquishCacheNexusPixels(nexus_info[i]);
01524     nexus_info[i]->signature=(~MagickSignature);
01525     nexus_info[i]=(NexusInfo *) RelinquishMagickMemory(nexus_info[i]);
01526   }
01527   return((NexusInfo **) RelinquishMagickMemory(nexus_info));
01528 }
01529 
01530 /*
01531 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01532 %                                                                             %
01533 %                                                                             %
01534 %                                                                             %
01535 +   D e s t r o y P i x e l C a c h e R e s o u r c e s                       %
01536 %                                                                             %
01537 %                                                                             %
01538 %                                                                             %
01539 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01540 %
01541 %  DestroyPixelCacheResources() destroys the cache resources.
01542 %
01543 %  The format of the DestroyPixelCacheResources() method is:
01544 %
01545 %      DestroyPixelCacheResources(void)
01546 %
01547 */
01548 MagickExport void DestroyPixelCacheResources(void)
01549 {
01550   AcquireSemaphoreInfo(&cache_semaphore);
01551   if (cache_resources != (SplayTreeInfo *) NULL)
01552     cache_resources=DestroySplayTree(cache_resources);
01553   instantiate_cache=MagickFalse;
01554   RelinquishSemaphoreInfo(cache_semaphore);
01555   DestroySemaphoreInfo(&cache_semaphore);
01556 }
01557 
01558 /*
01559 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01560 %                                                                             %
01561 %                                                                             %
01562 %                                                                             %
01563 +   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                   %
01564 %                                                                             %
01565 %                                                                             %
01566 %                                                                             %
01567 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01568 %
01569 %  GetAuthenticIndexesFromCache() returns the indexes associated with the last
01570 %  call to QueueAuthenticPixelsCache() or GetAuthenticPixelsCache().
01571 %
01572 %  The format of the GetAuthenticIndexesFromCache() method is:
01573 %
01574 %      IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
01575 %
01576 %  A description of each parameter follows:
01577 %
01578 %    o image: the image.
01579 %
01580 */
01581 static IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
01582 {
01583   CacheInfo
01584     *cache_info;
01585 
01586   IndexPacket
01587     *indexes;
01588 
01589   long
01590     id;
01591 
01592   if (image->debug != MagickFalse)
01593     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01594   cache_info=(CacheInfo *) image->cache;
01595   id=GetOpenMPThreadId();
01596   assert(id < (long) cache_info->number_threads);
01597   indexes=GetPixelCacheNexusIndexes(image->cache,cache_info->nexus_info[id]);
01598   return(indexes);
01599 }
01600 
01601 /*
01602 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01603 %                                                                             %
01604 %                                                                             %
01605 %                                                                             %
01606 %   G e t A u t h e n t i c I n d e x Q u e u e                               %
01607 %                                                                             %
01608 %                                                                             %
01609 %                                                                             %
01610 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01611 %
01612 %  GetAuthenticIndexQueue() returns the authentic black channel or the colormap
01613 %  indexes associated with the last call to QueueAuthenticPixels() or
01614 %  GetVirtualPixels().  NULL is returned if the black channel or colormap
01615 %  indexes are not available.
01616 %
01617 %  The format of the GetAuthenticIndexQueue() method is:
01618 %
01619 %      IndexPacket *GetAuthenticIndexQueue(const Image *image)
01620 %
01621 %  A description of each parameter follows:
01622 %
01623 %    o image: the image.
01624 %
01625 */
01626 MagickExport IndexPacket *GetAuthenticIndexQueue(const Image *image)
01627 {
01628   CacheInfo
01629     *cache_info;
01630 
01631   assert(image != (const Image *) NULL);
01632   assert(image->signature == MagickSignature);
01633   if (image->debug != MagickFalse)
01634     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01635   assert(image->cache != (Cache) NULL);
01636   cache_info=(CacheInfo *) image->cache;
01637   assert(cache_info->signature == MagickSignature);
01638   if (cache_info->methods.get_authentic_indexes_from_handler ==
01639        (GetAuthenticIndexesFromHandler) NULL)
01640     return((IndexPacket *) NULL);
01641   return(cache_info->methods.get_authentic_indexes_from_handler(image));
01642 }
01643 
01644 /*
01645 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01646 %                                                                             %
01647 %                                                                             %
01648 %                                                                             %
01649 +   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                     %
01650 %                                                                             %
01651 %                                                                             %
01652 %                                                                             %
01653 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01654 %
01655 %  GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
01656 %  disk pixel cache as defined by the geometry parameters.   A pointer to the
01657 %  pixels is returned if the pixels are transferred, otherwise a NULL is
01658 %  returned.
01659 %
01660 %  The format of the GetAuthenticPixelCacheNexus() method is:
01661 %
01662 %      PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const long x,
01663 %        const long y,const unsigned long columns,const unsigned long rows,
01664 %        NexusInfo *nexus_info,ExceptionInfo *exception)
01665 %
01666 %  A description of each parameter follows:
01667 %
01668 %    o image: the image.
01669 %
01670 %    o x,y,columns,rows:  These values define the perimeter of a region of
01671 %      pixels.
01672 %
01673 %    o nexus_info: the cache nexus to return.
01674 %
01675 %    o exception: return any errors or warnings in this structure.
01676 %
01677 */
01678 
01679 static inline MagickBooleanType IsNexusInCore(const CacheInfo *cache_info,
01680   NexusInfo *nexus_info)
01681 {
01682   MagickOffsetType
01683     offset;
01684 
01685   offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
01686     nexus_info->region.x;
01687   if (nexus_info->pixels != (cache_info->pixels+offset))
01688     return(MagickFalse);
01689   return(MagickTrue);
01690 }
01691 
01692 MagickExport PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const long x,
01693   const long y,const unsigned long columns,const unsigned long rows,
01694   NexusInfo *nexus_info,ExceptionInfo *exception)
01695 {
01696   CacheInfo
01697     *cache_info;
01698 
01699   PixelPacket
01700     *pixels;
01701 
01702   /*
01703     Transfer pixels from the cache.
01704   */
01705   assert(image != (Image *) NULL);
01706   assert(image->signature == MagickSignature);
01707   if (image->debug != MagickFalse)
01708     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01709   pixels=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
01710   if (pixels == (PixelPacket *) NULL)
01711     return((PixelPacket *) NULL);
01712   cache_info=(CacheInfo *) image->cache;
01713   assert(cache_info->signature == MagickSignature);
01714   if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
01715     return(pixels);
01716   if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
01717     return((PixelPacket *) NULL);
01718   if (cache_info->active_index_channel != MagickFalse)
01719     if (ReadPixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse)
01720       return((PixelPacket *) NULL);
01721   return(pixels);
01722 }
01723 
01724 /*
01725 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01726 %                                                                             %
01727 %                                                                             %
01728 %                                                                             %
01729 +   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                     %
01730 %                                                                             %
01731 %                                                                             %
01732 %                                                                             %
01733 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01734 %
01735 %  GetAuthenticPixelsFromCache() returns the pixels associated with the last
01736 %  call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
01737 %
01738 %  The format of the GetAuthenticPixelsFromCache() method is:
01739 %
01740 %      PixelPacket *GetAuthenticPixelsFromCache(const Image image)
01741 %
01742 %  A description of each parameter follows:
01743 %
01744 %    o image: the image.
01745 %
01746 */
01747 static PixelPacket *GetAuthenticPixelsFromCache(const Image *image)
01748 {
01749   CacheInfo
01750     *cache_info;
01751 
01752   long
01753     id;
01754 
01755   PixelPacket
01756     *pixels;
01757 
01758   if (image->debug != MagickFalse)
01759     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01760   cache_info=(CacheInfo *) image->cache;
01761   id=GetOpenMPThreadId();
01762   assert(id < (long) cache_info->number_threads);
01763   pixels=GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]);
01764   return(pixels);
01765 }
01766 
01767 /*
01768 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01769 %                                                                             %
01770 %                                                                             %
01771 %                                                                             %
01772 %   G e t A u t h e n t i c P i x e l Q u e u e                               %
01773 %                                                                             %
01774 %                                                                             %
01775 %                                                                             %
01776 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01777 %
01778 %  GetAuthenticPixelQueue() returns the authentic pixels associated with the
01779 %  last call to QueueAuthenticPixels() or GetAuthenticPixels().
01780 %
01781 %  The format of the GetAuthenticPixelQueue() method is:
01782 %
01783 %      PixelPacket *GetAuthenticPixelQueue(const Image image)
01784 %
01785 %  A description of each parameter follows:
01786 %
01787 %    o image: the image.
01788 %
01789 */
01790 MagickExport PixelPacket *GetAuthenticPixelQueue(const Image *image)
01791 {
01792   CacheInfo
01793     *cache_info;
01794 
01795   assert(image != (const Image *) NULL);
01796   assert(image->signature == MagickSignature);
01797   if (image->debug != MagickFalse)
01798     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01799   assert(image->cache != (Cache) NULL);
01800   cache_info=(CacheInfo *) image->cache;
01801   assert(cache_info->signature == MagickSignature);
01802   if (cache_info->methods.get_authentic_pixels_from_handler ==
01803       (GetAuthenticPixelsFromHandler) NULL)
01804     return((PixelPacket *) NULL);
01805   return(cache_info->methods.get_authentic_pixels_from_handler(image));
01806 }
01807 
01808 /*
01809 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01810 %                                                                             %
01811 %                                                                             %
01812 %                                                                             %
01813 %   G e t A u t h e n t i c P i x e l s                                       %
01814 %                                                                             %
01815 %                                                                             %
01816 %                                                                             %
01817 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01818 %
01819 %  GetAuthenticPixels() obtains a pixel region for read/write access. If the
01820 %  region is successfully accessed, a pointer to a PixelPacket array
01821 %  representing the region is returned, otherwise NULL is returned.
01822 %
01823 %  The returned pointer may point to a temporary working copy of the pixels
01824 %  or it may point to the original pixels in memory. Performance is maximized
01825 %  if the selected region is part of one row, or one or more full rows, since
01826 %  then there is opportunity to access the pixels in-place (without a copy)
01827 %  if the image is in RAM, or in a memory-mapped file. The returned pointer
01828 %  should *never* be deallocated by the user.
01829 %
01830 %  Pixels accessed via the returned pointer represent a simple array of type
01831 %  PixelPacket. If the image type is CMYK or if the storage class is
01832 %  PseduoClass, call GetAuthenticIndexQueue() after invoking
01833 %  GetAuthenticPixels() to obtain the black color component or colormap indexes
01834 %  (of type IndexPacket) corresponding to the region.  Once the PixelPacket
01835 %  (and/or IndexPacket) array has been updated, the changes must be saved back
01836 %  to the underlying image using SyncAuthenticPixels() or they may be lost.
01837 %
01838 %  The format of the GetAuthenticPixels() method is:
01839 %
01840 %      PixelPacket *GetAuthenticPixels(Image *image,const long x,const long y,
01841 %        const unsigned long columns,const unsigned long rows,
01842 %        ExceptionInfo *exception)
01843 %
01844 %  A description of each parameter follows:
01845 %
01846 %    o image: the image.
01847 %
01848 %    o x,y,columns,rows:  These values define the perimeter of a region of
01849 %      pixels.
01850 %
01851 %    o exception: return any errors or warnings in this structure.
01852 %
01853 */
01854 MagickExport PixelPacket *GetAuthenticPixels(Image *image,const long x,
01855   const long y,const unsigned long columns,const unsigned long rows,
01856   ExceptionInfo *exception)
01857 {
01858   CacheInfo
01859     *cache_info;
01860 
01861   PixelPacket
01862     *pixels;
01863 
01864   assert(image != (Image *) NULL);
01865   assert(image->signature == MagickSignature);
01866   if (image->debug != MagickFalse)
01867     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01868   assert(image->cache != (Cache) NULL);
01869   cache_info=(CacheInfo *) image->cache;
01870   assert(cache_info->signature == MagickSignature);
01871   if (cache_info->methods.get_authentic_pixels_handler ==
01872       (GetAuthenticPixelsHandler) NULL)
01873     return((PixelPacket *) NULL);
01874   pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
01875     rows,exception);
01876   return(pixels);
01877 }
01878 
01879 /*
01880 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01881 %                                                                             %
01882 %                                                                             %
01883 %                                                                             %
01884 +   G e t A u t h e n t i c P i x e l s C a c h e                             %
01885 %                                                                             %
01886 %                                                                             %
01887 %                                                                             %
01888 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01889 %
01890 %  GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
01891 %  as defined by the geometry parameters.   A pointer to the pixels is returned
01892 %  if the pixels are transferred, otherwise a NULL is returned.
01893 %
01894 %  The format of the GetAuthenticPixelsCache() method is:
01895 %
01896 %      PixelPacket *GetAuthenticPixelsCache(Image *image,const long x,
01897 %        const long y,const unsigned long columns,const unsigned long rows,
01898 %        ExceptionInfo *exception)
01899 %
01900 %  A description of each parameter follows:
01901 %
01902 %    o image: the image.
01903 %
01904 %    o x,y,columns,rows:  These values define the perimeter of a region of
01905 %      pixels.
01906 %
01907 %    o exception: return any errors or warnings in this structure.
01908 %
01909 */
01910 static PixelPacket *GetAuthenticPixelsCache(Image *image,const long x,
01911   const long y,const unsigned long columns,const unsigned long rows,
01912   ExceptionInfo *exception)
01913 {
01914   CacheInfo
01915     *cache_info;
01916 
01917   long
01918     id;
01919 
01920   PixelPacket
01921     *pixels;
01922 
01923   cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
01924   if (cache_info == (Cache) NULL)
01925     return((PixelPacket *) NULL);
01926   id=GetOpenMPThreadId();
01927   assert(id < (long) cache_info->number_threads);
01928   pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
01929     cache_info->nexus_info[id],exception);
01930   return(pixels);
01931 }
01932 
01933 /*
01934 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01935 %                                                                             %
01936 %                                                                             %
01937 %                                                                             %
01938 +   G e t I m a g e E x t e n t                                               %
01939 %                                                                             %
01940 %                                                                             %
01941 %                                                                             %
01942 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01943 %
01944 %  GetImageExtent() returns the extent of the pixels associated with the
01945 %  last call to QueueAuthenticPixels() or GetAuthenticPixels().
01946 %
01947 %  The format of the GetImageExtent() method is:
01948 %
01949 %      MagickSizeType GetImageExtent(const Image *image)
01950 %
01951 %  A description of each parameter follows:
01952 %
01953 %    o image: the image.
01954 %
01955 */
01956 MagickExport MagickSizeType GetImageExtent(const Image *image)
01957 {
01958   CacheInfo
01959     *cache_info;
01960 
01961   long
01962     id;
01963 
01964   MagickSizeType
01965     extent;
01966 
01967   assert(image != (Image *) NULL);
01968   assert(image->signature == MagickSignature);
01969   if (image->debug != MagickFalse)
01970     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01971   assert(image->cache != (Cache) NULL);
01972   cache_info=(CacheInfo *) image->cache;
01973   assert(cache_info->signature == MagickSignature);
01974   id=GetOpenMPThreadId();
01975   assert(id < (long) cache_info->number_threads);
01976   extent=GetPixelCacheNexusExtent(image->cache,cache_info->nexus_info[id]);
01977   return(extent);
01978 }
01979 
01980 /*
01981 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01982 %                                                                             %
01983 %                                                                             %
01984 %                                                                             %
01985 +   G e t I m a g e P i x e l C a c h e                                       %
01986 %                                                                             %
01987 %                                                                             %
01988 %                                                                             %
01989 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01990 %
01991 %  GetImagePixelCache() ensures that there is only a single reference to the
01992 %  pixel cache to be modified, updating the provided cache pointer to point to
01993 %  a clone of the original pixel cache if necessary.
01994 %
01995 %  The format of the GetImagePixelCache method is:
01996 %
01997 %      Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
01998 %        ExceptionInfo *exception)
01999 %
02000 %  A description of each parameter follows:
02001 %
02002 %    o image: the image.
02003 %
02004 %    o clone: any value other than MagickFalse clones the cache pixels.
02005 %
02006 %    o exception: return any errors or warnings in this structure.
02007 %
02008 */
02009 
02010 static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
02011 {
02012   CacheInfo
02013     *cache_info;
02014 
02015   /*
02016     Does the image match the pixel cache morphology?
02017   */
02018   cache_info=(CacheInfo *) image->cache;
02019   if ((image->storage_class != cache_info->storage_class) ||
02020       (image->colorspace != cache_info->colorspace) ||
02021       (image->columns != cache_info->columns) ||
02022       (image->rows != cache_info->rows) ||
02023       (cache_info->nexus_info == (NexusInfo **) NULL) ||
02024       (cache_info->number_threads < GetOpenMPMaximumThreads()))
02025     return(MagickFalse);
02026   return(MagickTrue);
02027 }
02028 
02029 MagickExport Cache GetImagePixelCache(Image *image,
02030   const MagickBooleanType clone,ExceptionInfo *exception)
02031 {
02032   CacheInfo
02033     *cache_info;
02034 
02035   MagickSizeType
02036     time_limit;
02037 
02038   MagickBooleanType
02039     status;
02040 
02041   if (image->debug != MagickFalse)
02042     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
02043   status=MagickTrue;
02044   (void) LockSemaphoreInfo(image->semaphore);
02045   time_limit=GetMagickResourceLimit(TimeResource);
02046   if (cache_timer == 0)
02047     cache_timer=time((time_t *) NULL);
02048   if ((time_limit != MagickResourceInfinity) &&
02049       ((time((time_t *) NULL)-cache_timer) >= (MagickOffsetType) time_limit))
02050     ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
02051   assert(image->cache != (Cache) NULL);
02052   cache_info=(CacheInfo *) image->cache;
02053   (void) LockSemaphoreInfo(cache_info->semaphore);
02054   if (cache_info->reference_count > 1)
02055     {
02056       Image
02057         clone_image;
02058 
02059       CacheInfo
02060         *clone_info;
02061 
02062       /*
02063         Clone pixel cache.
02064       */
02065       clone_image=(*image);
02066       clone_image.cache=AcquirePixelCacheInfo(cache_info->number_threads);
02067       clone_info=(CacheInfo *) clone_image.cache;
02068       status=ClonePixelCacheNexus(cache_info,clone_info,exception);
02069       if (status != MagickFalse)
02070         {
02071           status=OpenPixelCache(&clone_image,IOMode,exception);
02072           if (status != MagickFalse)
02073             {
02074               if (clone != MagickFalse)
02075                 status=ClonePixelCache(clone_info,cache_info,exception);
02076               if (status != MagickFalse)
02077                 {
02078                   cache_info->reference_count--;
02079                   image->cache=clone_image.cache;
02080                   (void) SetPixelCacheVirtualMethod(image,
02081                     cache_info->virtual_pixel_method);
02082                 }
02083             }
02084         }
02085     }
02086   (void) UnlockSemaphoreInfo(cache_info->semaphore);
02087   if (status != MagickFalse)
02088     {
02089       /*
02090         Ensure the image matches the pixel cache morphology.
02091       */
02092       image->taint=MagickTrue;
02093       image->type=UndefinedType;
02094       if (image->colorspace == GRAYColorspace)
02095         image->colorspace=RGBColorspace;
02096       if (ValidatePixelCacheMorphology(image) == MagickFalse)
02097         status=OpenPixelCache(image,IOMode,exception);
02098     }
02099   (void) UnlockSemaphoreInfo(image->semaphore);
02100   if (status == MagickFalse)
02101     return((Cache) NULL);
02102   return(image->cache);
02103 }
02104 
02105 /*
02106 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02107 %                                                                             %
02108 %                                                                             %
02109 %                                                                             %
02110 %   G e t O n e A u t h e n t i c P i x e l                                   %
02111 %                                                                             %
02112 %                                                                             %
02113 %                                                                             %
02114 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02115 %
02116 %  GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
02117 %  location.  The image background color is returned if an error occurs.
02118 %
02119 %  The format of the GetOneAuthenticPixel() method is:
02120 %
02121 %      MagickBooleanType GetOneAuthenticPixel(const Image image,const long x,
02122 %        const long y,PixelPacket *pixel,ExceptionInfo *exception)
02123 %
02124 %  A description of each parameter follows:
02125 %
02126 %    o image: the image.
02127 %
02128 %    o x,y:  These values define the location of the pixel to return.
02129 %
02130 %    o pixel: return a pixel at the specified (x,y) location.
02131 %
02132 %    o exception: return any errors or warnings in this structure.
02133 %
02134 */
02135 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,const long x,
02136   const long y,PixelPacket *pixel,ExceptionInfo *exception)
02137 {
02138   CacheInfo
02139     *cache_info;
02140 
02141   GetOneAuthenticPixelFromHandler
02142     get_one_authentic_pixel_from_handler;
02143 
02144   MagickBooleanType
02145     status;
02146 
02147   assert(image != (Image *) NULL);
02148   assert(image->signature == MagickSignature);
02149   if (image->debug != MagickFalse)
02150     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
02151   assert(image->cache != (Cache) NULL);
02152   cache_info=(CacheInfo *) image->cache;
02153   assert(cache_info->signature == MagickSignature);
02154   *pixel=image->background_color;
02155   get_one_authentic_pixel_from_handler=
02156     cache_info->methods.get_one_authentic_pixel_from_handler;
02157   if (get_one_authentic_pixel_from_handler ==
02158       (GetOneAuthenticPixelFromHandler) NULL)
02159     return(MagickFalse);
02160   status=cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
02161     pixel,exception);
02162   return(status);
02163 }
02164 
02165 /*
02166 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02167 %                                                                             %
02168 %                                                                             %
02169 %                                                                             %
02170 +   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                 %
02171 %                                                                             %
02172 %                                                                             %
02173 %                                                                             %
02174 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02175 %
02176 %  GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
02177 %  location.  The image background color is returned if an error occurs.
02178 %
02179 %  The format of the GetOneAuthenticPixelFromCache() method is:
02180 %
02181 %      MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
02182 %        const long x,const long y,PixelPacket *pixel,ExceptionInfo *exception)
02183 %
02184 %  A description of each parameter follows:
02185 %
02186 %    o image: the image.
02187 %
02188 %    o x,y:  These values define the location of the pixel to return.
02189 %
02190 %    o pixel: return a pixel at the specified (x,y) location.
02191 %
02192 %    o exception: return any errors or warnings in this structure.
02193 %
02194 */
02195 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
02196   const long x,const long y,PixelPacket *pixel,ExceptionInfo *exception)
02197 {
02198   PixelPacket
02199     *pixels;
02200 
02201   if (image->debug != MagickFalse)
02202     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
02203   *pixel=image->background_color;
02204   pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
02205   if (pixels == (PixelPacket *) NULL)
02206     return(MagickFalse);
02207   *pixel=(*pixels);
02208   return(MagickTrue);
02209 }
02210 
02211 /*
02212 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02213 %                                                                             %
02214 %                                                                             %
02215 %                                                                             %
02216 %   G e t O n e V i r t u a l M a g i c k P i x e l                           %
02217 %                                                                             %
02218 %                                                                             %
02219 %                                                                             %
02220 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02221 %
02222 %  GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
02223 %  location.  The image background color is returned if an error occurs.  If
02224 %  you plan to modify the pixel, use GetOneAuthenticPixel() instead.
02225 %
02226 %  The format of the GetOneVirtualMagickPixel() method is:
02227 %
02228 %      MagickBooleanType GetOneVirtualMagickPixel(const Image image,
02229 %        const long x,const long y,MagickPixelPacket *pixel,
02230 %        ExceptionInfo exception)
02231 %
02232 %  A description of each parameter follows:
02233 %
02234 %    o image: the image.
02235 %
02236 %    o x,y:  these values define the location of the pixel to return.
02237 %
02238 %    o pixel: return a pixel at the specified (x,y) location.
02239 %
02240 %    o exception: return any errors or warnings in this structure.
02241 %
02242 */
02243 MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
02244   const long x,const long y,MagickPixelPacket *pixel,ExceptionInfo *exception)
02245 {
02246   CacheInfo
02247     *cache_info;
02248 
02249   register const IndexPacket
02250     *indexes;
02251 
02252   register const PixelPacket
02253     *p;
02254 
02255   assert(image != (const Image *) NULL);
02256   assert(image->signature == MagickSignature);
02257   assert(image->cache != (Cache) NULL);
02258   cache_info=(CacheInfo *) image->cache;
02259   assert(cache_info->signature == MagickSignature);
02260   GetMagickPixelPacket(image,pixel);
02261   p=GetVirtualPixelCache(image,GetPixelCacheVirtualMethod(image),x,y,1,1,
02262     exception);
02263   if (p == (const PixelPacket *) NULL)
02264     return(MagickFalse);
02265   indexes=GetVirtualIndexQueue(image);
02266   SetMagickPixelPacket(image,p,indexes,pixel);
02267   return(MagickTrue);
02268 }
02269 
02270 /*
02271 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02272 %                                                                             %
02273 %                                                                             %
02274 %                                                                             %
02275 %   G e t O n e V i r t u a l M e t h o d P i x e l                           %
02276 %                                                                             %
02277 %                                                                             %
02278 %                                                                             %
02279 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02280 %
02281 %  GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
02282 %  location as defined by specified pixel method.  The image background color
02283 %  is returned if an error occurs.  If you plan to modify the pixel, use
02284 %  GetOneAuthenticPixel() instead.
02285 %
02286 %  The format of the GetOneVirtualMethodPixel() method is:
02287 %
02288 %      MagickBooleanType GetOneVirtualMethodPixel(const Image image,
02289 %        const VirtualPixelMethod virtual_pixel_method,const long x,
02290 %        const long y,Pixelpacket *pixel,ExceptionInfo exception)
02291 %
02292 %  A description of each parameter follows:
02293 %
02294 %    o image: the image.
02295 %
02296 %    o virtual_pixel_method: the virtual pixel method.
02297 %
02298 %    o x,y:  These values define the location of the pixel to return.
02299 %
02300 %    o pixel: return a pixel at the specified (x,y) location.
02301 %
02302 %    o exception: return any errors or warnings in this structure.
02303 %
02304 */
02305 MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
02306   const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
02307   PixelPacket *pixel,ExceptionInfo *exception)
02308 {
02309   GetOneVirtualPixelFromHandler
02310     get_one_virtual_pixel_from_handler;
02311 
02312   CacheInfo
02313     *cache_info;
02314 
02315   MagickBooleanType
02316     status;
02317 
02318   assert(image != (const Image *) NULL);
02319   assert(image->signature == MagickSignature);
02320   assert(image->cache != (Cache) NULL);
02321   cache_info=(CacheInfo *) image->cache;
02322   assert(cache_info->signature == MagickSignature);
02323   *pixel=image->background_color;
02324   get_one_virtual_pixel_from_handler=
02325     cache_info->methods.get_one_virtual_pixel_from_handler;
02326   if (get_one_virtual_pixel_from_handler ==
02327       (GetOneVirtualPixelFromHandler) NULL)
02328     return(MagickFalse);
02329   status=get_one_virtual_pixel_from_handler(image,virtual_pixel_method,x,y,
02330     pixel,exception);
02331   return(status);
02332 }
02333 
02334 /*
02335 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02336 %                                                                             %
02337 %                                                                             %
02338 %                                                                             %
02339 %   G e t O n e V i r t u a l P i x e l                                       %
02340 %                                                                             %
02341 %                                                                             %
02342 %                                                                             %
02343 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02344 %
02345 %  GetOneVirtualPixel() returns a single virtual pixel at the specified
02346 %  (x,y) location.  The image background color is returned if an error occurs.
02347 %  If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
02348 %
02349 %  The format of the GetOneVirtualPixel() method is:
02350 %
02351 %      MagickBooleanType GetOneVirtualPixel(const Image image,const long x,
02352 %        const long y,PixelPacket *pixel,ExceptionInfo exception)
02353 %
02354 %  A description of each parameter follows:
02355 %
02356 %    o image: the image.
02357 %
02358 %    o x,y:  These values define the location of the pixel to return.
02359 %
02360 %    o pixel: return a pixel at the specified (x,y) location.
02361 %
02362 %    o exception: return any errors or warnings in this structure.
02363 %
02364 */
02365 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
02366   const long x,const long y,PixelPacket *pixel,ExceptionInfo *exception)
02367 {
02368   GetOneVirtualPixelFromHandler
02369     get_one_virtual_pixel_from_handler;
02370 
02371   CacheInfo
02372     *cache_info;
02373 
02374   MagickBooleanType
02375     status;
02376 
02377   assert(image != (const Image *) NULL);
02378   assert(image->signature == MagickSignature);
02379   assert(image->cache != (Cache) NULL);
02380   cache_info=(CacheInfo *) image->cache;
02381   assert(cache_info->signature == MagickSignature);
02382   *pixel=image->background_color;
02383   get_one_virtual_pixel_from_handler=
02384     cache_info->methods.get_one_virtual_pixel_from_handler;
02385   if (get_one_virtual_pixel_from_handler ==
02386       (GetOneVirtualPixelFromHandler) NULL)
02387     return(MagickFalse);
02388   status=get_one_virtual_pixel_from_handler(image,GetPixelCacheVirtualMethod(
02389     image),x,y,pixel,exception);
02390   return(status);
02391 }
02392 
02393 /*
02394 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02395 %                                                                             %
02396 %                                                                             %
02397 %                                                                             %
02398 +   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                     %
02399 %                                                                             %
02400 %                                                                             %
02401 %                                                                             %
02402 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02403 %
02404 %  GetOneVirtualPixelFromCache() returns a single virtual pixel at the
02405 %  specified (x,y) location.  The image background color is returned if an
02406 %  error occurs.
02407 %
02408 %  The format of the GetOneVirtualPixelFromCache() method is:
02409 %
02410 %      MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
02411 %        const VirtualPixelPacket method,const long x,const long y,
02412 %        PixelPacket *pixel,ExceptionInfo *exception)
02413 %
02414 %  A description of each parameter follows:
02415 %
02416 %    o image: the image.
02417 %
02418 %    o virtual_pixel_method: the virtual pixel method.
02419 %
02420 %    o x,y:  These values define the location of the pixel to return.
02421 %
02422 %    o pixel: return a pixel at the specified (x,y) location.
02423 %
02424 %    o exception: return any errors or warnings in this structure.
02425 %
02426 */
02427 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
02428   const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
02429   PixelPacket *pixel,ExceptionInfo *exception)
02430 {
02431   const PixelPacket
02432     *pixels;
02433 
02434   *pixel=image->background_color;
02435   pixels=GetVirtualPixelCache(image,virtual_pixel_method,x,y,1UL,1UL,exception);
02436   if (pixels == (const PixelPacket *) NULL)
02437     return(MagickFalse);
02438   *pixel=(*pixels);
02439   return(MagickTrue);
02440 }
02441 
02442 /*
02443 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02444 %                                                                             %
02445 %                                                                             %
02446 %                                                                             %
02447 +   G e t P i x e l C a c h e C o l o r s p a c e                             %
02448 %                                                                             %
02449 %                                                                             %
02450 %                                                                             %
02451 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02452 %
02453 %  GetPixelCacheColorspace() returns the class type of the pixel cache.
02454 %
02455 %  The format of the GetPixelCacheColorspace() method is:
02456 %
02457 %      Colorspace GetPixelCacheColorspace(Cache cache)
02458 %
02459 %  A description of each parameter follows:
02460 %
02461 %    o cache: the pixel cache.
02462 %
02463 */
02464 MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
02465 {
02466   CacheInfo
02467     *cache_info;
02468 
02469   assert(cache != (Cache) NULL);
02470   cache_info=(CacheInfo *) cache;
02471   assert(cache_info->signature == MagickSignature);
02472   if (cache_info->debug != MagickFalse)
02473     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
02474       cache_info->filename);
02475   return(cache_info->colorspace);
02476 }
02477 
02478 /*
02479 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02480 %                                                                             %
02481 %                                                                             %
02482 %                                                                             %
02483 +   G e t P i x e l C a c h e M e t h o d s                                   %
02484 %                                                                             %
02485 %                                                                             %
02486 %                                                                             %
02487 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02488 %
02489 %  GetPixelCacheMethods() initializes the CacheMethods structure.
02490 %
02491 %  The format of the GetPixelCacheMethods() method is:
02492 %
02493 %      void GetPixelCacheMethods(CacheMethods *cache_methods)
02494 %
02495 %  A description of each parameter follows:
02496 %
02497 %    o cache_methods: Specifies a pointer to a CacheMethods structure.
02498 %
02499 */
02500 MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
02501 {
02502   assert(cache_methods != (CacheMethods *) NULL);
02503   (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
02504   cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
02505   cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
02506   cache_methods->get_virtual_indexes_from_handler=GetVirtualIndexesFromCache;
02507   cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
02508   cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
02509   cache_methods->get_authentic_indexes_from_handler=
02510     GetAuthenticIndexesFromCache;
02511   cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
02512   cache_methods->get_one_authentic_pixel_from_handler=
02513     GetOneAuthenticPixelFromCache;
02514   cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
02515   cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
02516   cache_methods->destroy_pixel_handler=DestroyPixelCache;
02517 }
02518 
02519 /*
02520 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02521 %                                                                             %
02522 %                                                                             %
02523 %                                                                             %
02524 +   G e t P i x e l C a c h e N e x u s E x t e n t                           %
02525 %                                                                             %
02526 %                                                                             %
02527 %                                                                             %
02528 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02529 %
02530 %  GetPixelCacheNexusExtent() returns the extent of the pixels associated with
02531 %  the last call to SetPixelCacheNexusPixels() or GetPixelCacheNexusPixels().
02532 %
02533 %  The format of the GetPixelCacheNexusExtent() method is:
02534 %
02535 %      MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
02536 %        NexusInfo *nexus_info)
02537 %
02538 %  A description of each parameter follows:
02539 %
02540 %    o nexus_info: the nexus info.
02541 %
02542 */
02543 MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
02544   NexusInfo *nexus_info)
02545 {
02546   CacheInfo
02547     *cache_info;
02548 
02549   MagickSizeType
02550     extent;
02551 
02552   if (cache == (Cache) NULL)
02553     return(0);
02554   cache_info=(CacheInfo *) cache;
02555   assert(cache_info->signature == MagickSignature);
02556   extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
02557   if (extent == 0)
02558     return((MagickSizeType) cache_info->columns*cache_info->rows);
02559   return(extent);
02560 }
02561 
02562 /*
02563 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02564 %                                                                             %
02565 %                                                                             %
02566 %                                                                             %
02567 +   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                         %
02568 %                                                                             %
02569 %                                                                             %
02570 %                                                                             %
02571 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02572 %
02573 %  GetPixelCacheNexusIndexes() returns the indexes associated with the
02574 %  specified cache nexus.
02575 %
02576 %  The format of the GetPixelCacheNexusIndexes() method is:
02577 %
02578 %      IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
02579 %        NexusInfo *nexus_info)
02580 %
02581 %  A description of each parameter follows:
02582 %
02583 %    o cache: the pixel cache.
02584 %
02585 %    o nexus_info: the cache nexus to return the colormap indexes.
02586 %
02587 */
02588 MagickExport IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
02589   NexusInfo *nexus_info)
02590 {
02591   CacheInfo
02592     *cache_info;
02593 
02594   if (cache == (Cache) NULL)
02595     return((IndexPacket *) NULL);
02596   cache_info=(CacheInfo *) cache;
02597   assert(cache_info->signature == MagickSignature);
02598   if (cache_info->storage_class == UndefinedClass)
02599     return((IndexPacket *) NULL);
02600   return(nexus_info->indexes);
02601 }
02602 
02603 /*
02604 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02605 %                                                                             %
02606 %                                                                             %
02607 %                                                                             %
02608 +   G e t P i x e l C a c h e N e x u s P i x e l s                           %
02609 %                                                                             %
02610 %                                                                             %
02611 %                                                                             %
02612 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02613 %
02614 %  GetPixelCacheNexusPixels() returns the pixels associated with the specified
02615 %  cache nexus.
02616 %
02617 %  The format of the GetPixelCacheNexusPixels() method is:
02618 %
02619 %      PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
02620 %        NexusInfo *nexus_info)
02621 %
02622 %  A description of each parameter follows:
02623 %
02624 %    o cache: the pixel cache.
02625 %
02626 %    o nexus_info: the cache nexus to return the pixels.
02627 %
02628 */
02629 MagickExport PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
02630   NexusInfo *nexus_info)
02631 {
02632   CacheInfo
02633     *cache_info;
02634 
02635   if (cache == (Cache) NULL)
02636     return((PixelPacket *) NULL);
02637   cache_info=(CacheInfo *) cache;
02638   assert(cache_info->signature == MagickSignature);
02639   if (cache_info->debug != MagickFalse)
02640     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
02641       cache_info->filename);
02642   if (cache_info->storage_class == UndefinedClass)
02643     return((PixelPacket *) NULL);
02644   return(nexus_info->pixels);
02645 }
02646 
02647 /*
02648 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02649 %                                                                             %
02650 %                                                                             %
02651 %                                                                             %
02652 +   G e t P i x e l C a c h e S t o r a e C l a s s                           %
02653 %                                                                             %
02654 %                                                                             %
02655 %                                                                             %
02656 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02657 %
02658 %  GetPixelCacheStorageClass() returns the class type of the pixel cache.
02659 %
02660 %  The format of the GetPixelCacheStorageClass() method is:
02661 %
02662 %      ClassType GetPixelCacheStorageClass(Cache cache)
02663 %
02664 %  A description of each parameter follows:
02665 %
02666 %    o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
02667 %
02668 %    o cache: the pixel cache.
02669 %
02670 */
02671 MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
02672 {
02673   CacheInfo
02674     *cache_info;
02675 
02676   assert(cache != (Cache) NULL);
02677   cache_info=(CacheInfo *) cache;
02678   assert(cache_info->signature == MagickSignature);
02679   if (cache_info->debug != MagickFalse)
02680     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
02681       cache_info->filename);
02682   return(cache_info->storage_class);
02683 }
02684 
02685 /*
02686 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02687 %                                                                             %
02688 %                                                                             %
02689 %                                                                             %
02690 +   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                       %
02691 %                                                                             %
02692 %                                                                             %
02693 %                                                                             %
02694 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02695 %
02696 %  GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
02697 %  pixel cache.  A virtual pixel is any pixel access that is outside the
02698 %  boundaries of the image cache.
02699 %
02700 %  The format of the GetPixelCacheVirtualMethod() method is:
02701 %
02702 %      VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
02703 %
02704 %  A description of each parameter follows:
02705 %
02706 %    o image: the image.
02707 %
02708 */
02709 MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
02710 {
02711   CacheInfo
02712     *cache_info;
02713 
02714   assert(image != (Image *) NULL);
02715   assert(image->signature == MagickSignature);
02716   if (image->debug != MagickFalse)
02717     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
02718   assert(image->cache != (Cache) NULL);
02719   cache_info=(CacheInfo *) image->cache;
02720   assert(cache_info->signature == MagickSignature);
02721   return(cache_info->virtual_pixel_method);
02722 }
02723 
02724 /*
02725 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02726 %                                                                             %
02727 %                                                                             %
02728 %                                                                             %
02729 +   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                       %
02730 %                                                                             %
02731 %                                                                             %
02732 %                                                                             %
02733 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02734 %
02735 %  GetVirtualIndexesFromCache() returns the indexes associated with the last
02736 %  call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
02737 %
02738 %  The format of the GetVirtualIndexesFromCache() method is:
02739 %
02740 %      IndexPacket *GetVirtualIndexesFromCache(const Image *image)
02741 %
02742 %  A description of each parameter follows:
02743 %
02744 %    o image: the image.
02745 %
02746 */
02747 static const IndexPacket *GetVirtualIndexesFromCache(const Image *image)
02748 {
02749   CacheInfo
02750     *cache_info;
02751 
02752   const IndexPacket
02753     *indexes;
02754 
02755   long
02756     id;
02757 
02758   if (image->debug != MagickFalse)
02759     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
02760   cache_info=(CacheInfo *) image->cache;
02761   id=GetOpenMPThreadId();
02762   assert(id < (long) cache_info->number_threads);
02763   indexes=GetVirtualIndexesFromNexus(image->cache,cache_info->nexus_info[id]);
02764   return(indexes);
02765 }
02766 
02767 /*
02768 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02769 %                                                                             %
02770 %                                                                             %
02771 %                                                                             %
02772 +   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                       %
02773 %                                                                             %
02774 %                                                                             %
02775 %                                                                             %
02776 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02777 %
02778 %  GetVirtualIndexesFromNexus() returns the indexes associated with the
02779 %  specified cache nexus.
02780 %
02781 %  The format of the GetVirtualIndexesFromNexus() method is:
02782 %
02783 %      const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
02784 %        NexusInfo *nexus_info)
02785 %
02786 %  A description of each parameter follows:
02787 %
02788 %    o cache: the pixel cache.
02789 %
02790 %    o nexus_info: the cache nexus to return the colormap indexes.
02791 %
02792 */
02793 MagickExport const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
02794   NexusInfo *nexus_info)
02795 {
02796   CacheInfo
02797     *cache_info;
02798 
02799   if (cache == (Cache) NULL)
02800     return((IndexPacket *) NULL);
02801   cache_info=(CacheInfo *) cache;
02802   assert(cache_info->signature == MagickSignature);
02803   if (cache_info->storage_class == UndefinedClass)
02804     return((IndexPacket *) NULL);
02805   return(nexus_info->indexes);
02806 }
02807 
02808 /*
02809 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02810 %                                                                             %
02811 %                                                                             %
02812 %                                                                             %
02813 %   G e t V i r t u a l I n d e x Q u e u e                                   %
02814 %                                                                             %
02815 %                                                                             %
02816 %                                                                             %
02817 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02818 %
02819 %  GetVirtualIndexQueue() returns the virtual black channel or the
02820 %  colormap indexes associated with the last call to QueueAuthenticPixels() or
02821 %  GetVirtualPixels().  NULL is returned if the black channel or colormap
02822 %  indexes are not available.
02823 %
02824 %  The format of the GetVirtualIndexQueue() method is:
02825 %
02826 %      const IndexPacket *GetVirtualIndexQueue(const Image *image)
02827 %
02828 %  A description of each parameter follows:
02829 %
02830 %    o image: the image.
02831 %
02832 */
02833 MagickExport const IndexPacket *GetVirtualIndexQueue(const Image *image)
02834 {
02835   CacheInfo
02836     *cache_info;
02837 
02838   assert(image != (const Image *) NULL);
02839   assert(image->signature == MagickSignature);
02840   if (image->debug != MagickFalse)
02841     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
02842   assert(image->cache != (Cache) NULL);
02843   cache_info=(CacheInfo *) image->cache;
02844   assert(cache_info->signature == MagickSignature);
02845   if (cache_info->methods.get_virtual_indexes_from_handler ==
02846       (GetVirtualIndexesFromHandler) NULL)
02847     return((IndexPacket *) NULL);
02848   return(cache_info->methods.get_virtual_indexes_from_handler(image));
02849 }
02850 
02851 /*
02852 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02853 %                                                                             %
02854 %                                                                             %
02855 %                                                                             %
02856 +   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                         %
02857 %                                                                             %
02858 %                                                                             %
02859 %                                                                             %
02860 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02861 %
02862 %  GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
02863 %  pixel cache as defined by the geometry parameters.   A pointer to the pixels
02864 %  is returned if the pixels are transferred, otherwise a NULL is returned.
02865 %
02866 %  The format of the GetVirtualPixelsFromNexus() method is:
02867 %
02868 %      PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
02869 %        const VirtualPixelMethod method,const long x,const long y,
02870 %        const unsigned long columns,const unsigned long rows,
02871 %        NexusInfo *nexus_info,ExceptionInfo *exception)
02872 %
02873 %  A description of each parameter follows:
02874 %
02875 %    o image: the image.
02876 %
02877 %    o virtual_pixel_method: the virtual pixel method.
02878 %
02879 %    o x,y,columns,rows:  These values define the perimeter of a region of
02880 %      pixels.
02881 %
02882 %    o nexus_info: the cache nexus to acquire.
02883 %
02884 %    o exception: return any errors or warnings in this structure.
02885 %
02886 */
02887 
02888 static long
02889   DitherMatrix[64] =
02890   {
02891      0,  48,  12,  60,   3,  51,  15,  63,
02892     32,  16,  44,  28,  35,  19,  47,  31,
02893      8,  56,   4,  52,  11,  59,   7,  55,
02894     40,  24,  36,  20,  43,  27,  39,  23,
02895      2,  50,  14,  62,   1,  49,  13,  61,
02896     34,  18,  46,  30,  33,  17,  45,  29,
02897     10,  58,   6,  54,   9,  57,   5,  53,
02898     42,  26,  38,  22,  41,  25,  37,  21
02899   };
02900 
02901 static inline long DitherX(const unsigned long columns,const long x)
02902 {
02903   long
02904     index;
02905 
02906   index=x+DitherMatrix[x & 0x07]-32L;
02907   if (index < 0L)
02908     return(0L);
02909   if (index >= (long) columns)
02910     return((long) columns-1L);
02911   return(index);
02912 }
02913 
02914 static inline long DitherY(const unsigned long rows,const long y)
02915 {
02916   long
02917     index;
02918 
02919   index=y+DitherMatrix[y & 0x07]-32L;
02920   if (index < 0L)
02921     return(0L);
02922   if (index >= (long) rows)
02923     return((long) rows-1L);
02924   return(index);
02925 }
02926 
02927 static inline long EdgeX(const unsigned long columns,const long x)
02928 {
02929   if (x < 0L)
02930     return(0L);
02931   if (x >= (long) columns)
02932     return((long) columns-1L);
02933   return(x);
02934 }
02935 
02936 static inline long EdgeY(const unsigned long rows,const long y)
02937 {
02938   if (y < 0L)
02939     return(0L);
02940   if (y >= (long) rows)
02941     return((long) rows-1L);
02942   return(y);
02943 }
02944 
02945 static inline long RandomX(const unsigned long columns,RandomInfo *random_info)
02946 {
02947   return((long) (columns*GetPseudoRandomValue(random_info)));
02948 }
02949 
02950 static inline long RandomY(const unsigned long rows,RandomInfo *random_info)
02951 {
02952   return((long) (rows*GetPseudoRandomValue(random_info)));
02953 }
02954 
02955 /*
02956   VirtualPixelModulo() computes the remainder of dividing offset by extent.  It
02957   returns not only the quotient (tile the offset falls in) but also the positive
02958   remainer within that tile such that 0 <= remainder < extent.  This method is
02959   essentially a ldiv() using a floored modulo division rather than the normal
02960   default truncated modulo division.
02961 */
02962 static inline MagickModulo VirtualPixelModulo(const long offset,
02963   const unsigned long extent)
02964 {
02965   MagickModulo
02966     modulo;
02967 
02968   modulo.quotient=offset/(long) extent;
02969   if (offset < 0L)
02970     modulo.quotient--;
02971   modulo.remainder=offset-modulo.quotient*(long) extent;
02972   return(modulo);
02973 }
02974 
02975 MagickExport const PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
02976   const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
02977   const unsigned long columns,const unsigned long rows,NexusInfo *nexus_info,
02978   ExceptionInfo *exception)
02979 {
02980   CacheInfo
02981     *cache_info;
02982 
02983   MagickOffsetType
02984     offset;
02985 
02986   MagickSizeType
02987     length,
02988     number_pixels;
02989 
02990   NexusInfo
02991     **virtual_nexus;
02992 
02993   PixelPacket
02994     *pixels,
02995     virtual_pixel;
02996 
02997   RectangleInfo
02998     region;
02999 
03000   register const IndexPacket
03001     *__restrict nexus_indexes;
03002 
03003   register const PixelPacket
03004     *__restrict p;
03005 
03006   register IndexPacket
03007     *__restrict indexes;
03008 
03009   register long
03010     u,
03011     v;
03012 
03013   register PixelPacket
03014     *__restrict q;
03015 
03016   /*
03017     Acquire pixels.
03018   */
03019   if (image->debug != MagickFalse)
03020     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
03021   cache_info=(CacheInfo *) image->cache;
03022   if (cache_info->type == UndefinedCache)
03023     return((const PixelPacket *) NULL);
03024   region.x=x;
03025   region.y=y;
03026   region.width=columns;
03027   region.height=rows;
03028   pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
03029   if (pixels == (PixelPacket *) NULL)
03030     return((const PixelPacket *) NULL);
03031   offset=(MagickOffsetType) region.y*cache_info->columns+region.x;
03032   length=(MagickSizeType) (region.height-1)*cache_info->columns+region.width-1;
03033   number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
03034   if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
03035     if ((x >= 0) && ((long) (x+columns) <= (long) cache_info->columns) &&
03036         (y >= 0) && ((long) (y+rows) <= (long) cache_info->rows))
03037       {
03038         MagickBooleanType
03039           status;
03040 
03041         /*
03042           Pixel request is inside cache extents.
03043         */
03044         if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
03045           return(pixels);
03046         status=ReadPixelCachePixels(cache_info,nexus_info,exception);
03047         if (status == MagickFalse)
03048           return((const PixelPacket *) NULL);
03049         if ((cache_info->storage_class == PseudoClass) ||
03050             (cache_info->colorspace == CMYKColorspace))
03051           {
03052             status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
03053             if (status == MagickFalse)
03054               return((const PixelPacket *) NULL);
03055           }
03056         return(pixels);
03057       }
03058   /*
03059     Pixel request is outside cache extents.
03060   */
03061   q=pixels;
03062   indexes=GetPixelCacheNexusIndexes(cache_info,nexus_info);
03063   virtual_nexus=AcquirePixelCacheNexus(1);
03064   if (virtual_nexus == (NexusInfo **) NULL)
03065     {
03066       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
03067         "UnableToGetCacheNexus","`%s'",image->filename);
03068       return((const PixelPacket *) NULL);
03069     }
03070   switch (virtual_pixel_method)
03071   {
03072     case BlackVirtualPixelMethod:
03073     {
03074       virtual_pixel.red=0;
03075       virtual_pixel.green=0;
03076       virtual_pixel.blue=0;
03077       virtual_pixel.opacity=OpaqueOpacity;
03078       break;
03079     }
03080     case GrayVirtualPixelMethod:
03081     {
03082       virtual_pixel.red=(Quantum) QuantumRange/2;
03083       virtual_pixel.green=(Quantum) QuantumRange/2;
03084       virtual_pixel.blue=(Quantum) QuantumRange/2;
03085       virtual_pixel.opacity=(Quantum) OpaqueOpacity;
03086       break;
03087     }
03088     case TransparentVirtualPixelMethod:
03089     {
03090       virtual_pixel.red=(Quantum) 0;
03091       virtual_pixel.green=(Quantum) 0;
03092       virtual_pixel.blue=(Quantum) 0;
03093       virtual_pixel.opacity=(Quantum) TransparentOpacity;
03094       break;
03095     }
03096     case MaskVirtualPixelMethod:
03097     case WhiteVirtualPixelMethod:
03098     {
03099       virtual_pixel.red=(Quantum) QuantumRange;
03100       virtual_pixel.green=(Quantum) QuantumRange;
03101       virtual_pixel.blue=(Quantum) QuantumRange;
03102       virtual_pixel.opacity=OpaqueOpacity;
03103       break;
03104     }
03105     default:
03106     {
03107       virtual_pixel=image->background_color;
03108       break;
03109     }
03110   }
03111   for (v=0; v < (long) rows; v++)
03112   {
03113     for (u=0; u < (long) columns; u+=length)
03114     {
03115       length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
03116       if ((((x+u) < 0) || ((x+u) >= (long) cache_info->columns)) ||
03117           (((y+v) < 0) || ((y+v) >= (long) cache_info->rows)) || (length == 0))
03118         {
03119           MagickModulo
03120             x_modulo,
03121             y_modulo;
03122 
03123           /*
03124             Transfer a single pixel.
03125           */
03126           length=(MagickSizeType) 1;
03127           switch (virtual_pixel_method)
03128           {
03129             case BackgroundVirtualPixelMethod:
03130             case ConstantVirtualPixelMethod:
03131             case BlackVirtualPixelMethod:
03132             case GrayVirtualPixelMethod:
03133             case TransparentVirtualPixelMethod:
03134             case MaskVirtualPixelMethod:
03135             case WhiteVirtualPixelMethod:
03136             {
03137               p=(&virtual_pixel);
03138               break;
03139             }
03140             case EdgeVirtualPixelMethod:
03141             default:
03142             {
03143               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
03144                 EdgeX(cache_info->columns,x+u),EdgeY(cache_info->rows,y+v),
03145                 1UL,1UL,virtual_nexus[0],exception);
03146               break;
03147             }
03148             case RandomVirtualPixelMethod:
03149             {
03150               if (cache_info->random_info == (RandomInfo *) NULL)
03151                 cache_info->random_info=AcquireRandomInfo();
03152               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
03153                 RandomX(cache_info->columns,cache_info->random_info),
03154                 RandomY(cache_info->rows,cache_info->random_info),1UL,1UL,
03155                 virtual_nexus[0],exception);
03156               break;
03157             }
03158             case DitherVirtualPixelMethod:
03159             {
03160               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
03161                 DitherX(cache_info->columns,x+u),DitherY(cache_info->rows,y+v),
03162                 1UL,1UL,virtual_nexus[0],exception);
03163               break;
03164             }
03165             case TileVirtualPixelMethod:
03166             {
03167               x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
03168               y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
03169               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
03170                 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
03171                 exception);
03172               break;
03173             }
03174             case MirrorVirtualPixelMethod:
03175             {
03176               x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
03177               if ((x_modulo.quotient & 0x01) == 1L)
03178                 x_modulo.remainder=(long) cache_info->columns-
03179                   x_modulo.remainder-1L;
03180               y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
03181               if ((y_modulo.quotient & 0x01) == 1L)
03182                 y_modulo.remainder=(long) cache_info->rows-
03183                   y_modulo.remainder-1L;
03184               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
03185                 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
03186                 exception);
03187               break;
03188             }
03189             case CheckerTileVirtualPixelMethod:
03190             {
03191               x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
03192               y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
03193               if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
03194                 {
03195                   p=(&virtual_pixel);
03196                   break;
03197                 }
03198               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
03199                 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
03200                 exception);
03201               break;
03202             }
03203             case HorizontalTileVirtualPixelMethod:
03204             {
03205               if (((y+v) < 0) || ((y+v) >= (long) cache_info->rows))
03206                 {
03207                   p=(&virtual_pixel);
03208                   break;
03209                 }
03210               x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
03211               y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
03212               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
03213                 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
03214                 exception);
03215               break;
03216             }
03217             case VerticalTileVirtualPixelMethod:
03218             {
03219               if (((x+u) < 0) || ((x+u) >= (long) cache_info->columns))
03220                 {
03221                   p=(&virtual_pixel);
03222                   break;
03223                 }
03224               x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
03225               y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
03226               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
03227                 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
03228                 exception);
03229               break;
03230             }
03231             case HorizontalTileEdgeVirtualPixelMethod:
03232             {
03233               x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
03234               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
03235                 x_modulo.remainder,EdgeY(cache_info->rows,y+v),1UL,1UL,
03236                 virtual_nexus[0],exception);
03237               break;
03238             }
03239             case VerticalTileEdgeVirtualPixelMethod:
03240             {
03241               y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
03242               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
03243                 EdgeX(cache_info->columns,x+u),y_modulo.remainder,1UL,1UL,
03244                 virtual_nexus[0],exception);
03245               break;
03246             }
03247           }
03248           if (p == (const PixelPacket *) NULL)
03249             break;
03250           *q++=(*p);
03251           if (indexes != (IndexPacket *) NULL)
03252             {
03253               nexus_indexes=GetVirtualIndexesFromNexus(cache_info,
03254                 virtual_nexus[0]);
03255               if (nexus_indexes != (const IndexPacket *) NULL)
03256                 *indexes++=(*nexus_indexes);
03257             }
03258           continue;
03259         }
03260       /*
03261         Transfer a run of pixels.
03262       */
03263       p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,
03264         (unsigned long) length,1UL,virtual_nexus[0],exception);
03265       if (p == (const PixelPacket *) NULL)
03266         break;
03267       (void) CopyMagickMemory(q,p,(size_t) length*sizeof(*p));
03268       q+=length;
03269       if (indexes != (IndexPacket *) NULL)
03270         {
03271           nexus_indexes=GetVirtualIndexesFromNexus(cache_info,virtual_nexus[0]);
03272           if (nexus_indexes != (const IndexPacket *) NULL)
03273             {
03274               (void) CopyMagickMemory(indexes,nexus_indexes,(size_t) length*
03275                 sizeof(*nexus_indexes));
03276               indexes+=length;
03277             }
03278         }
03279     }
03280   }
03281   virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
03282   return(pixels);
03283 }
03284 
03285 /*
03286 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
03287 %                                                                             %
03288 %                                                                             %
03289 %                                                                             %
03290 +   G e t V i r t u a l P i x e l C a c h e                                   %
03291 %                                                                             %
03292 %                                                                             %
03293 %                                                                             %
03294 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
03295 %
03296 %  GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
03297 %  cache as defined by the geometry parameters.   A pointer to the pixels
03298 %  is returned if the pixels are transferred, otherwise a NULL is returned.
03299 %
03300 %  The format of the GetVirtualPixelCache() method is:
03301 %
03302 %      const PixelPacket *GetVirtualPixelCache(const Image *image,
03303 %        const VirtualPixelMethod virtual_pixel_method,const long x,
03304 %        const long y,const unsigned long columns,const unsigned long rows,
03305 %        ExceptionInfo *exception)
03306 %
03307 %  A description of each parameter follows:
03308 %
03309 %    o image: the image.
03310 %
03311 %    o virtual_pixel_method: the virtual pixel method.
03312 %
03313 %    o x,y,columns,rows:  These values define the perimeter of a region of
03314 %      pixels.
03315 %
03316 %    o exception: return any errors or warnings in this structure.
03317 %
03318 */
03319 static const PixelPacket *GetVirtualPixelCache(const Image *image,
03320   const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
03321   const unsigned long columns,const unsigned long rows,ExceptionInfo *exception)
03322 {
03323   CacheInfo
03324    *cache_info;
03325 
03326   const PixelPacket
03327     *pixels;
03328 
03329   long
03330     id;
03331 
03332   if (image->debug != MagickFalse)
03333     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
03334   cache_info=(CacheInfo *) image->cache;
03335   id=GetOpenMPThreadId();
03336   assert(id < (long) cache_info->number_threads);
03337   pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
03338     cache_info->nexus_info[id],exception);
03339   return(pixels);
03340 }
03341 
03342 /*
03343 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
03344 %                                                                             %
03345 %                                                                             %
03346 %                                                                             %
03347 %   G e t V i r t u a l P i x e l Q u e u e                                   %
03348 %                                                                             %
03349 %                                                                             %
03350 %                                                                             %
03351 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
03352 %
03353 %  GetVirtualPixelQueue() returns the virtual pixels associated with the
03354 %  last call to QueueAuthenticPixels() or GetVirtualPixels().
03355 %
03356 %  The format of the GetVirtualPixelQueue() method is:
03357 %
03358 %      const PixelPacket *GetVirtualPixelQueue(const Image image)
03359 %
03360 %  A description of each parameter follows:
03361 %
03362 %    o image: the image.
03363 %
03364 */
03365 MagickExport const PixelPacket *GetVirtualPixelQueue(const Image *image)
03366 {
03367   CacheInfo
03368     *cache_info;
03369 
03370   assert(image != (const Image *) NULL);
03371   assert(image->signature == MagickSignature);
03372   if (image->debug != MagickFalse)
03373     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
03374   assert(image->cache != (Cache) NULL);
03375   cache_info=(CacheInfo *) image->cache;
03376   assert(cache_info->signature == MagickSignature);
03377   if (cache_info->methods.get_virtual_pixels_handler ==
03378       (GetVirtualPixelsHandler) NULL)
03379     return((PixelPacket *) NULL);
03380   return(cache_info->methods.get_virtual_pixels_handler(image));
03381 }
03382 
03383 /*
03384 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
03385 %                                                                             %
03386 %                                                                             %
03387 %                                                                             %
03388 %   G e t V i r t u a l P i x e l s                                           %
03389 %                                                                             %
03390 %                                                                             %
03391 %                                                                             %
03392 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
03393 %
03394 %  GetVirtualPixels() returns an immutable pixel region. If the
03395 %  region is successfully accessed, a pointer to it is returned, otherwise
03396 %  NULL is returned. The returned pointer may point to a temporary working
03397 %  copy of the pixels or it may point to the original pixels in memory.
03398 %  Performance is maximized if the selected region is part of one row, or one
03399 %  or more full rows, since there is opportunity to access the pixels in-place
03400 %  (without a copy) if the image is in RAM, or in a memory-mapped file.  The
03401 %  returned pointer should *never* be deallocated by the user.
03402 %
03403 %  Pixels accessed via the returned pointer represent a simple array of type
03404 %  PixelPacket.  If the image type is CMYK or the storage class is PseudoClass,
03405 %  call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access
03406 %  the black color component or to obtain the colormap indexes (of type
03407 %  IndexPacket) corresponding to the region.
03408 %
03409 %  If you plan to modify the pixels, use GetAuthenticPixels() instead.
03410 %
03411 %  Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
03412 %  safe.  In a threaded environment, use GetCacheViewVirtualPixels() or
03413 %  GetCacheViewAuthenticPixels() instead.
03414 %
03415 %  The format of the GetVirtualPixels() method is:
03416 %
03417 %      const PixelPacket *GetVirtualPixels(const Image *image,const long x,
03418 %        const long y,const unsigned long columns,const unsigned long rows,
03419 %        ExceptionInfo *exception)
03420 %
03421 %  A description of each parameter follows:
03422 %
03423 %    o image: the image.
03424 %
03425 %    o x,y,columns,rows:  These values define the perimeter of a region of
03426 %      pixels.
03427 %
03428 %    o exception: return any errors or warnings in this structure.
03429 %
03430 */
03431 MagickExport const PixelPacket *GetVirtualPixels(const Image *image,
03432   const long x,const long y,const unsigned long columns,
03433   const unsigned long rows,ExceptionInfo *exception)
03434 {
03435   CacheInfo
03436     *cache_info;
03437 
03438   const PixelPacket
03439     *pixels;
03440 
03441   assert(image != (const Image *) NULL);
03442   assert(image->signature == MagickSignature);
03443   if (image->debug != MagickFalse)
03444     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
03445   assert(image->cache != (Cache) NULL);
03446   cache_info=(CacheInfo *) image->cache;
03447   assert(cache_info->signature == MagickSignature);
03448   if (cache_info->methods.get_virtual_pixel_handler ==
03449       (GetVirtualPixelHandler) NULL)
03450     return((const PixelPacket *) NULL);
03451   pixels=cache_info->methods.get_virtual_pixel_handler(image,
03452     GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception);
03453   return(pixels);
03454 }
03455 
03456 /*
03457 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
03458 %                                                                             %
03459 %                                                                             %
03460 %                                                                             %
03461 +   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                         %
03462 %                                                                             %
03463 %                                                                             %
03464 %                                                                             %
03465 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
03466 %
03467 %  GetVirtualPixelsCache() returns the pixels associated with the last call
03468 %  to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
03469 %
03470 %  The format of the GetVirtualPixelsCache() method is:
03471 %
03472 %      PixelPacket *GetVirtualPixelsCache(const Image *image)
03473 %
03474 %  A description of each parameter follows:
03475 %
03476 %    o image: the image.
03477 %
03478 */
03479 static const PixelPacket *GetVirtualPixelsCache(const Image *image)
03480 {
03481   CacheInfo
03482     *cache_info;
03483 
03484   const PixelPacket
03485     *pixels;
03486 
03487   long
03488     id;
03489 
03490   if (image->debug != MagickFalse)
03491     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
03492   cache_info=(CacheInfo *) image->cache;
03493   id=GetOpenMPThreadId();
03494   assert(id < (long) cache_info->number_threads);
03495   pixels=GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]);
03496   return(pixels);
03497 }
03498 
03499 /*
03500 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
03501 %                                                                             %
03502 %                                                                             %
03503 %                                                                             %
03504 +   G e t V i r t u a l P i x e l s N e x u s                                 %
03505 %                                                                             %
03506 %                                                                             %
03507 %                                                                             %
03508 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
03509 %
03510 %  GetVirtualPixelsNexus() returns the pixels associated with the specified
03511 %  cache nexus.
03512 %
03513 %  The format of the GetVirtualPixelsNexus() method is:
03514 %
03515 %      const IndexPacket *GetVirtualPixelsNexus(const Cache cache,
03516 %        NexusInfo *nexus_info)
03517 %
03518 %  A description of each parameter follows:
03519 %
03520 %    o cache: the pixel cache.
03521 %
03522 %    o nexus_info: the cache nexus to return the colormap pixels.
03523 %
03524 */
03525 MagickExport const PixelPacket *GetVirtualPixelsNexus(const Cache cache,
03526   NexusInfo *nexus_info)
03527 {
03528   CacheInfo
03529     *cache_info;
03530 
03531   if (cache == (Cache) NULL)
03532     return((PixelPacket *) NULL);
03533   cache_info=(CacheInfo *) cache;
03534   assert(cache_info->signature == MagickSignature);
03535   if (cache_info->storage_class == UndefinedClass)
03536     return((PixelPacket *) NULL);
03537   return((const PixelPacket *) nexus_info->pixels);
03538 }
03539 
03540 /*
03541 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
03542 %                                                                             %
03543 %                                                                             %
03544 %                                                                             %
03545 +   M a s k P i x e l C a c h e N e x u s                                     %
03546 %                                                                             %
03547 %                                                                             %
03548 %                                                                             %
03549 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
03550 %
03551 %  MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
03552 %  The method returns MagickTrue if the pixel region is masked, otherwise
03553 %  MagickFalse.
03554 %
03555 %  The format of the MaskPixelCacheNexus() method is:
03556 %
03557 %      MagickBooleanType MaskPixelCacheNexus(Image *image,
03558 %        NexusInfo *nexus_info,ExceptionInfo *exception)
03559 %
03560 %  A description of each parameter follows:
03561 %
03562 %    o image: the image.
03563 %
03564 %    o nexus_info: the cache nexus to clip.
03565 %
03566 %    o exception: return any errors or warnings in this structure.
03567 %
03568 */
03569 
03570 static inline void MagickPixelCompositeMask(const MagickPixelPacket *p,
03571   const MagickRealType alpha,const MagickPixelPacket *q,
03572   const MagickRealType beta,MagickPixelPacket *composite)
03573 {
03574   MagickRealType
03575     gamma;
03576 
03577   if (alpha == TransparentOpacity)
03578     {
03579       *composite=(*q);
03580       return;
03581     }
03582   gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
03583   gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
03584   composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
03585   composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
03586   composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
03587   if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
03588     composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
03589 }
03590 
03591 static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
03592   ExceptionInfo *exception)
03593 {
03594   CacheInfo
03595     *cache_info;
03596 
03597   MagickPixelPacket
03598     alpha,
03599     beta;
03600 
03601   MagickSizeType
03602     number_pixels;
03603 
03604   NexusInfo
03605     **clip_nexus,
03606     **image_nexus;
03607 
03608   register const PixelPacket
03609     *__restrict r;
03610 
03611   register IndexPacket
03612     *__restrict nexus_indexes,
03613     *__restrict indexes;
03614 
03615   register long
03616     i;
03617 
03618   register PixelPacket
03619     *__restrict p,
03620     *__restrict q;
03621 
03622   /*
03623     Apply clip mask.
03624   */
03625   if (image->debug != MagickFalse)
03626     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
03627   if (image->mask == (Image *) NULL)
03628     return(MagickFalse);
03629   cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
03630   if (cache_info == (Cache) NULL)
03631     return(MagickFalse);
03632   image_nexus=AcquirePixelCacheNexus(1);
03633   clip_nexus=AcquirePixelCacheNexus(1);
03634   if ((image_nexus == (NexusInfo **) NULL) ||
03635       (clip_nexus == (NexusInfo **) NULL))
03636     ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
03637   p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,nexus_info->region.y,
03638     nexus_info->region.width,nexus_info->region.height,image_nexus[0],
03639     exception);
03640   indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
03641   q=nexus_info->pixels;
03642   nexus_indexes=nexus_info->indexes;
03643   r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
03644     nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
03645     nexus_info->region.height,clip_nexus[0],&image->exception);
03646   GetMagickPixelPacket(image,&alpha);
03647   GetMagickPixelPacket(image,&beta);
03648   number_pixels=(MagickSizeType) nexus_info->region.width*
03649     nexus_info->region.height;
03650   for (i=0; i < (long) number_pixels; i++)
03651   {
03652     if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
03653       break;
03654     SetMagickPixelPacket(image,p,indexes+i,&alpha);
03655     SetMagickPixelPacket(image,q,nexus_indexes+i,&beta);
03656     MagickPixelCompositeMask(&beta,(MagickRealType) PixelIntensityToQuantum(r),
03657       &alpha,alpha.opacity,&beta);
03658     q->red=RoundToQuantum(beta.red);
03659     q->green=RoundToQuantum(beta.green);
03660     q->blue=RoundToQuantum(beta.blue);
03661     q->opacity=RoundToQuantum(beta.opacity);
03662     if (cache_info->active_index_channel != MagickFalse)
03663       nexus_indexes[i]=indexes[i];
03664     p++;
03665     q++;
03666     r++;
03667   }
03668   clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
03669   image_nexus=DestroyPixelCacheNexus(image_nexus,1);
03670   if (i < (long) number_pixels)
03671     return(MagickFalse);
03672   return(MagickTrue);
03673 }
03674 
03675 /*
03676 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
03677 %                                                                             %
03678 %                                                                             %
03679 %                                                                             %
03680 +   O p e n P i x e l C a c h e                                               %
03681 %                                                                             %
03682 %                                                                             %
03683 %                                                                             %
03684 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
03685 %
03686 %  OpenPixelCache() allocates the pixel cache.  This includes defining the cache
03687 %  dimensions, allocating space for the image pixels and optionally the
03688 %  colormap indexes, and memory mapping the cache if it is disk based.  The
03689 %  cache nexus array is initialized as well.
03690 %
03691 %  The format of the OpenPixelCache() method is:
03692 %
03693 %      MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
03694 %        ExceptionInfo *exception)
03695 %
03696 %  A description of each parameter follows:
03697 %
03698 %    o image: the image.
03699 %
03700 %    o mode: ReadMode, WriteMode, or IOMode.
03701 %
03702 %    o exception: return any errors or warnings in this structure.
03703 %
03704 */
03705 
03706 static inline void AcquirePixelCachePixels(CacheInfo *cache_info)
03707 {
03708   cache_info->mapped=MagickFalse;
03709   cache_info->pixels=(PixelPacket *) AcquireMagickMemory((size_t)
03710     cache_info->length);
03711   if (cache_info->pixels == (PixelPacket *) NULL)
03712     {
03713       cache_info->mapped=MagickTrue;
03714       cache_info->pixels=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
03715         cache_info->length);
03716     }
03717 }
03718 
03719 static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
03720 {
03721   CacheInfo
03722     *cache_info;
03723 
03724   MagickOffsetType
03725     count,
03726     extent,
03727     offset;
03728 
03729   cache_info=(CacheInfo *) image->cache;
03730   if (image->debug != MagickFalse)
03731     {
03732       char
03733         format[MaxTextExtent],
03734         message[MaxTextExtent];
03735 
03736       (void) FormatMagickSize(length,format);
03737       (void) FormatMagickString(message,MaxTextExtent,
03738         "extend %s (%s[%d], disk, %s)",cache_info->filename,
03739         cache_info->cache_filename,cache_info->file,format);
03740       (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
03741     }
03742   if (length != (MagickSizeType) ((MagickOffsetType) length))
03743     return(MagickFalse);
03744   extent=(MagickOffsetType) MagickSeek(cache_info->file,0,SEEK_END);
03745   if (extent < 0)
03746     return(MagickFalse);
03747   if ((MagickSizeType) extent >= length)
03748     return(MagickTrue);
03749   offset=(MagickOffsetType) length-1;
03750   count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
03751   return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
03752 }
03753 
03754 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
03755   ExceptionInfo *exception)
03756 {
03757   char
03758     format[MaxTextExtent],
03759     message[MaxTextExtent];
03760 
03761   CacheInfo
03762     *cache_info,
03763     source_info;
03764 
03765   MagickSizeType
03766     length,
03767     number_pixels;
03768 
03769   MagickStatusType
03770     status;
03771 
03772   size_t
03773     packet_size;
03774 
03775   unsigned long
03776     columns;
03777 
03778   if (image->debug != MagickFalse)
03779     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
03780   if ((image->columns == 0) || (image->rows == 0))
03781     ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
03782   cache_info=(CacheInfo *) image->cache;
03783   source_info=(*cache_info);
03784   source_info.file=(-1);
03785   (void) FormatMagickString(cache_info->filename,MaxTextExtent,"%s[%ld]",
03786     image->filename,GetImageIndexInList(image));
03787   cache_info->rows=image->rows;
03788   cache_info->columns=image->columns;
03789   cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
03790     (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
03791   number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
03792   packet_size=sizeof(PixelPacket);
03793   if (cache_info->active_index_channel != MagickFalse)
03794     packet_size+=sizeof(IndexPacket);
03795   length=number_pixels*packet_size;
03796   columns=(unsigned long) (length/cache_info->rows/packet_size);
03797   if (cache_info->columns != columns)
03798     ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
03799       image->filename);
03800   cache_info->length=length;
03801   status=AcquireMagickResource(AreaResource,cache_info->length);
03802   length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
03803   if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
03804     {
03805       status=AcquireMagickResource(MemoryResource,cache_info->length);
03806       if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
03807           (cache_info->type == MemoryCache))
03808         {
03809           AcquirePixelCachePixels(cache_info);
03810           if (cache_info->pixels == (PixelPacket *) NULL)
03811             cache_info->pixels=source_info.pixels;
03812           else
03813             {
03814               /*
03815                 Create memory pixel cache.
03816               */
03817               if (image->debug != MagickFalse)
03818                 {
03819                   (void) FormatMagickSize(cache_info->length,format);
03820                   (void) FormatMagickString(message,MaxTextExtent,
03821                     "open %s (%s memory, %lux%lu %s)",cache_info->filename,
03822                     cache_info->mapped != MagickFalse ? "anonymous" : "heap",
03823                     cache_info->columns,cache_info->rows,format);
03824                   (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
03825                     message);
03826                 }
03827               cache_info->storage_class=image->storage_class;
03828               cache_info->colorspace=image->colorspace;
03829               cache_info->type=MemoryCache;
03830               cache_info->indexes=(IndexPacket *) NULL;
03831               if (cache_info->active_index_channel != MagickFalse)
03832                 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
03833                   number_pixels);
03834               if (source_info.storage_class != UndefinedClass)
03835                 {
03836                   status|=ClonePixelCache(cache_info,&source_info,exception);
03837                   RelinquishPixelCachePixels(&source_info);
03838                 }
03839               return(MagickTrue);
03840             }
03841         }
03842       RelinquishMagickResource(MemoryResource,cache_info->length);
03843     }
03844   /*
03845     Create pixel cache on disk.
03846   */
03847   status=AcquireMagickResource(DiskResource,cache_info->length);
03848   if (status == MagickFalse)
03849     {
03850       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
03851         "CacheResourcesExhausted","`%s'",image->filename);
03852       return(MagickFalse);
03853     }
03854   if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
03855     {
03856       RelinquishMagickResource(DiskResource,cache_info->length);
03857       ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
03858         image->filename);
03859       return(MagickFalse);
03860     }
03861   status=ExtendCache(image,(MagickSizeType) cache_info->offset+
03862     cache_info->length);
03863   if (status == MagickFalse)
03864     {
03865       ThrowFileException(exception,CacheError,"UnableToExtendCache",
03866         image->filename);
03867       return(MagickFalse);
03868     }
03869   cache_info->storage_class=image->storage_class;
03870   cache_info->colorspace=image->colorspace;
03871   length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
03872   status=AcquireMagickResource(AreaResource,cache_info->length);
03873   if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
03874     cache_info->type=DiskCache;
03875   else
03876     {
03877       status=AcquireMagickResource(MapResource,cache_info->length);
03878       if ((status == MagickFalse) && (cache_info->type != MapCache) &&
03879           (cache_info->type != MemoryCache))
03880         cache_info->type=DiskCache;
03881       else
03882         {
03883           cache_info->pixels=(PixelPacket *) MapBlob(cache_info->file,mode,
03884             cache_info->offset,(size_t) cache_info->length);
03885           if (cache_info->pixels == (PixelPacket *) NULL)
03886             {
03887               cache_info->pixels=source_info.pixels;
03888               cache_info->type=DiskCache;
03889             }
03890           else
03891             {
03892               /*
03893                 Create file-backed memory-mapped pixel cache.
03894               */
03895               (void) ClosePixelCacheOnDisk(cache_info);
03896               cache_info->type=MapCache;
03897               cache_info->mapped=MagickTrue;
03898               cache_info->indexes=(IndexPacket *) NULL;
03899               if (cache_info->active_index_channel != MagickFalse)
03900                 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
03901                   number_pixels);
03902               if ((source_info.type != UndefinedCache) && (mode != ReadMode))
03903                 {
03904                   status=ClonePixelCache(cache_info,&source_info,exception);
03905                   RelinquishPixelCachePixels(&source_info);
03906                 }
03907               if (image->debug != MagickFalse)
03908                 {
03909                   (void) FormatMagickSize(cache_info->length,format);
03910                   (void) FormatMagickString(message,MaxTextExtent,
03911                     "open %s (%s[%d], memory-mapped, %lux%lu %s)",
03912                     cache_info->filename,cache_info->cache_filename,
03913                     cache_info->file,cache_info->columns,cache_info->rows,
03914                     format);
03915                   (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
03916                     message);
03917                 }
03918               return(MagickTrue);
03919             }
03920         }
03921       RelinquishMagickResource(MapResource,cache_info->length);
03922     }
03923   if ((source_info.type != UndefinedCache) && (mode != ReadMode))
03924     {
03925       status=ClonePixelCache(cache_info,&source_info,exception);
03926       RelinquishPixelCachePixels(&source_info);
03927     }
03928   if (image->debug != MagickFalse)
03929     {
03930       (void) FormatMagickSize(cache_info->length,format);
03931       (void) FormatMagickString(message,MaxTextExtent,
03932         "open %s (%s[%d], disk, %lux%lu %s)",cache_info->filename,
03933         cache_info->cache_filename,cache_info->file,cache_info->columns,
03934         cache_info->rows,format);
03935       (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
03936     }
03937   return(MagickTrue);
03938 }
03939 
03940 /*
03941 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
03942 %                                                                             %
03943 %                                                                             %
03944 %                                                                             %
03945 +   P e r s i s t P i x e l C a c h e                                         %
03946 %                                                                             %
03947 %                                                                             %
03948 %                                                                             %
03949 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
03950 %
03951 %  PersistPixelCache() attaches to or initializes a persistent pixel cache.  A
03952 %  persistent pixel cache is one that resides on disk and is not destroyed
03953 %  when the program exits.
03954 %
03955 %  The format of the PersistPixelCache() method is:
03956 %
03957 %      MagickBooleanType PersistPixelCache(Image *image,const char *filename,
03958 %        const MagickBooleanType attach,MagickOffsetType *offset,
03959 %        ExceptionInfo *exception)
03960 %
03961 %  A description of each parameter follows:
03962 %
03963 %    o image: the image.
03964 %
03965 %    o filename: the persistent pixel cache filename.
03966 %
03967 %    o initialize: A value other than zero initializes the persistent pixel
03968 %      cache.
03969 %
03970 %    o offset: the offset in the persistent cache to store pixels.
03971 %
03972 %    o exception: return any errors or warnings in this structure.
03973 %
03974 */
03975 MagickExport MagickBooleanType PersistPixelCache(Image *image,
03976   const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
03977   ExceptionInfo *exception)
03978 {
03979   CacheInfo
03980     *cache_info,
03981     *clone_info;
03982 
03983   Image
03984     clone_image;
03985 
03986   long
03987     pagesize;
03988 
03989   MagickBooleanType
03990     status;
03991 
03992   assert(image != (Image *) NULL);
03993   assert(image->signature == MagickSignature);
03994   if (image->debug != MagickFalse)
03995     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
03996   assert(image->cache != (void *) NULL);
03997   assert(filename != (const char *) NULL);
03998   assert(offset != (MagickOffsetType *) NULL);
03999   pagesize=(-1);
04000 #if defined(MAGICKCORE_HAVE_SYSCONF) && defined(_SC_PAGESIZE)
04001   pagesize=sysconf(_SC_PAGESIZE);
04002 #elif defined(MAGICKCORE_HAVE_GETPAGESIZE) && defined(MAGICKCORE_POSIX_SUPPORT)
04003   pagesize=getpagesize();
04004 #endif
04005   if (pagesize <= 0)
04006     pagesize=4096;
04007   cache_info=(CacheInfo *) image->cache;
04008   assert(cache_info->signature == MagickSignature);
04009   if (attach != MagickFalse)
04010     {
04011       /*
04012         Attach persistent pixel cache.
04013       */
04014       if (image->debug != MagickFalse)
04015         (void) LogMagickEvent(CacheEvent,GetMagickModule(),
04016           "attach persistent cache");
04017       (void) CopyMagickString(cache_info->cache_filename,filename,
04018         MaxTextExtent);
04019       cache_info->type=DiskCache;
04020       cache_info->offset=(*offset);
04021       if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
04022         return(MagickFalse);
04023       cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
04024       *offset+=cache_info->length+pagesize-(cache_info->length % pagesize);
04025       return(MagickTrue);
04026     }
04027   if ((cache_info->type != MemoryCache) && (cache_info->reference_count == 1))
04028     {
04029       (void) LockSemaphoreInfo(cache_info->semaphore);
04030       if ((cache_info->type != MemoryCache) &&
04031           (cache_info->reference_count == 1))
04032         {
04033           int
04034             status;
04035 
04036           /*
04037             Usurp resident persistent pixel cache.
04038           */
04039           status=rename(cache_info->cache_filename,filename);
04040           if (status == 0)
04041             {
04042               (void) CopyMagickString(cache_info->cache_filename,filename,
04043                 MaxTextExtent);
04044               cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
04045               *offset+=cache_info->length+pagesize-(cache_info->length %
04046                 pagesize);
04047               if (image->debug != MagickFalse)
04048                 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
04049                   "Usurp resident persistent cache");
04050               (void) UnlockSemaphoreInfo(cache_info->semaphore);
04051               return(MagickTrue);
04052             }
04053         }
04054       (void) UnlockSemaphoreInfo(cache_info->semaphore);
04055     }
04056   /*
04057     Attach persistent pixel cache.
04058   */
04059   clone_image=(*image);
04060   clone_info=(CacheInfo *) clone_image.cache;
04061   image->cache=AcquirePixelCacheInfo(cache_info->number_threads);
04062   cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
04063   (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
04064   cache_info->type=DiskCache;
04065   cache_info->offset=(*offset);
04066   cache_info=(CacheInfo *) image->cache;
04067   status=ClonePixelCacheNexus(cache_info,clone_info,exception);
04068   if (status != MagickFalse)
04069     {
04070       status=OpenPixelCache(image,IOMode,exception);
04071       if (status != MagickFalse)
04072        status=ClonePixelCache(cache_info,clone_info,&image->exception);
04073     }
04074   *offset+=cache_info->length+pagesize-(cache_info->length % pagesize);
04075   clone_info=(CacheInfo *) DestroyPixelCacheInfo(clone_info);
04076   return(status);
04077 }
04078 
04079 /*
04080 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
04081 %                                                                             %
04082 %                                                                             %
04083 %                                                                             %
04084 +   Q u e u e A u t h e n t i c N e x u s                                     %
04085 %                                                                             %
04086 %                                                                             %
04087 %                                                                             %
04088 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
04089 %
04090 %  QueueAuthenticNexus() allocates an region to store image pixels as defined
04091 %  by the region rectangle and returns a pointer to the region.  This region is
04092 %  subsequently transferred from the pixel cache with
04093 %  SyncAuthenticPixelsCache().  A pointer to the pixels is returned if the
04094 %  pixels are transferred, otherwise a NULL is returned.
04095 %
04096 %  The format of the QueueAuthenticNexus() method is:
04097 %
04098 %      PixelPacket *QueueAuthenticNexus(Image *image,const long x,const long y,
04099 %        const unsigned long columns,const unsigned long rows,
04100 %        NexusInfo *nexus_info,ExceptionInfo *exception)
04101 %
04102 %  A description of each parameter follows:
04103 %
04104 %    o image: the image.
04105 %
04106 %    o x,y,columns,rows:  These values define the perimeter of a region of
04107 %      pixels.
04108 %
04109 %    o nexus_info: the cache nexus to set.
04110 %
04111 %    o exception: return any errors or warnings in this structure.
04112 %
04113 */
04114 MagickExport PixelPacket *QueueAuthenticNexus(Image *image,const long x,
04115   const long y,const unsigned long columns,const unsigned long rows,
04116   NexusInfo *nexus_info,ExceptionInfo *exception)
04117 {
04118   CacheInfo
04119     *cache_info;
04120 
04121   MagickOffsetType
04122     offset;
04123 
04124   MagickSizeType
04125     number_pixels;
04126 
04127   RectangleInfo
04128     region;
04129 
04130   /*
04131     Validate pixel cache geometry.
04132   */
04133   cache_info=(CacheInfo *) image->cache;
04134   if ((cache_info->columns == 0) && (cache_info->rows == 0))
04135     {
04136       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
04137         "NoPixelsDefinedInCache","`%s'",image->filename);
04138       return((PixelPacket *) NULL);
04139     }
04140   if ((x < 0) || (y < 0) || (x >= (long) cache_info->columns) ||
04141       (y >= (long) cache_info->rows))
04142     {
04143       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
04144         "PixelsAreNotAuthentic","`%s'",image->filename);
04145       return((PixelPacket *) NULL);
04146     }
04147   offset=(MagickOffsetType) y*cache_info->columns+x;
04148   if (offset < 0)
04149     return((PixelPacket *) NULL);
04150   number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
04151   offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
04152   if ((MagickSizeType) offset >= number_pixels)
04153     return((PixelPacket *) NULL);
04154   /*
04155     Return pixel cache.
04156   */
04157   region.x=x;
04158   region.y=y;
04159   region.width=columns;
04160   region.height=rows;
04161   return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
04162 }
04163 
04164 /*
04165 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
04166 %                                                                             %
04167 %                                                                             %
04168 %                                                                             %
04169 +   Q u e u e A u t h e n t i c P i x e l s C a c h e                         %
04170 %                                                                             %
04171 %                                                                             %
04172 %                                                                             %
04173 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
04174 %
04175 %  QueueAuthenticPixelsCache() allocates an region to store image pixels as
04176 %  defined by the region rectangle and returns a pointer to the region.  This
04177 %  region is subsequently transferred from the pixel cache with
04178 %  SyncAuthenticPixelsCache().  A pointer to the pixels is returned if the
04179 %  pixels are transferred, otherwise a NULL is returned.
04180 %
04181 %  The format of the QueueAuthenticPixelsCache() method is:
04182 %
04183 %      PixelPacket *QueueAuthenticPixelsCache(Image *image,const long x,
04184 %        const long y,const unsigned long columns,const unsigned long rows,
04185 %        ExceptionInfo *exception)
04186 %
04187 %  A description of each parameter follows:
04188 %
04189 %    o image: the image.
04190 %
04191 %    o x,y,columns,rows:  These values define the perimeter of a region of
04192 %      pixels.
04193 %
04194 %    o exception: return any errors or warnings in this structure.
04195 %
04196 */
04197 static PixelPacket *QueueAuthenticPixelsCache(Image *image,const long x,
04198   const long y,const unsigned long columns,const unsigned long rows,
04199   ExceptionInfo *exception)
04200 {
04201   CacheInfo
04202     *cache_info;
04203 
04204   long
04205     id;
04206 
04207   PixelPacket
04208     *pixels;
04209 
04210   cache_info=(CacheInfo *) GetImagePixelCache(image,MagickFalse,exception);
04211   if (cache_info == (Cache) NULL)
04212     return((PixelPacket *) NULL);
04213   id=GetOpenMPThreadId();
04214   assert(id < (long) cache_info->number_threads);
04215   pixels=QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
04216     exception);
04217   return(pixels);
04218 }
04219 
04220 /*
04221 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
04222 %                                                                             %
04223 %                                                                             %
04224 %                                                                             %
04225 %   Q u e u e A u t h e n t i c P i x e l s                                   %
04226 %                                                                             %
04227 %                                                                             %
04228 %                                                                             %
04229 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
04230 %
04231 %  QueueAuthenticPixels() queues a mutable pixel region.  If the region is
04232 %  successfully intialized a pointer to a PixelPacket array representing the
04233 %  region is returned, otherwise NULL is returned.  The returned pointer may
04234 %  point to a temporary working buffer for the pixels or it may point to the
04235 %  final location of the pixels in memory.
04236 %
04237 %  Write-only access means that any existing pixel values corresponding to
04238 %  the region are ignored.  This is useful if the initial image is being
04239 %  created from scratch, or if the existing pixel values are to be
04240 %  completely replaced without need to refer to their pre-existing values.
04241 %  The application is free to read and write the pixel buffer returned by
04242 %  QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
04243 %  initialize the pixel array values. Initializing pixel array values is the
04244 %  application's responsibility.
04245 %
04246 %  Performance is maximized if the selected region is part of one row, or
04247 %  one or more full rows, since then there is opportunity to access the
04248 %  pixels in-place (without a copy) if the image is in RAM, or in a
04249 %  memory-mapped file. The returned pointer should *never* be deallocated
04250 %  by the user.
04251 %
04252 %  Pixels accessed via the returned pointer represent a simple array of type
04253 %  PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
04254 %  call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
04255 %  the black color component or the colormap indexes (of type IndexPacket)
04256 %  corresponding to the region.  Once the PixelPacket (and/or IndexPacket)
04257 %  array has been updated, the changes must be saved back to the underlying
04258 %  image using SyncAuthenticPixels() or they may be lost.
04259 %
04260 %  The format of the QueueAuthenticPixels() method is:
04261 %
04262 %      PixelPacket *QueueAuthenticPixels(Image *image,const long x,const long y,
04263 %        const unsigned long columns,const unsigned long rows,
04264 %        ExceptionInfo *exception)
04265 %
04266 %  A description of each parameter follows:
04267 %
04268 %    o image: the image.
04269 %
04270 %    o x,y,columns,rows:  These values define the perimeter of a region of
04271 %      pixels.
04272 %
04273 %    o exception: return any errors or warnings in this structure.
04274 %
04275 */
04276 MagickExport PixelPacket *QueueAuthenticPixels(Image *image,const long x,
04277   const long y,const unsigned long columns,const unsigned long rows,
04278   ExceptionInfo *exception)
04279 {
04280   CacheInfo
04281     *cache_info;
04282 
04283   PixelPacket
04284     *pixels;
04285 
04286   assert(image != (Image *) NULL);
04287   assert(image->signature == MagickSignature);
04288   if (image->debug != MagickFalse)
04289     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
04290   assert(image->cache != (Cache) NULL);
04291   cache_info=(CacheInfo *) image->cache;
04292   assert(cache_info->signature == MagickSignature);
04293   if (cache_info->methods.queue_authentic_pixels_handler ==
04294       (QueueAuthenticPixelsHandler) NULL)
04295     return((PixelPacket *) NULL);
04296   pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
04297     rows,exception);
04298   return(pixels);
04299 }
04300 
04301 /*
04302 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
04303 %                                                                             %
04304 %                                                                             %
04305 %                                                                             %
04306 +   R e a d P i x e l C a c h e I n d e x e s                                 %
04307 %                                                                             %
04308 %                                                                             %
04309 %                                                                             %
04310 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
04311 %
04312 %  ReadPixelCacheIndexes() reads colormap indexes from the specified region of
04313 %  the pixel cache.
04314 %
04315 %  The format of the ReadPixelCacheIndexes() method is:
04316 %
04317 %      MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
04318 %        NexusInfo *nexus_info,ExceptionInfo *exception)
04319 %
04320 %  A description of each parameter follows:
04321 %
04322 %    o cache_info: the pixel cache.
04323 %
04324 %    o nexus_info: the cache nexus to read the colormap indexes.
04325 %
04326 %    o exception: return any errors or warnings in this structure.
04327 %
04328 */
04329 static MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
04330   NexusInfo *nexus_info,ExceptionInfo *exception)
04331 {
04332   MagickOffsetType
04333     count,
04334     offset;
04335 
04336   MagickSizeType
04337     length,
04338     number_pixels;
04339 
04340   register IndexPacket
04341     *__restrict q;
04342 
04343   register long
04344     y;
04345 
04346   unsigned long
04347     rows;
04348 
04349   if (cache_info->debug != MagickFalse)
04350     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
04351       cache_info->filename);
04352   if (cache_info->active_index_channel == MagickFalse)
04353     return(MagickFalse);
04354   if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
04355     return(MagickTrue);
04356   offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
04357     nexus_info->region.x;
04358   length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
04359   rows=nexus_info->region.height;
04360   number_pixels=length*rows;
04361   if ((cache_info->columns == nexus_info->region.width) &&
04362       (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
04363     {
04364       length=number_pixels;
04365       rows=1UL;
04366     }
04367   q=nexus_info->indexes;
04368   switch (cache_info->type)
04369   {
04370     case MemoryCache:
04371     case MapCache:
04372     {
04373       register IndexPacket
04374         *__restrict p;
04375 
04376       /*
04377         Read indexes from memory.
04378       */
04379       p=cache_info->indexes+offset;
04380       for (y=0; y < (long) rows; y++)
04381       {
04382         (void) CopyMagickMemory(q,p,(size_t) length);
04383         p+=cache_info->columns;
04384         q+=nexus_info->region.width;
04385       }
04386       break;
04387     }
04388     case DiskCache:
04389     {
04390       /*
04391         Read indexes from disk.
04392       */
04393       if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
04394         {
04395           ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
04396             cache_info->cache_filename);
04397           return(MagickFalse);
04398         }
04399       number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
04400       for (y=0; y < (long) rows; y++)
04401       {
04402         count=ReadPixelCacheRegion(cache_info,cache_info->offset+number_pixels*
04403           sizeof(PixelPacket)+offset*sizeof(*q),length,(unsigned char *) q);
04404         if ((MagickSizeType) count < length)
04405           break;
04406         offset+=cache_info->columns;
04407         q+=nexus_info->region.width;
04408       }
04409       if (y < (long) rows)
04410         {
04411           ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
04412             cache_info->cache_filename);
04413           return(MagickFalse);
04414         }
04415       break;
04416     }
04417     default:
04418       break;
04419   }
04420   if ((cache_info->debug != MagickFalse) &&
04421       (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
04422     (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
04423       cache_info->filename,nexus_info->region.width,nexus_info->region.height,
04424       nexus_info->region.x,nexus_info->region.y);
04425   return(MagickTrue);
04426 }
04427 
04428 /*
04429 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
04430 %                                                                             %
04431 %                                                                             %
04432 %                                                                             %
04433 +   R e a d P i x e l C a c h e P i x e l s                                   %
04434 %                                                                             %
04435 %                                                                             %
04436 %                                                                             %
04437 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
04438 %
04439 %  ReadPixelCachePixels() reads pixels from the specified region of the pixel
04440 %  cache.
04441 %
04442 %  The format of the ReadPixelCachePixels() method is:
04443 %
04444 %      MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
04445 %        NexusInfo *nexus_info,ExceptionInfo *exception)
04446 %
04447 %  A description of each parameter follows:
04448 %
04449 %    o cache_info: the pixel cache.
04450 %
04451 %    o nexus_info: the cache nexus to read the pixels.
04452 %
04453 %    o exception: return any errors or warnings in this structure.
04454 %
04455 */
04456 static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
04457   NexusInfo *nexus_info,ExceptionInfo *exception)
04458 {
04459   MagickOffsetType
04460     count,
04461     offset;
04462 
04463   MagickSizeType
04464     length,
04465     number_pixels;
04466 
04467   register long
04468     y;
04469 
04470   register PixelPacket
04471     *__restrict q;
04472 
04473   unsigned long
04474     rows;
04475 
04476   if (cache_info->debug != MagickFalse)
04477     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
04478       cache_info->filename);
04479   if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
04480     return(MagickTrue);
04481   offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
04482     nexus_info->region.x;
04483   length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
04484   rows=nexus_info->region.height;
04485   number_pixels=length*rows;
04486   if ((cache_info->columns == nexus_info->region.width) &&
04487       (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
04488     {
04489       length=number_pixels;
04490       rows=1UL;
04491     }
04492   q=nexus_info->pixels;
04493   switch (cache_info->type)
04494   {
04495     case MemoryCache:
04496     case MapCache:
04497     {
04498       register PixelPacket
04499         *__restrict p;
04500 
04501       /*
04502         Read pixels from memory.
04503       */
04504       p=cache_info->pixels+offset;
04505       for (y=0; y < (long) rows; y++)
04506       {
04507         (void) CopyMagickMemory(q,p,(size_t) length);
04508         p+=cache_info->columns;
04509         q+=nexus_info->region.width;
04510       }
04511       break;
04512     }
04513     case DiskCache:
04514     {
04515       /*
04516         Read pixels from disk.
04517       */
04518       if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
04519         {
04520           ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
04521             cache_info->cache_filename);
04522           return(MagickFalse);
04523         }
04524       for (y=0; y < (long) rows; y++)
04525       {
04526         count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
04527           sizeof(*q),length,(unsigned char *) q);
04528         if ((MagickSizeType) count < length)
04529           break;
04530         offset+=cache_info->columns;
04531         q+=nexus_info->region.width;
04532       }
04533       if (y < (long) rows)
04534         {
04535           ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
04536             cache_info->cache_filename);
04537           return(MagickFalse);
04538         }
04539       break;
04540     }
04541     default:
04542       break;
04543   }
04544   if ((cache_info->debug != MagickFalse) &&
04545       (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
04546     (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
04547       cache_info->filename,nexus_info->region.width,nexus_info->region.height,
04548       nexus_info->region.x,nexus_info->region.y);
04549   return(MagickTrue);
04550 }
04551 
04552 /*
04553 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
04554 %                                                                             %
04555 %                                                                             %
04556 %                                                                             %
04557 +   R e f e r e n c e P i x e l C a c h e                                     %
04558 %                                                                             %
04559 %                                                                             %
04560 %                                                                             %
04561 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
04562 %
04563 %  ReferencePixelCache() increments the reference count associated with the
04564 %  pixel cache returning a pointer to the cache.
04565 %
04566 %  The format of the ReferencePixelCache method is:
04567 %
04568 %      Cache ReferencePixelCache(Cache cache_info)
04569 %
04570 %  A description of each parameter follows:
04571 %
04572 %    o cache_info: the pixel cache.
04573 %
04574 */
04575 MagickExport Cache ReferencePixelCache(Cache cache)
04576 {
04577   CacheInfo
04578     *cache_info;
04579 
04580   assert(cache != (Cache *) NULL);
04581   cache_info=(CacheInfo *) cache;
04582   assert(cache_info->signature == MagickSignature);
04583   if (cache_info->debug != MagickFalse)
04584     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
04585       cache_info->filename);
04586   (void) LockSemaphoreInfo(cache_info->semaphore);
04587   cache_info->reference_count++;
04588   (void) UnlockSemaphoreInfo(cache_info->semaphore);
04589   return(cache_info);
04590 }
04591 
04592 /*
04593 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
04594 %                                                                             %
04595 %                                                                             %
04596 %                                                                             %
04597 +   S e t P i x e l C a c h e M e t h o d s                                   %
04598 %                                                                             %
04599 %                                                                             %
04600 %                                                                             %
04601 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
04602 %
04603 %  SetPixelCacheMethods() sets the image pixel methods to the specified ones.
04604 %
04605 %  The format of the SetPixelCacheMethods() method is:
04606 %
04607 %      SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
04608 %
04609 %  A description of each parameter follows:
04610 %
04611 %    o cache: the pixel cache.
04612 %
04613 %    o cache_methods: Specifies a pointer to a CacheMethods structure.
04614 %
04615 */
04616 MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
04617 {
04618   CacheInfo
04619     *cache_info;
04620 
04621   GetOneAuthenticPixelFromHandler
04622     get_one_authentic_pixel_from_handler;
04623 
04624   GetOneVirtualPixelFromHandler
04625     get_one_virtual_pixel_from_handler;
04626 
04627   /*
04628     Set cache pixel methods.
04629   */
04630   assert(cache != (Cache) NULL);
04631   assert(cache_methods != (CacheMethods *) NULL);
04632   cache_info=(CacheInfo *) cache;
04633   assert(cache_info->signature == MagickSignature);
04634   if (cache_info->debug != MagickFalse)
04635     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
04636       cache_info->filename);
04637   if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
04638     cache_info->methods.get_virtual_pixel_handler=
04639       cache_methods->get_virtual_pixel_handler;
04640   if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
04641     cache_info->methods.destroy_pixel_handler=
04642       cache_methods->destroy_pixel_handler;
04643   if (cache_methods->get_virtual_indexes_from_handler !=
04644       (GetVirtualIndexesFromHandler) NULL)
04645     cache_info->methods.get_virtual_indexes_from_handler=
04646       cache_methods->get_virtual_indexes_from_handler;
04647   if (cache_methods->get_authentic_pixels_handler !=
04648       (GetAuthenticPixelsHandler) NULL)
04649     cache_info->methods.get_authentic_pixels_handler=
04650       cache_methods->get_authentic_pixels_handler;
04651   if (cache_methods->queue_authentic_pixels_handler !=
04652       (QueueAuthenticPixelsHandler) NULL)
04653     cache_info->methods.queue_authentic_pixels_handler=
04654       cache_methods->queue_authentic_pixels_handler;
04655   if (cache_methods->sync_authentic_pixels_handler !=
04656       (SyncAuthenticPixelsHandler) NULL)
04657     cache_info->methods.sync_authentic_pixels_handler=
04658       cache_methods->sync_authentic_pixels_handler;
04659   if (cache_methods->get_authentic_pixels_from_handler !=
04660       (GetAuthenticPixelsFromHandler) NULL)
04661     cache_info->methods.get_authentic_pixels_from_handler=
04662       cache_methods->get_authentic_pixels_from_handler;
04663   if (cache_methods->get_authentic_indexes_from_handler !=
04664       (GetAuthenticIndexesFromHandler) NULL)
04665     cache_info->methods.get_authentic_indexes_from_handler=
04666       cache_methods->get_authentic_indexes_from_handler;
04667   get_one_virtual_pixel_from_handler=
04668     cache_info->methods.get_one_virtual_pixel_from_handler;
04669   if (get_one_virtual_pixel_from_handler !=
04670       (GetOneVirtualPixelFromHandler) NULL)
04671     cache_info->methods.get_one_virtual_pixel_from_handler=
04672       cache_methods->get_one_virtual_pixel_from_handler;
04673   get_one_authentic_pixel_from_handler=
04674     cache_methods->get_one_authentic_pixel_from_handler;
04675   if (get_one_authentic_pixel_from_handler !=
04676       (GetOneAuthenticPixelFromHandler) NULL)
04677     cache_info->methods.get_one_authentic_pixel_from_handler=
04678       cache_methods->get_one_authentic_pixel_from_handler;
04679 }
04680 
04681 /*
04682 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
04683 %                                                                             %
04684 %                                                                             %
04685 %                                                                             %
04686 +   S e t P i x e l C a c h e N e x u s P i x e l s                           %
04687 %                                                                             %
04688 %                                                                             %
04689 %                                                                             %
04690 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
04691 %
04692 %  SetPixelCacheNexusPixels() defines the region of the cache for the
04693 %  specified cache nexus.
04694 %
04695 %  The format of the SetPixelCacheNexusPixels() method is:
04696 %
04697 %      PixelPacket SetPixelCacheNexusPixels(const Image *image,
04698 %        const RectangleInfo *region,NexusInfo *nexus_info,
04699 %        ExceptionInfo *exception)
04700 %
04701 %  A description of each parameter follows:
04702 %
04703 %    o image: the image.
04704 %
04705 %    o region: A pointer to the RectangleInfo structure that defines the
04706 %      region of this particular cache nexus.
04707 %
04708 %    o nexus_info: the cache nexus to set.
04709 %
04710 %    o exception: return any errors or warnings in this structure.
04711 %
04712 */
04713 static PixelPacket *SetPixelCacheNexusPixels(const Image *image,
04714   const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
04715 {
04716   CacheInfo
04717     *cache_info;
04718 
04719   MagickBooleanType
04720     status;
04721 
04722   MagickOffsetType
04723     offset;
04724 
04725   MagickSizeType
04726     length,
04727     number_pixels;
04728 
04729   if (image->debug != MagickFalse)
04730     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
04731   cache_info=(CacheInfo *) image->cache;
04732   assert(cache_info->signature == MagickSignature);
04733   if (cache_info->type == UndefinedCache)
04734     return((PixelPacket *) NULL);
04735   nexus_info->region.width=region->width == 0UL ? 1UL : region->width;
04736   nexus_info->region.height=region->height == 0UL ? 1UL : region->height;
04737   nexus_info->region.x=region->x;
04738   nexus_info->region.y=region->y;
04739   if ((cache_info->type != DiskCache) && (image->clip_mask == (Image *) NULL) &&
04740       (image->mask == (Image *) NULL))
04741     {
04742       offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
04743         nexus_info->region.x;
04744       length=(MagickSizeType) (nexus_info->region.height-1)*cache_info->columns+
04745         nexus_info->region.width-1;
04746       number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
04747       if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
04748         {
04749           long
04750             x,
04751             y;
04752 
04753           x=nexus_info->region.x+nexus_info->region.width;
04754           y=nexus_info->region.y+nexus_info->region.height;
04755           if ((nexus_info->region.x >= 0) &&
04756               (x <= (long) cache_info->columns) &&
04757               (nexus_info->region.y >= 0) && (y <= (long) cache_info->rows))
04758             if ((nexus_info->region.height == 1UL) ||
04759                 ((nexus_info->region.x == 0) &&
04760                 ((nexus_info->region.width % cache_info->columns) == 0)))
04761               {
04762                 /*
04763                   Pixels are accessed directly from memory.
04764                 */
04765                 nexus_info->pixels=cache_info->pixels+offset;
04766                 nexus_info->indexes=(IndexPacket *) NULL;
04767                 if (cache_info->active_index_channel != MagickFalse)
04768                   nexus_info->indexes=cache_info->indexes+offset;
04769                 return(nexus_info->pixels);
04770               }
04771         }
04772     }
04773   /*
04774     Pixels are stored in a cache region until they are synced to the cache.
04775   */
04776   number_pixels=(MagickSizeType) nexus_info->region.width*
04777     nexus_info->region.height;
04778   length=number_pixels*sizeof(PixelPacket);
04779   if (cache_info->active_index_channel != MagickFalse)
04780     length+=number_pixels*sizeof(IndexPacket);
04781   if (nexus_info->cache == (PixelPacket *) NULL)
04782     {
04783       nexus_info->length=length;
04784       status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
04785       if (status == MagickFalse)
04786         return((PixelPacket *) NULL);
04787     }
04788   else
04789     if (nexus_info->length != length)
04790       {
04791         RelinquishCacheNexusPixels(nexus_info);
04792         nexus_info->length=length;
04793         status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
04794         if (status == MagickFalse)
04795           return((PixelPacket *) NULL);
04796       }
04797   nexus_info->pixels=nexus_info->cache;
04798   nexus_info->indexes=(IndexPacket *) NULL;
04799   if (cache_info->active_index_channel != MagickFalse)
04800     nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
04801   return(nexus_info->pixels);
04802 }
04803 
04804 /*
04805 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
04806 %                                                                             %
04807 %                                                                             %
04808 %                                                                             %
04809 %   S 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                       %
04810 %                                                                             %
04811 %                                                                             %
04812 %                                                                             %
04813 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
04814 %
04815 %  SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
04816 %  pixel cache and returns the previous setting.  A virtual pixel is any pixel
04817 %  access that is outside the boundaries of the image cache.
04818 %
04819 %  The format of the SetPixelCacheVirtualMethod() method is:
04820 %
04821 %      VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
04822 %        const VirtualPixelMethod virtual_pixel_method)
04823 %
04824 %  A description of each parameter follows:
04825 %
04826 %    o image: the image.
04827 %
04828 %    o virtual_pixel_method: choose the type of virtual pixel.
04829 %
04830 */
04831 MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
04832   const VirtualPixelMethod virtual_pixel_method)
04833 {
04834   CacheInfo
04835     *cache_info;
04836 
04837   VirtualPixelMethod
04838     method;
04839 
04840   assert(image != (Image *) NULL);
04841   assert(image->signature == MagickSignature);
04842   if (image->debug != MagickFalse)
04843     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
04844   assert(image->cache != (Cache) NULL);
04845   cache_info=(CacheInfo *) image->cache;
04846   assert(cache_info->signature == MagickSignature);
04847   method=cache_info->virtual_pixel_method;
04848   cache_info->virtual_pixel_method=virtual_pixel_method;
04849   return(method);
04850 }
04851 
04852 /*
04853 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
04854 %                                                                             %
04855 %                                                                             %
04856 %                                                                             %
04857 +   S y n c A u t h e n t i c P i x e l C a c h e N e x u s                   %
04858 %                                                                             %
04859 %                                                                             %
04860 %                                                                             %
04861 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
04862 %
04863 %  SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
04864 %  in-memory or disk cache.  The method returns MagickTrue if the pixel region
04865 %  is synced, otherwise MagickFalse.
04866 %
04867 %  The format of the SyncAuthenticPixelCacheNexus() method is:
04868 %
04869 %      MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
04870 %        NexusInfo *nexus_info,ExceptionInfo *exception)
04871 %
04872 %  A description of each parameter follows:
04873 %
04874 %    o image: the image.
04875 %
04876 %    o nexus_info: the cache nexus to sync.
04877 %
04878 %    o exception: return any errors or warnings in this structure.
04879 %
04880 */
04881 MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
04882   NexusInfo *nexus_info,ExceptionInfo *exception)
04883 {
04884   CacheInfo
04885     *cache_info;
04886 
04887   MagickBooleanType
04888     status;
04889 
04890   /*
04891     Transfer pixels to the cache.
04892   */
04893   assert(image != (Image *) NULL);
04894   assert(image->signature == MagickSignature);
04895   if (image->debug != MagickFalse)
04896     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
04897   if (image->cache == (Cache) NULL)
04898     ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
04899   cache_info=(CacheInfo *) image->cache;
04900   if (cache_info->type == UndefinedCache)
04901     return(MagickFalse);
04902   if ((image->clip_mask != (Image *) NULL) &&
04903       (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
04904     return(MagickFalse);
04905   if ((image->mask != (Image *) NULL) &&
04906       (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
04907     return(MagickFalse);
04908   if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
04909     return(MagickTrue);
04910   assert(cache_info->signature == MagickSignature);
04911   status=WritePixelCachePixels(cache_info,nexus_info,exception);
04912   if ((cache_info->active_index_channel != MagickFalse) &&
04913       (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
04914     return(MagickFalse);
04915   return(status);
04916 }
04917 
04918 /*
04919 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
04920 %                                                                             %
04921 %                                                                             %
04922 %                                                                             %
04923 +   S y n c A u t h e n t i c P i x e l C a c h e                             %
04924 %                                                                             %
04925 %                                                                             %
04926 %                                                                             %
04927 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
04928 %
04929 %  SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
04930 %  or disk cache.  The method returns MagickTrue if the pixel region is synced,
04931 %  otherwise MagickFalse.
04932 %
04933 %  The format of the SyncAuthenticPixelsCache() method is:
04934 %
04935 %      MagickBooleanType SyncAuthenticPixelsCache(Image *image,
04936 %        ExceptionInfo *exception)
04937 %
04938 %  A description of each parameter follows:
04939 %
04940 %    o image: the image.
04941 %
04942 %    o exception: return any errors or warnings in this structure.
04943 %
04944 */
04945 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
04946   ExceptionInfo *exception)
04947 {
04948   CacheInfo
04949     *cache_info;
04950 
04951   long
04952     id;
04953 
04954   MagickBooleanType
04955     status;
04956 
04957   cache_info=(CacheInfo *) image->cache;
04958   id=GetOpenMPThreadId();
04959   assert(id < (long) cache_info->number_threads);
04960   status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
04961     exception);
04962   return(status);
04963 }
04964 
04965 /*
04966 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
04967 %                                                                             %
04968 %                                                                             %
04969 %                                                                             %
04970 %   S y n c A u t h e n t i c P i x e l s                                     %
04971 %                                                                             %
04972 %                                                                             %
04973 %                                                                             %
04974 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
04975 %
04976 %  SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
04977 %  The method returns MagickTrue if the pixel region is flushed, otherwise
04978 %  MagickFalse.
04979 %
04980 %  The format of the SyncAuthenticPixels() method is:
04981 %
04982 %      MagickBooleanType SyncAuthenticPixels(Image *image,
04983 %        ExceptionInfo *exception)
04984 %
04985 %  A description of each parameter follows:
04986 %
04987 %    o image: the image.
04988 %
04989 %    o exception: return any errors or warnings in this structure.
04990 %
04991 */
04992 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
04993   ExceptionInfo *exception)
04994 {
04995   CacheInfo
04996     *cache_info;
04997 
04998   assert(image != (Image *) NULL);
04999   assert(image->signature == MagickSignature);
05000   if (image->debug != MagickFalse)
05001     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
05002   assert(image->cache != (Cache) NULL);
05003   cache_info=(CacheInfo *) image->cache;
05004   assert(cache_info->signature == MagickSignature);
05005   if (cache_info->methods.sync_authentic_pixels_handler ==
05006       (SyncAuthenticPixelsHandler) NULL)
05007     return(MagickFalse);
05008   return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
05009 }
05010 
05011 /*
05012 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
05013 %                                                                             %
05014 %                                                                             %
05015 %                                                                             %
05016 +   W r i t e P i x e l C a c h e I n d e x e s                               %
05017 %                                                                             %
05018 %                                                                             %
05019 %                                                                             %
05020 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
05021 %
05022 %  WritePixelCacheIndexes() writes the colormap indexes to the specified
05023 %  region of the pixel cache.
05024 %
05025 %  The format of the WritePixelCacheIndexes() method is:
05026 %
05027 %      MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
05028 %        NexusInfo *nexus_info,ExceptionInfo *exception)
05029 %
05030 %  A description of each parameter follows:
05031 %
05032 %    o cache_info: the pixel cache.
05033 %
05034 %    o nexus_info: the cache nexus to write the colormap indexes.
05035 %
05036 %    o exception: return any errors or warnings in this structure.
05037 %
05038 */
05039 static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
05040   NexusInfo *nexus_info,ExceptionInfo *exception)
05041 {
05042   MagickOffsetType
05043     count,
05044     offset;
05045 
05046   MagickSizeType
05047     length,
05048     number_pixels;
05049 
05050   register const IndexPacket
05051     *__restrict p;
05052 
05053   register long
05054     y;
05055 
05056   unsigned long
05057     rows;
05058 
05059   if (cache_info->debug != MagickFalse)
05060     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
05061       cache_info->filename);
05062   if (cache_info->active_index_channel == MagickFalse)
05063     return(MagickFalse);
05064   if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
05065     return(MagickTrue);
05066   offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
05067     nexus_info->region.x;
05068   length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
05069   rows=nexus_info->region.height;
05070   number_pixels=(MagickSizeType) length*rows;
05071   if ((cache_info->columns == nexus_info->region.width) &&
05072       (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
05073     {
05074       length=number_pixels;
05075       rows=1UL;
05076     }
05077   p=nexus_info->indexes;
05078   switch (cache_info->type)
05079   {
05080     case MemoryCache:
05081     case MapCache:
05082     {
05083       register IndexPacket
05084         *__restrict q;
05085 
05086       /*
05087         Write indexes to memory.
05088       */
05089       q=cache_info->indexes+offset;
05090       for (y=0; y < (long) rows; y++)
05091       {
05092         (void) CopyMagickMemory(q,p,(size_t) length);
05093         p+=nexus_info->region.width;
05094         q+=cache_info->columns;
05095       }
05096       break;
05097     }
05098     case DiskCache:
05099     {
05100       /*
05101         Write indexes to disk.
05102       */
05103       if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
05104         {
05105           ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
05106             cache_info->cache_filename);
05107           return(MagickFalse);
05108         }
05109       number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
05110       for (y=0; y < (long) rows; y++)
05111       {
05112         count=WritePixelCacheRegion(cache_info,cache_info->offset+number_pixels*
05113           sizeof(PixelPacket)+offset*sizeof(*p),length,
05114           (const unsigned char *) p);
05115         if ((MagickSizeType) count < length)
05116           break;
05117         p+=nexus_info->region.width;
05118         offset+=cache_info->columns;
05119       }
05120       if (y < (long) rows)
05121         {
05122           ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
05123             cache_info->cache_filename);
05124           return(MagickFalse);
05125         }
05126       break;
05127     }
05128     default:
05129       break;
05130   }
05131   if ((cache_info->debug != MagickFalse) &&
05132       (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
05133     (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
05134       cache_info->filename,nexus_info->region.width,nexus_info->region.height,
05135       nexus_info->region.x,nexus_info->region.y);
05136   return(MagickTrue);
05137 }
05138 
05139 /*
05140 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
05141 %                                                                             %
05142 %                                                                             %
05143 %                                                                             %
05144 +   W r i t e C a c h e P i x e l s                                           %
05145 %                                                                             %
05146 %                                                                             %
05147 %                                                                             %
05148 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
05149 %
05150 %  WritePixelCachePixels() writes image pixels to the specified region of the
05151 %  pixel cache.
05152 %
05153 %  The format of the WritePixelCachePixels() method is:
05154 %
05155 %      MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
05156 %        NexusInfo *nexus_info,ExceptionInfo *exception)
05157 %
05158 %  A description of each parameter follows:
05159 %
05160 %    o cache_info: the pixel cache.
05161 %
05162 %    o nexus_info: the cache nexus to write the pixels.
05163 %
05164 %    o exception: return any errors or warnings in this structure.
05165 %
05166 */
05167 static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
05168   NexusInfo *nexus_info,ExceptionInfo *exception)
05169 {
05170   MagickOffsetType
05171     count,
05172     offset;
05173 
05174   MagickSizeType
05175     length,
05176     number_pixels;
05177 
05178   register long
05179     y;
05180 
05181   register const PixelPacket
05182     *__restrict p;
05183 
05184   unsigned long
05185     rows;
05186 
05187   if (cache_info->debug != MagickFalse)
05188     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
05189       cache_info->filename);
05190   if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
05191     return(MagickTrue);
05192   offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
05193     nexus_info->region.x;
05194   length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
05195   rows=nexus_info->region.height;
05196   number_pixels=length*rows;
05197   if ((cache_info->columns == nexus_info->region.width) &&
05198       (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
05199     {
05200       length=number_pixels;
05201       rows=1UL;
05202     }
05203   p=nexus_info->pixels;
05204   switch (cache_info->type)
05205   {
05206     case MemoryCache:
05207     case MapCache:
05208     {
05209       register PixelPacket
05210         *__restrict q;
05211 
05212       /*
05213         Write pixels to memory.
05214       */
05215       q=cache_info->pixels+offset;
05216       for (y=0; y < (long) rows; y++)
05217       {
05218         (void) CopyMagickMemory(q,p,(size_t) length);
05219         p+=nexus_info->region.width;
05220         q+=cache_info->columns;
05221       }
05222       break;
05223     }
05224     case DiskCache:
05225     {
05226       /*
05227         Write pixels to disk.
05228       */
05229       if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
05230         {
05231           ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
05232             cache_info->cache_filename);
05233           return(MagickFalse);
05234         }
05235       for (y=0; y < (long) rows; y++)
05236       {
05237         count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
05238           sizeof(*p),length,(const unsigned char *) p);
05239         if ((MagickSizeType) count < length)
05240           break;
05241         p+=nexus_info->region.width;
05242         offset+=cache_info->columns;
05243       }
05244       if (y < (long) rows)
05245         {
05246           ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
05247             cache_info->cache_filename);
05248           return(MagickFalse);
05249         }
05250       break;
05251     }
05252     default:
05253       break;
05254   }
05255   if ((cache_info->debug != MagickFalse) &&
05256       (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
05257     (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
05258       cache_info->filename,nexus_info->region.width,nexus_info->region.height,
05259       nexus_info->region.x,nexus_info->region.y);
05260   return(MagickTrue);
05261 }

Generated on Thu Jul 2 12:03:13 2009 for MagickCore by  doxygen 1.5.8