source: ImageMagick/trunk/magick/cache.c @ 4683

Revision 4683, 198.0 KB checked in by glennrp, 2 years ago (diff)

spelling (initialize)

Line 
1/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3%                                                                             %
4%                                                                             %
5%                                                                             %
6%                      CCCC   AAA    CCCC  H   H  EEEEE                       %
7%                     C      A   A  C      H   H  E                           %
8%                     C      AAAAA  C      HHHHH  EEE                         %
9%                     C      A   A  C      H   H  E                           %
10%                      CCCC  A   A   CCCC  H   H  EEEEE                       %
11%                                                                             %
12%                                                                             %
13%                       MagickCore Pixel Cache Methods                        %
14%                                                                             %
15%                              Software Design                                %
16%                                John Cristy                                  %
17%                                 July 1999                                   %
18%                                                                             %
19%                                                                             %
20%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
21%  dedicated to making software imaging solutions freely available.           %
22%                                                                             %
23%  You may not use this file except in compliance with the License.  You may  %
24%  obtain a copy of the License at                                            %
25%                                                                             %
26%    http://www.imagemagick.org/script/license.php                            %
27%                                                                             %
28%  Unless required by applicable law or agreed to in writing, software        %
29%  distributed under the License is distributed on an "AS IS" BASIS,          %
30%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31%  See the License for the specific language governing permissions and        %
32%  limitations under the License.                                             %
33%                                                                             %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37%
38*/
39
40/*
41  Include declarations.
42*/
43#include "magick/studio.h"
44#include "magick/blob.h"
45#include "magick/blob-private.h"
46#include "magick/cache.h"
47#include "magick/cache-private.h"
48#include "magick/color-private.h"
49#include "magick/composite-private.h"
50#include "magick/exception.h"
51#include "magick/exception-private.h"
52#include "magick/geometry.h"
53#include "magick/list.h"
54#include "magick/log.h"
55#include "magick/magick.h"
56#include "magick/memory_.h"
57#include "magick/pixel.h"
58#include "magick/pixel-private.h"
59#include "magick/policy.h"
60#include "magick/quantum.h"
61#include "magick/random_.h"
62#include "magick/resource_.h"
63#include "magick/semaphore.h"
64#include "magick/splay-tree.h"
65#include "magick/string_.h"
66#include "magick/string-private.h"
67#include "magick/thread-private.h"
68#include "magick/utility.h"
69#if defined(MAGICKCORE_ZLIB_DELEGATE)
70#include "zlib.h"
71#endif
72
73/*
74  Define declarations.
75*/
76#define CacheTick(offset,extent)  QuantumTick((MagickOffsetType) offset,extent)
77
78/*
79  Typedef declarations.
80*/
81typedef struct _MagickModulo
82{
83  ssize_t
84    quotient,
85    remainder;
86} MagickModulo;
87
88struct _NexusInfo
89{
90  MagickBooleanType
91    mapped;
92
93  RectangleInfo
94    region;
95
96  MagickSizeType
97    length;
98
99  PixelPacket
100    *cache,
101    *pixels;
102
103  IndexPacket
104    *indexes;
105
106  size_t
107    signature;
108};
109
110/*
111  Forward declarations.
112*/
113#if defined(__cplusplus) || defined(c_plusplus)
114extern "C" {
115#endif
116
117static const IndexPacket
118  *GetVirtualIndexesFromCache(const Image *);
119
120static const PixelPacket
121  *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
122    const ssize_t,const size_t,const size_t,ExceptionInfo *),
123  *GetVirtualPixelsCache(const Image *);
124
125static MagickBooleanType
126  GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,
127    PixelPacket *,ExceptionInfo *),
128  GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
129    const ssize_t,const ssize_t,PixelPacket *,ExceptionInfo *),
130  OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
131  ReadPixelCacheIndexes(CacheInfo *,NexusInfo *,ExceptionInfo *),
132  ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
133  SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
134  WritePixelCacheIndexes(CacheInfo *,NexusInfo *,ExceptionInfo *),
135  WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
136
137static PixelPacket
138  *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
139    const size_t,ExceptionInfo *),
140  *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
141    const size_t,ExceptionInfo *),
142  *SetPixelCacheNexusPixels(const Image *,const RectangleInfo *,NexusInfo *,
143    ExceptionInfo *);
144
145#if defined(__cplusplus) || defined(c_plusplus)
146}
147#endif
148
149/*
150  Global declarations.
151*/
152static volatile MagickBooleanType
153  instantiate_cache = MagickFalse;
154
155static SemaphoreInfo
156  *cache_semaphore = (SemaphoreInfo *) NULL;
157
158static SplayTreeInfo
159  *cache_resources = (SplayTreeInfo *) NULL;
160
161/*
162%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
163%                                                                             %
164%                                                                             %
165%                                                                             %
166+   A c q u i r e P i x e l C a c h e                                         %
167%                                                                             %
168%                                                                             %
169%                                                                             %
170%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
171%
172%  AcquirePixelCache() acquires a pixel cache.
173%
174%  The format of the AcquirePixelCache() method is:
175%
176%      Cache AcquirePixelCache(const size_t number_threads)
177%
178%  A description of each parameter follows:
179%
180%    o number_threads: the number of nexus threads.
181%
182*/
183MagickExport Cache AcquirePixelCache(const size_t number_threads)
184{
185  CacheInfo
186    *cache_info;
187
188  cache_info=(CacheInfo *) AcquireMagickMemory(sizeof(*cache_info));
189  if (cache_info == (CacheInfo *) NULL)
190    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
191  (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
192  cache_info->type=UndefinedCache;
193  cache_info->mode=IOMode;
194  cache_info->colorspace=RGBColorspace;
195  cache_info->channels=4;
196  cache_info->file=(-1);
197  cache_info->id=GetMagickThreadId();
198  cache_info->number_threads=number_threads;
199  if (number_threads == 0)
200    cache_info->number_threads=GetOpenMPMaximumThreads();
201  cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
202  if (cache_info->nexus_info == (NexusInfo **) NULL)
203    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
204  cache_info->semaphore=AllocateSemaphoreInfo();
205  cache_info->reference_count=1;
206  cache_info->disk_semaphore=AllocateSemaphoreInfo();
207  cache_info->debug=IsEventLogging();
208  cache_info->signature=MagickSignature;
209  if ((cache_resources == (SplayTreeInfo *) NULL) &&
210      (instantiate_cache == MagickFalse))
211    {
212      if (cache_semaphore == (SemaphoreInfo *) NULL)
213        AcquireSemaphoreInfo(&cache_semaphore);
214      LockSemaphoreInfo(cache_semaphore);
215      if ((cache_resources == (SplayTreeInfo *) NULL) &&
216          (instantiate_cache == MagickFalse))
217        {
218          cache_resources=NewSplayTree((int (*)(const void *,const void *))
219            NULL,(void *(*)(void *)) NULL,(void *(*)(void *)) NULL);
220          instantiate_cache=MagickTrue;
221        }
222      UnlockSemaphoreInfo(cache_semaphore);
223    }
224  (void) AddValueToSplayTree(cache_resources,cache_info,cache_info);
225  return((Cache ) cache_info);
226}
227
228/*
229%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
230%                                                                             %
231%                                                                             %
232%                                                                             %
233%   A c q u i r e P i x e l C a c h e N e x u s                               %
234%                                                                             %
235%                                                                             %
236%                                                                             %
237%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
238%
239%  AcquirePixelCacheNexus() allocates the NexusInfo structure.
240%
241%  The format of the AcquirePixelCacheNexus method is:
242%
243%      NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
244%
245%  A description of each parameter follows:
246%
247%    o number_threads: the number of nexus threads.
248%
249*/
250MagickExport NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
251{
252  NexusInfo
253    **nexus_info;
254
255  register ssize_t
256    i;
257
258  nexus_info=(NexusInfo **) AcquireQuantumMemory(number_threads,
259    sizeof(*nexus_info));
260  if (nexus_info == (NexusInfo **) NULL)
261    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
262  for (i=0; i < (ssize_t) number_threads; i++)
263  {
264    nexus_info[i]=(NexusInfo *) AcquireAlignedMemory(1,sizeof(**nexus_info));
265    if (nexus_info[i] == (NexusInfo *) NULL)
266      ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
267    (void) ResetMagickMemory(nexus_info[i],0,sizeof(*nexus_info[i]));
268    nexus_info[i]->signature=MagickSignature;
269  }
270  return(nexus_info);
271}
272
273/*
274%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
275%                                                                             %
276%                                                                             %
277%                                                                             %
278+   A c q u i r e P i x e l C a c h e P i x e l s                             %
279%                                                                             %
280%                                                                             %
281%                                                                             %
282%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
283%
284%  AcquirePixelCachePixels() returns the pixels associated with the specified
285%  image.
286%
287%  The format of the AcquirePixelCachePixels() method is:
288%
289%      const void *AcquirePixelCachePixels(const Image *image,
290%        MagickSizeType *length,ExceptionInfo *exception)
291%
292%  A description of each parameter follows:
293%
294%    o image: the image.
295%
296%    o length: the pixel cache length.
297%
298%    o exception: return any errors or warnings in this structure.
299%
300*/
301MagickExport const void *AcquirePixelCachePixels(const Image *image,
302  MagickSizeType *length,ExceptionInfo *exception)
303{
304  CacheInfo
305    *cache_info;
306
307  assert(image != (const Image *) NULL);
308  assert(image->signature == MagickSignature);
309  assert(exception != (ExceptionInfo *) NULL);
310  assert(exception->signature == MagickSignature);
311  assert(image->cache != (Cache) NULL);
312  cache_info=(CacheInfo *) image->cache;
313  assert(cache_info->signature == MagickSignature);
314  *length=0;
315  if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
316    return((const void *) NULL);
317  *length=cache_info->length;
318  return((const void *) cache_info->pixels);
319}
320
321/*
322%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
323%                                                                             %
324%                                                                             %
325%                                                                             %
326+   C a c h e C o m p o n e n t G e n e s i s                                 %
327%                                                                             %
328%                                                                             %
329%                                                                             %
330%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
331%
332%  CacheComponentGenesis() instantiates the cache component.
333%
334%  The format of the CacheComponentGenesis method is:
335%
336%      MagickBooleanType CacheComponentGenesis(void)
337%
338*/
339MagickExport MagickBooleanType CacheComponentGenesis(void)
340{
341  AcquireSemaphoreInfo(&cache_semaphore);
342  return(MagickTrue);
343}
344
345/*
346%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
347%                                                                             %
348%                                                                             %
349%                                                                             %
350+   C a c h e C o m p o n e n t T e r m i n u s                               %
351%                                                                             %
352%                                                                             %
353%                                                                             %
354%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
355%
356%  CacheComponentTerminus() destroys the cache component.
357%
358%  The format of the CacheComponentTerminus() method is:
359%
360%      CacheComponentTerminus(void)
361%
362*/
363MagickExport void CacheComponentTerminus(void)
364{
365  if (cache_semaphore == (SemaphoreInfo *) NULL)
366    AcquireSemaphoreInfo(&cache_semaphore);
367  LockSemaphoreInfo(cache_semaphore);
368  if (cache_resources != (SplayTreeInfo *) NULL)
369    cache_resources=DestroySplayTree(cache_resources);
370  instantiate_cache=MagickFalse;
371  UnlockSemaphoreInfo(cache_semaphore);
372  DestroySemaphoreInfo(&cache_semaphore);
373}
374
375/*
376%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
377%                                                                             %
378%                                                                             %
379%                                                                             %
380+   C l i p P i x e l C a c h e N e x u s                                     %
381%                                                                             %
382%                                                                             %
383%                                                                             %
384%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
385%
386%  ClipPixelCacheNexus() clips the cache nexus as defined by the image clip
387%  mask.  The method returns MagickTrue if the pixel region is clipped,
388%  otherwise MagickFalse.
389%
390%  The format of the ClipPixelCacheNexus() method is:
391%
392%      MagickBooleanType ClipPixelCacheNexus(Image *image,NexusInfo *nexus_info,
393%        ExceptionInfo *exception)
394%
395%  A description of each parameter follows:
396%
397%    o image: the image.
398%
399%    o nexus_info: the cache nexus to clip.
400%
401%    o exception: return any errors or warnings in this structure.
402%
403*/
404static MagickBooleanType ClipPixelCacheNexus(Image *image,
405  NexusInfo *nexus_info,ExceptionInfo *exception)
406{
407  CacheInfo
408    *cache_info;
409
410  MagickSizeType
411    number_pixels;
412
413  NexusInfo
414    **clip_nexus,
415    **image_nexus;
416
417  register const PixelPacket
418    *restrict r;
419
420  register IndexPacket
421    *restrict nexus_indexes,
422    *restrict indexes;
423
424  register PixelPacket
425    *restrict p,
426    *restrict q;
427
428  register ssize_t
429    i;
430
431  /*
432    Apply clip mask.
433  */
434  if (image->debug != MagickFalse)
435    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
436  if (image->clip_mask == (Image *) NULL)
437    return(MagickFalse);
438  cache_info=(CacheInfo *) image->cache;
439  if (cache_info == (Cache) NULL)
440    return(MagickFalse);
441  image_nexus=AcquirePixelCacheNexus(1);
442  clip_nexus=AcquirePixelCacheNexus(1);
443  if ((image_nexus == (NexusInfo **) NULL) ||
444      (clip_nexus == (NexusInfo **) NULL))
445    ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
446  p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,nexus_info->region.y,
447    nexus_info->region.width,nexus_info->region.height,image_nexus[0],
448    exception);
449  indexes=GetPixelCacheNexusIndexes(cache_info,image_nexus[0]);
450  q=nexus_info->pixels;
451  nexus_indexes=nexus_info->indexes;
452  r=GetVirtualPixelsFromNexus(image->clip_mask,MaskVirtualPixelMethod,
453    nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
454    nexus_info->region.height,clip_nexus[0],exception);
455  number_pixels=(MagickSizeType) nexus_info->region.width*
456    nexus_info->region.height;
457  for (i=0; i < (ssize_t) number_pixels; i++)
458  {
459    if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
460      break;
461    if (PixelIntensityToQuantum(r) > ((Quantum) QuantumRange/2))
462      {
463        SetPixelRed(q,GetPixelRed(p));
464        SetPixelGreen(q,GetPixelGreen(p));
465        SetPixelBlue(q,GetPixelBlue(p));
466        SetPixelOpacity(q,GetPixelOpacity(p));
467        if (cache_info->active_index_channel != MagickFalse)
468          SetPixelIndex(nexus_indexes+i,GetPixelIndex(
469            indexes+i));
470      }
471    p++;
472    q++;
473    r++;
474  }
475  clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
476  image_nexus=DestroyPixelCacheNexus(image_nexus,1);
477  if (i < (ssize_t) number_pixels)
478    return(MagickFalse);
479  return(MagickTrue);
480}
481
482/*
483%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
484%                                                                             %
485%                                                                             %
486%                                                                             %
487+   C l o n e P i x e l C a c h e                                             %
488%                                                                             %
489%                                                                             %
490%                                                                             %
491%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
492%
493%  ClonePixelCache() clones a pixel cache.
494%
495%  The format of the ClonePixelCache() method is:
496%
497%      Cache ClonePixelCache(const Cache cache)
498%
499%  A description of each parameter follows:
500%
501%    o cache: the pixel cache.
502%
503*/
504MagickExport Cache ClonePixelCache(const Cache cache)
505{
506  CacheInfo
507    *clone_info;
508
509  const CacheInfo
510    *cache_info;
511
512  assert(cache != (const Cache) NULL);
513  cache_info=(const CacheInfo *) cache;
514  assert(cache_info->signature == MagickSignature);
515  if (cache_info->debug != MagickFalse)
516    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
517      cache_info->filename);
518  clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
519  if (clone_info == (Cache) NULL)
520    return((Cache) NULL);
521  clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
522  return((Cache ) clone_info);
523}
524
525/*
526%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
527%                                                                             %
528%                                                                             %
529%                                                                             %
530+   C l o n e P i x e l C a c h e P i x e l s                                 %
531%                                                                             %
532%                                                                             %
533%                                                                             %
534%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
535%  ClonePixelCachePixels() clones the source pixel cache to the destination
536%  cache.
537%
538%  The format of the ClonePixelCachePixels() method is:
539%
540%      MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
541%        CacheInfo *source_info,ExceptionInfo *exception)
542%
543%  A description of each parameter follows:
544%
545%    o cache_info: the pixel cache.
546%
547%    o source_info: the source pixel cache.
548%
549%    o exception: return any errors or warnings in this structure.
550%
551*/
552
553static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
554{
555  int
556    status;
557
558  status=(-1);
559  LockSemaphoreInfo(cache_info->disk_semaphore);
560  if (cache_info->file != -1)
561    status=close(cache_info->file);
562  cache_info->file=(-1);
563  RelinquishMagickResource(FileResource,1);
564  UnlockSemaphoreInfo(cache_info->disk_semaphore);
565  return(status == -1 ? MagickFalse : MagickTrue);
566}
567
568static void LimitPixelCacheDescriptors(void)
569{
570  register CacheInfo
571    *p,
572    *q;
573
574  /*
575    Limit # of open file descriptors.
576  */
577  if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
578    return;
579  LockSemaphoreInfo(cache_semaphore);
580  if (cache_resources == (SplayTreeInfo *) NULL)
581    {
582      UnlockSemaphoreInfo(cache_semaphore);
583      return;
584    }
585  ResetSplayTreeIterator(cache_resources);
586  p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
587  while (p != (CacheInfo *) NULL)
588  {
589    if ((p->type == DiskCache) && (p->file != -1))
590      break;
591    p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
592  }
593  for (q=p; p != (CacheInfo *) NULL; )
594  {
595    if ((p->type == DiskCache) && (p->file != -1) &&
596        (p->timestamp < q->timestamp))
597      q=p;
598    p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
599  }
600  if (q != (CacheInfo *) NULL)
601    {
602      /*
603        Close least recently used cache.
604      */
605      (void) close(q->file);
606      q->file=(-1);
607    }
608  UnlockSemaphoreInfo(cache_semaphore);
609}
610
611static inline MagickSizeType MagickMax(const MagickSizeType x,
612  const MagickSizeType y)
613{
614  if (x > y)
615    return(x);
616  return(y);
617}
618
619static inline MagickSizeType MagickMin(const MagickSizeType x,
620  const MagickSizeType y)
621{
622  if (x < y)
623    return(x);
624  return(y);
625}
626
627static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
628  const MapMode mode)
629{
630  int
631    file;
632
633  /*
634    Open pixel cache on disk.
635  */
636  LockSemaphoreInfo(cache_info->disk_semaphore);
637  if (cache_info->file != -1)
638    {
639      UnlockSemaphoreInfo(cache_info->disk_semaphore);
640      return(MagickTrue);  /* cache already open */
641    }
642  LimitPixelCacheDescriptors();
643  if (*cache_info->cache_filename == '\0')
644    file=AcquireUniqueFileResource(cache_info->cache_filename);
645  else
646    switch (mode)
647    {
648      case ReadMode:
649      {
650        file=open(cache_info->cache_filename,O_RDONLY | O_BINARY);
651        break;
652      }
653      case WriteMode:
654      {
655        file=open(cache_info->cache_filename,O_WRONLY | O_CREAT | O_BINARY |
656          O_EXCL,S_MODE);
657        if (file == -1)
658          file=open(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
659        break;
660      }
661      case IOMode:
662      default:
663      {
664        file=open(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
665          O_EXCL,S_MODE);
666        if (file == -1)
667          file=open(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
668        break;
669      }
670    }
671  if (file == -1)
672    {
673      UnlockSemaphoreInfo(cache_info->disk_semaphore);
674      return(MagickFalse);
675    }
676  (void) AcquireMagickResource(FileResource,1);
677  cache_info->file=file;
678  cache_info->timestamp=time(0);
679  UnlockSemaphoreInfo(cache_info->disk_semaphore);
680  return(MagickTrue);
681}
682
683static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
684  const MagickOffsetType offset,const MagickSizeType length,
685  unsigned char *restrict buffer)
686{
687  register MagickOffsetType
688    i;
689
690  ssize_t
691    count;
692
693  cache_info->timestamp=time(0);
694#if !defined(MAGICKCORE_HAVE_PREAD)
695  LockSemaphoreInfo(cache_info->disk_semaphore);
696  if (lseek(cache_info->file,offset,SEEK_SET) < 0)
697    {
698      UnlockSemaphoreInfo(cache_info->disk_semaphore);
699      return((MagickOffsetType) -1);
700    }
701#endif
702  count=0;
703  for (i=0; i < (MagickOffsetType) length; i+=count)
704  {
705#if !defined(MAGICKCORE_HAVE_PREAD)
706    count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
707      (MagickSizeType) SSIZE_MAX));
708#else
709    count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
710      (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
711#endif
712    if (count > 0)
713      continue;
714    count=0;
715    if (errno != EINTR)
716      {
717        i=(-1);
718        break;
719      }
720  }
721#if !defined(MAGICKCORE_HAVE_PREAD)
722  UnlockSemaphoreInfo(cache_info->disk_semaphore);
723#endif
724  return(i);
725}
726
727static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
728  const MagickOffsetType offset,const MagickSizeType length,
729  const unsigned char *restrict buffer)
730{
731  register MagickOffsetType
732    i;
733
734  ssize_t
735    count;
736
737  cache_info->timestamp=time(0);
738#if !defined(MAGICKCORE_HAVE_PWRITE)
739  LockSemaphoreInfo(cache_info->disk_semaphore);
740  if (lseek(cache_info->file,offset,SEEK_SET) < 0)
741    {
742      UnlockSemaphoreInfo(cache_info->disk_semaphore);
743      return((MagickOffsetType) -1);
744    }
745#endif
746  count=0;
747  for (i=0; i < (MagickOffsetType) length; i+=count)
748  {
749#if !defined(MAGICKCORE_HAVE_PWRITE)
750    count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
751      (MagickSizeType) SSIZE_MAX));
752#else
753    count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
754      (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
755#endif
756    if (count > 0)
757      continue;
758    count=0;
759    if (errno != EINTR)
760      {
761        i=(-1);
762        break;
763      }
764  }
765#if !defined(MAGICKCORE_HAVE_PWRITE)
766  UnlockSemaphoreInfo(cache_info->disk_semaphore);
767#endif
768  return(i);
769}
770
771static MagickBooleanType CloneDiskToDiskPixelCache(CacheInfo *clone_info,
772  CacheInfo *cache_info,ExceptionInfo *exception)
773{
774  MagickOffsetType
775    count,
776    offset,
777    source_offset;
778
779  MagickSizeType
780    length;
781
782  register PixelPacket
783    *restrict pixels;
784
785  register ssize_t
786    y;
787
788  size_t
789    columns,
790    rows;
791
792  if (cache_info->debug != MagickFalse)
793    (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
794  if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
795    {
796      ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
797        clone_info->cache_filename);
798      return(MagickFalse);
799    }
800  if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
801    {
802      ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
803        cache_info->cache_filename);
804      return(MagickFalse);
805    }
806  columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
807  rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
808  if ((clone_info->active_index_channel != MagickFalse) &&
809      (cache_info->active_index_channel != MagickFalse))
810    {
811      register IndexPacket
812        *indexes;
813
814      /*
815        Clone cache indexes.
816      */
817      length=MagickMax(clone_info->columns,cache_info->columns)*
818        sizeof(*indexes);
819      indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
820      if (indexes == (IndexPacket *) NULL)
821        {
822          (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
823            "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
824          return(MagickFalse);
825        }
826      (void) ResetMagickMemory(indexes,0,(size_t) length);
827      length=columns*sizeof(*indexes);
828      source_offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
829        sizeof(*pixels);
830      offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
831        sizeof(*pixels);
832      for (y=0; y < (ssize_t) rows; y++)
833      {
834        count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
835          length,(unsigned char *) indexes);
836        if ((MagickSizeType) count != length)
837          break;
838        count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
839          (unsigned char *) indexes);
840        if ((MagickSizeType) count != length)
841          break;
842        source_offset+=cache_info->columns*sizeof(*indexes);
843        offset+=clone_info->columns*sizeof(*indexes);
844      }
845      if (y < (ssize_t) rows)
846        {
847          indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
848          ThrowFileException(exception,CacheError,"UnableToCloneCache",
849            cache_info->cache_filename);
850          return(MagickFalse);
851        }
852      if (clone_info->columns > cache_info->columns)
853        {
854          length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
855          (void) ResetMagickMemory(indexes,0,(size_t) length);
856          offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
857            sizeof(*pixels);
858          for (y=0; y < (ssize_t) rows; y++)
859          {
860            count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
861              length,(unsigned char *) indexes);
862            if ((MagickSizeType) count != length)
863              break;
864            offset+=clone_info->columns*sizeof(*indexes);
865          }
866          if (y < (ssize_t) rows)
867            {
868              indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
869              ThrowFileException(exception,CacheError,"UnableToCloneCache",
870                cache_info->cache_filename);
871              return(MagickFalse);
872            }
873        }
874      indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
875    }
876  /*
877    Clone cache pixels.
878  */
879  length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
880  pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
881  if (pixels == (PixelPacket *) NULL)
882    {
883      (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
884        "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
885      return(MagickFalse);
886    }
887  (void) ResetMagickMemory(pixels,0,(size_t) length);
888  length=columns*sizeof(*pixels);
889  source_offset=0;
890  offset=0;
891  for (y=0; y < (ssize_t) rows; y++)
892  {
893    count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
894      length,(unsigned char *) pixels);
895    if ((MagickSizeType) count != length)
896      break;
897    count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
898      (unsigned char *) pixels);
899    if ((MagickSizeType) count != length)
900      break;
901    source_offset+=cache_info->columns*sizeof(*pixels);
902    offset+=clone_info->columns*sizeof(*pixels);
903  }
904  if (y < (ssize_t) rows)
905    {
906      pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
907      ThrowFileException(exception,CacheError,"UnableToCloneCache",
908        cache_info->cache_filename);
909      return(MagickFalse);
910    }
911  if (clone_info->columns > cache_info->columns)
912    {
913      length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
914      (void) ResetMagickMemory(pixels,0,(size_t) length);
915      offset=(MagickOffsetType) columns*sizeof(*pixels);
916      for (y=0; y < (ssize_t) rows; y++)
917      {
918        count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
919          (unsigned char *) pixels);
920        if ((MagickSizeType) count != length)
921          break;
922        offset+=clone_info->columns*sizeof(*pixels);
923      }
924      if (y < (ssize_t) rows)
925        {
926          pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
927          ThrowFileException(exception,CacheError,"UnableToCloneCache",
928            cache_info->cache_filename);
929          return(MagickFalse);
930        }
931    }
932  pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
933  return(MagickTrue);
934}
935
936static MagickBooleanType CloneDiskToMemoryPixelCache(CacheInfo *clone_info,
937  CacheInfo *cache_info,ExceptionInfo *exception)
938{
939  MagickOffsetType
940    count,
941    offset;
942
943  MagickSizeType
944    length;
945
946  register PixelPacket
947    *restrict pixels,
948    *restrict q;
949
950  register ssize_t
951    y;
952
953  size_t
954    columns,
955    rows;
956
957  if (cache_info->debug != MagickFalse)
958    (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
959  if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
960    {
961      ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
962        cache_info->cache_filename);
963      return(MagickFalse);
964    }
965  columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
966  rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
967  if ((clone_info->active_index_channel != MagickFalse) &&
968      (cache_info->active_index_channel != MagickFalse))
969    {
970      register IndexPacket
971        *indexes,
972        *q;
973
974      /*
975        Clone cache indexes.
976      */
977      length=MagickMax(clone_info->columns,cache_info->columns)*
978        sizeof(*indexes);
979      indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
980      if (indexes == (IndexPacket *) NULL)
981        {
982          (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
983            "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
984          return(MagickFalse);
985        }
986      (void) ResetMagickMemory(indexes,0,(size_t) length);
987      length=columns*sizeof(IndexPacket);
988      offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
989        sizeof(*pixels);
990      q=clone_info->indexes;
991      for (y=0; y < (ssize_t) rows; y++)
992      {
993        count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,
994          length,(unsigned char *) indexes);
995        if ((MagickSizeType) count != length)
996          break;
997        (void) memcpy(q,indexes,(size_t) length);
998        if ((MagickSizeType) count != length)
999          break;
1000        offset+=cache_info->columns*sizeof(*indexes);
1001        q+=clone_info->columns;
1002      }
1003      if (y < (ssize_t) rows)
1004        {
1005          indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1006          ThrowFileException(exception,CacheError,"UnableToCloneCache",
1007            cache_info->cache_filename);
1008          return(MagickFalse);
1009        }
1010      indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1011    }
1012  /*
1013    Clone cache pixels.
1014  */
1015  length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1016  pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1017  if (pixels == (PixelPacket *) NULL)
1018    {
1019      (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1020        "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1021      return(MagickFalse);
1022    }
1023  (void) ResetMagickMemory(pixels,0,(size_t) length);
1024  length=columns*sizeof(*pixels);
1025  offset=0;
1026  q=clone_info->pixels;
1027  for (y=0; y < (ssize_t) rows; y++)
1028  {
1029    count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,length,
1030      (unsigned char *) pixels);
1031    if ((MagickSizeType) count != length)
1032      break;
1033    (void) memcpy(q,pixels,(size_t) length);
1034    offset+=cache_info->columns*sizeof(*pixels);
1035    q+=clone_info->columns;
1036  }
1037  if (y < (ssize_t) rows)
1038    {
1039      pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1040      ThrowFileException(exception,CacheError,"UnableToCloneCache",
1041        cache_info->cache_filename);
1042      return(MagickFalse);
1043    }
1044  pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1045  return(MagickTrue);
1046}
1047
1048static MagickBooleanType CloneMemoryToDiskPixelCache(CacheInfo *clone_info,
1049  CacheInfo *cache_info,ExceptionInfo *exception)
1050{
1051  MagickOffsetType
1052    count,
1053    offset;
1054
1055  MagickSizeType
1056    length;
1057
1058  register PixelPacket
1059    *restrict p,
1060    *restrict pixels;
1061
1062  register ssize_t
1063    y;
1064
1065  size_t
1066    columns,
1067    rows;
1068
1069  if (cache_info->debug != MagickFalse)
1070    (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
1071  if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
1072    {
1073      ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1074        clone_info->cache_filename);
1075      return(MagickFalse);
1076    }
1077  columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1078  rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
1079  if ((clone_info->active_index_channel != MagickFalse) &&
1080      (cache_info->active_index_channel != MagickFalse))
1081    {
1082      register IndexPacket
1083        *p,
1084        *indexes;
1085
1086      /*
1087        Clone cache indexes.
1088      */
1089      length=MagickMax(clone_info->columns,cache_info->columns)*
1090        sizeof(*indexes);
1091      indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1092      if (indexes == (IndexPacket *) NULL)
1093        {
1094          (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1095            "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1096          return(MagickFalse);
1097        }
1098      (void) ResetMagickMemory(indexes,0,(size_t) length);
1099      length=columns*sizeof(*indexes);
1100      p=cache_info->indexes;
1101      offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1102        sizeof(*pixels);
1103      for (y=0; y < (ssize_t) rows; y++)
1104      {
1105        (void) memcpy(indexes,p,(size_t) length);
1106        count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1107          (unsigned char *) indexes);
1108        if ((MagickSizeType) count != length)
1109          break;
1110        p+=cache_info->columns;
1111        offset+=clone_info->columns*sizeof(*indexes);
1112      }
1113      if (y < (ssize_t) rows)
1114        {
1115          indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1116          ThrowFileException(exception,CacheError,"UnableToCloneCache",
1117            cache_info->cache_filename);
1118          return(MagickFalse);
1119        }
1120      if (clone_info->columns > cache_info->columns)
1121        {
1122          length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
1123          (void) ResetMagickMemory(indexes,0,(size_t) length);
1124          offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1125            sizeof(*pixels);
1126          for (y=0; y < (ssize_t) rows; y++)
1127          {
1128            count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
1129              length,(unsigned char *) indexes);
1130            if ((MagickSizeType) count != length)
1131              break;
1132            offset+=clone_info->columns*sizeof(*indexes);
1133          }
1134          if (y < (ssize_t) rows)
1135            {
1136              indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1137              ThrowFileException(exception,CacheError,"UnableToCloneCache",
1138                cache_info->cache_filename);
1139              return(MagickFalse);
1140            }
1141        }
1142      indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1143    }
1144  /*
1145    Clone cache pixels.
1146  */
1147  length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1148  pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1149  if (pixels == (PixelPacket *) NULL)
1150    {
1151      (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1152        "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1153      return(MagickFalse);
1154    }
1155  (void) ResetMagickMemory(pixels,0,(size_t) length);
1156  length=columns*sizeof(*pixels);
1157  p=cache_info->pixels;
1158  offset=0;
1159  for (y=0; y < (ssize_t) rows; y++)
1160  {
1161    (void) memcpy(pixels,p,(size_t) length);
1162    count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1163      (unsigned char *) pixels);
1164    if ((MagickSizeType) count != length)
1165      break;
1166    p+=cache_info->columns;
1167    offset+=clone_info->columns*sizeof(*pixels);
1168  }
1169  if (y < (ssize_t) rows)
1170    {
1171      pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1172      ThrowFileException(exception,CacheError,"UnableToCloneCache",
1173        cache_info->cache_filename);
1174      return(MagickFalse);
1175    }
1176  if (clone_info->columns > cache_info->columns)
1177    {
1178      length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1179      (void) ResetMagickMemory(pixels,0,(size_t) length);
1180      offset=(MagickOffsetType) columns*sizeof(*pixels);
1181      for (y=0; y < (ssize_t) rows; y++)
1182      {
1183        count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1184          (unsigned char *) pixels);
1185        if ((MagickSizeType) count != length)
1186          break;
1187        offset+=clone_info->columns*sizeof(*pixels);
1188      }
1189      if (y < (ssize_t) rows)
1190        {
1191          pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1192          ThrowFileException(exception,CacheError,"UnableToCloneCache",
1193            cache_info->cache_filename);
1194          return(MagickFalse);
1195        }
1196    }
1197  pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1198  return(MagickTrue);
1199}
1200
1201static MagickBooleanType CloneMemoryToMemoryPixelCache(CacheInfo *clone_info,
1202  CacheInfo *cache_info,ExceptionInfo *magick_unused(exception))
1203{
1204  register PixelPacket
1205    *restrict pixels,
1206    *restrict source_pixels;
1207
1208  register ssize_t
1209    y;
1210
1211  size_t
1212    columns,
1213    length,
1214    rows;
1215
1216  if (cache_info->debug != MagickFalse)
1217    (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
1218  columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1219  rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
1220  if ((clone_info->active_index_channel != MagickFalse) &&
1221      (cache_info->active_index_channel != MagickFalse))
1222    {
1223      register IndexPacket
1224        *indexes,
1225        *source_indexes;
1226
1227      /*
1228        Clone cache indexes.
1229      */
1230      length=columns*sizeof(*indexes);
1231      if (clone_info->columns == cache_info->columns)
1232        (void) memcpy(clone_info->indexes,cache_info->indexes,length*rows);
1233      else
1234        {
1235          source_indexes=cache_info->indexes;
1236          indexes=clone_info->indexes;
1237          for (y=0; y < (ssize_t) rows; y++)
1238          {
1239            (void) memcpy(indexes,source_indexes,length);
1240            source_indexes+=cache_info->columns;
1241            indexes+=clone_info->columns;
1242          }
1243          if (clone_info->columns > cache_info->columns)
1244            {
1245              length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
1246              indexes=clone_info->indexes+cache_info->columns;
1247              for (y=0; y < (ssize_t) rows; y++)
1248              {
1249                (void) ResetMagickMemory(indexes,0,length);
1250                indexes+=clone_info->columns;
1251              }
1252            }
1253        }
1254    }
1255  /*
1256    Clone cache pixels.
1257  */
1258  length=columns*sizeof(*pixels);
1259  if (clone_info->columns == cache_info->columns)
1260    (void) memcpy(clone_info->pixels,cache_info->pixels,length*rows);
1261  else
1262    {
1263      source_pixels=cache_info->pixels;
1264      pixels=clone_info->pixels;
1265      for (y=0; y < (ssize_t) rows; y++)
1266      {
1267        (void) memcpy(pixels,source_pixels,length);
1268        source_pixels+=cache_info->columns;
1269        pixels+=clone_info->columns;
1270      }
1271      if (clone_info->columns > cache_info->columns)
1272        {
1273          length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1274          pixels=clone_info->pixels+cache_info->columns;
1275          for (y=0; y < (ssize_t) rows; y++)
1276          {
1277            (void) ResetMagickMemory(pixels,0,length);
1278            pixels+=clone_info->columns;
1279          }
1280        }
1281    }
1282  return(MagickTrue);
1283}
1284
1285static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1286  CacheInfo *cache_info,ExceptionInfo *exception)
1287{
1288  if (cache_info->type == PingCache)
1289    return(MagickTrue);
1290  if ((clone_info->type != DiskCache) && (cache_info->type != DiskCache))
1291    return(CloneMemoryToMemoryPixelCache(clone_info,cache_info,exception));
1292  if ((clone_info->type == DiskCache) && (cache_info->type == DiskCache))
1293    return(CloneDiskToDiskPixelCache(clone_info,cache_info,exception));
1294  if (cache_info->type == DiskCache)
1295    return(CloneDiskToMemoryPixelCache(clone_info,cache_info,exception));
1296  return(CloneMemoryToDiskPixelCache(clone_info,cache_info,exception));
1297}
1298
1299/*
1300%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1301%                                                                             %
1302%                                                                             %
1303%                                                                             %
1304+   C l o n e P i x e l C a c h e M e t h o d s                               %
1305%                                                                             %
1306%                                                                             %
1307%                                                                             %
1308%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1309%
1310%  ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1311%  another.
1312%
1313%  The format of the ClonePixelCacheMethods() method is:
1314%
1315%      void ClonePixelCacheMethods(Cache clone,const Cache cache)
1316%
1317%  A description of each parameter follows:
1318%
1319%    o clone: Specifies a pointer to a Cache structure.
1320%
1321%    o cache: the pixel cache.
1322%
1323*/
1324MagickExport void ClonePixelCacheMethods(Cache clone,const Cache cache)
1325{
1326  CacheInfo
1327    *cache_info,
1328    *source_info;
1329
1330  assert(clone != (Cache) NULL);
1331  source_info=(CacheInfo *) clone;
1332  assert(source_info->signature == MagickSignature);
1333  if (source_info->debug != MagickFalse)
1334    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1335      source_info->filename);
1336  assert(cache != (Cache) NULL);
1337  cache_info=(CacheInfo *) cache;
1338  assert(cache_info->signature == MagickSignature);
1339  source_info->methods=cache_info->methods;
1340}
1341
1342/*
1343%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1344%                                                                             %
1345%                                                                             %
1346%                                                                             %
1347+   D e s t r o y I m a g e P i x e l C a c h e                               %
1348%                                                                             %
1349%                                                                             %
1350%                                                                             %
1351%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1352%
1353%  DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1354%
1355%  The format of the DestroyImagePixelCache() method is:
1356%
1357%      void DestroyImagePixelCache(Image *image)
1358%
1359%  A description of each parameter follows:
1360%
1361%    o image: the image.
1362%
1363*/
1364static void DestroyImagePixelCache(Image *image)
1365{
1366  assert(image != (Image *) NULL);
1367  assert(image->signature == MagickSignature);
1368  if (image->debug != MagickFalse)
1369    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1370  if (image->cache == (void *) NULL)
1371    return;
1372  image->cache=DestroyPixelCache(image->cache);
1373}
1374
1375/*
1376%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1377%                                                                             %
1378%                                                                             %
1379%                                                                             %
1380+   D e s t r o y I m a g e P i x e l s                                       %
1381%                                                                             %
1382%                                                                             %
1383%                                                                             %
1384%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1385%
1386%  DestroyImagePixels() deallocates memory associated with the pixel cache.
1387%
1388%  The format of the DestroyImagePixels() method is:
1389%
1390%      void DestroyImagePixels(Image *image)
1391%
1392%  A description of each parameter follows:
1393%
1394%    o image: the image.
1395%
1396*/
1397MagickExport void DestroyImagePixels(Image *image)
1398{
1399  CacheInfo
1400    *cache_info;
1401
1402  assert(image != (const Image *) NULL);
1403  assert(image->signature == MagickSignature);
1404  if (image->debug != MagickFalse)
1405    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1406  assert(image->cache != (Cache) NULL);
1407  cache_info=(CacheInfo *) image->cache;
1408  assert(cache_info->signature == MagickSignature);
1409  if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1410    {
1411      cache_info->methods.destroy_pixel_handler(image);
1412      return;
1413    }
1414  image->cache=DestroyPixelCache(image->cache);
1415}
1416
1417/*
1418%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1419%                                                                             %
1420%                                                                             %
1421%                                                                             %
1422+   D e s t r o y P i x e l C a c h e                                         %
1423%                                                                             %
1424%                                                                             %
1425%                                                                             %
1426%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1427%
1428%  DestroyPixelCache() deallocates memory associated with the pixel cache.
1429%
1430%  The format of the DestroyPixelCache() method is:
1431%
1432%      Cache DestroyPixelCache(Cache cache)
1433%
1434%  A description of each parameter follows:
1435%
1436%    o cache: the pixel cache.
1437%
1438*/
1439
1440static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1441{
1442  switch (cache_info->type)
1443  {
1444    case MemoryCache:
1445    {
1446      if (cache_info->mapped == MagickFalse)
1447        cache_info->pixels=(PixelPacket *) RelinquishMagickMemory(
1448          cache_info->pixels);
1449      else
1450        cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,
1451          (size_t) cache_info->length);
1452      RelinquishMagickResource(MemoryResource,cache_info->length);
1453      break;
1454    }
1455    case MapCache:
1456    {
1457      cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,(size_t)
1458        cache_info->length);
1459      RelinquishMagickResource(MapResource,cache_info->length);
1460    }
1461    case DiskCache:
1462    {
1463      if (cache_info->file != -1)
1464        (void) ClosePixelCacheOnDisk(cache_info);
1465      RelinquishMagickResource(DiskResource,cache_info->length);
1466      break;
1467    }
1468    default:
1469      break;
1470  }
1471  cache_info->type=UndefinedCache;
1472  cache_info->mapped=MagickFalse;
1473  cache_info->indexes=(IndexPacket *) NULL;
1474}
1475
1476MagickExport Cache DestroyPixelCache(Cache cache)
1477{
1478  CacheInfo
1479    *cache_info;
1480
1481  assert(cache != (Cache) NULL);
1482  cache_info=(CacheInfo *) cache;
1483  assert(cache_info->signature == MagickSignature);
1484  if (cache_info->debug != MagickFalse)
1485    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1486      cache_info->filename);
1487  LockSemaphoreInfo(cache_info->semaphore);
1488  cache_info->reference_count--;
1489  if (cache_info->reference_count != 0)
1490    {
1491      UnlockSemaphoreInfo(cache_info->semaphore);
1492      return((Cache) NULL);
1493    }
1494  UnlockSemaphoreInfo(cache_info->semaphore);
1495  if (cache_resources != (SplayTreeInfo *) NULL)
1496    (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
1497  if (cache_info->debug != MagickFalse)
1498    {
1499      char
1500        message[MaxTextExtent];
1501
1502      (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
1503        cache_info->filename);
1504      (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1505    }
1506  if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1507      (cache_info->type != DiskCache)))
1508    RelinquishPixelCachePixels(cache_info);
1509  else
1510    {
1511      RelinquishPixelCachePixels(cache_info);
1512      (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1513    }
1514  *cache_info->cache_filename='\0';
1515  if (cache_info->nexus_info != (NexusInfo **) NULL)
1516    cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1517      cache_info->number_threads);
1518  if (cache_info->random_info != (RandomInfo *) NULL)
1519    cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
1520  if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1521    DestroySemaphoreInfo(&cache_info->disk_semaphore);
1522  if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1523    DestroySemaphoreInfo(&cache_info->semaphore);
1524  cache_info->signature=(~MagickSignature);
1525  cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
1526  cache=(Cache) NULL;
1527  return(cache);
1528}
1529
1530/*
1531%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1532%                                                                             %
1533%                                                                             %
1534%                                                                             %
1535+   D e s t r o y P i x e l C a c h e N e x u s                               %
1536%                                                                             %
1537%                                                                             %
1538%                                                                             %
1539%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1540%
1541%  DestroyPixelCacheNexus() destroys a pixel cache nexus.
1542%
1543%  The format of the DestroyPixelCacheNexus() method is:
1544%
1545%      NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
1546%        const size_t number_threads)
1547%
1548%  A description of each parameter follows:
1549%
1550%    o nexus_info: the nexus to destroy.
1551%
1552%    o number_threads: the number of nexus threads.
1553%
1554*/
1555
1556static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1557{
1558  if (nexus_info->mapped == MagickFalse)
1559    (void) RelinquishMagickMemory(nexus_info->cache);
1560  else
1561    (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1562  nexus_info->cache=(PixelPacket *) NULL;
1563  nexus_info->pixels=(PixelPacket *) NULL;
1564  nexus_info->indexes=(IndexPacket *) NULL;
1565  nexus_info->length=0;
1566  nexus_info->mapped=MagickFalse;
1567}
1568
1569MagickExport NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
1570  const size_t number_threads)
1571{
1572  register ssize_t
1573    i;
1574
1575  assert(nexus_info != (NexusInfo **) NULL);
1576  for (i=0; i < (ssize_t) number_threads; i++)
1577  {
1578    if (nexus_info[i]->cache != (PixelPacket *) NULL)
1579      RelinquishCacheNexusPixels(nexus_info[i]);
1580    nexus_info[i]->signature=(~MagickSignature);
1581    nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
1582  }
1583  nexus_info=(NexusInfo **) RelinquishMagickMemory(nexus_info);
1584  return(nexus_info);
1585}
1586
1587/*
1588%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1589%                                                                             %
1590%                                                                             %
1591%                                                                             %
1592+   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                   %
1593%                                                                             %
1594%                                                                             %
1595%                                                                             %
1596%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1597%
1598%  GetAuthenticIndexesFromCache() returns the indexes associated with the last
1599%  call to QueueAuthenticPixelsCache() or GetAuthenticPixelsCache().
1600%
1601%  The format of the GetAuthenticIndexesFromCache() method is:
1602%
1603%      IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1604%
1605%  A description of each parameter follows:
1606%
1607%    o image: the image.
1608%
1609*/
1610static IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1611{
1612  CacheInfo
1613    *cache_info;
1614
1615  const int
1616    id = GetOpenMPThreadId();
1617
1618  assert(image != (const Image *) NULL);
1619  assert(image->signature == MagickSignature);
1620  assert(image->cache != (Cache) NULL);
1621  cache_info=(CacheInfo *) image->cache;
1622  assert(cache_info->signature == MagickSignature);
1623  assert(id < (int) cache_info->number_threads);
1624  return(GetPixelCacheNexusIndexes(image->cache,cache_info->nexus_info[id]));
1625}
1626
1627/*
1628%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1629%                                                                             %
1630%                                                                             %
1631%                                                                             %
1632%   G e t A u t h e n t i c I n d e x Q u e u e                               %
1633%                                                                             %
1634%                                                                             %
1635%                                                                             %
1636%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1637%
1638%  GetAuthenticIndexQueue() returns the authentic black channel or the colormap
1639%  indexes associated with the last call to QueueAuthenticPixels() or
1640%  GetVirtualPixels().  NULL is returned if the black channel or colormap
1641%  indexes are not available.
1642%
1643%  The format of the GetAuthenticIndexQueue() method is:
1644%
1645%      IndexPacket *GetAuthenticIndexQueue(const Image *image)
1646%
1647%  A description of each parameter follows:
1648%
1649%    o image: the image.
1650%
1651*/
1652MagickExport IndexPacket *GetAuthenticIndexQueue(const Image *image)
1653{
1654  CacheInfo
1655    *cache_info;
1656
1657  const int
1658    id = GetOpenMPThreadId();
1659
1660  assert(image != (const Image *) NULL);
1661  assert(image->signature == MagickSignature);
1662  assert(image->cache != (Cache) NULL);
1663  cache_info=(CacheInfo *) image->cache;
1664  assert(cache_info->signature == MagickSignature);
1665  if (cache_info->methods.get_authentic_indexes_from_handler !=
1666       (GetAuthenticIndexesFromHandler) NULL)
1667    return(cache_info->methods.get_authentic_indexes_from_handler(image));
1668  assert(id < (int) cache_info->number_threads);
1669  return(GetPixelCacheNexusIndexes(cache_info,cache_info->nexus_info[id]));
1670}
1671
1672/*
1673%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1674%                                                                             %
1675%                                                                             %
1676%                                                                             %
1677+   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                     %
1678%                                                                             %
1679%                                                                             %
1680%                                                                             %
1681%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1682%
1683%  GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1684%  disk pixel cache as defined by the geometry parameters.   A pointer to the
1685%  pixels is returned if the pixels are transferred, otherwise a NULL is
1686%  returned.
1687%
1688%  The format of the GetAuthenticPixelCacheNexus() method is:
1689%
1690%      PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1691%        const ssize_t y,const size_t columns,const size_t rows,
1692%        NexusInfo *nexus_info,ExceptionInfo *exception)
1693%
1694%  A description of each parameter follows:
1695%
1696%    o image: the image.
1697%
1698%    o x,y,columns,rows:  These values define the perimeter of a region of
1699%      pixels.
1700%
1701%    o nexus_info: the cache nexus to return.
1702%
1703%    o exception: return any errors or warnings in this structure.
1704%
1705*/
1706
1707static inline MagickBooleanType IsNexusInCore(const CacheInfo *cache_info,
1708  NexusInfo *nexus_info)
1709{
1710  MagickOffsetType
1711    offset;
1712
1713  if (cache_info->type == PingCache)
1714    return(MagickTrue);
1715  offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1716    nexus_info->region.x;
1717  return(nexus_info->pixels == (cache_info->pixels+offset) ? MagickTrue :
1718    MagickFalse);
1719}
1720
1721MagickExport PixelPacket *GetAuthenticPixelCacheNexus(Image *image,
1722  const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
1723  NexusInfo *nexus_info,ExceptionInfo *exception)
1724{
1725  CacheInfo
1726    *cache_info;
1727
1728  PixelPacket
1729    *pixels;
1730
1731  /*
1732    Transfer pixels from the cache.
1733  */
1734  assert(image != (Image *) NULL);
1735  assert(image->signature == MagickSignature);
1736  pixels=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
1737  if (pixels == (PixelPacket *) NULL)
1738    return((PixelPacket *) NULL);
1739  cache_info=(CacheInfo *) image->cache;
1740  assert(cache_info->signature == MagickSignature);
1741  if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
1742    return(pixels);
1743  if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1744    return((PixelPacket *) NULL);
1745  if (cache_info->active_index_channel != MagickFalse)
1746    if (ReadPixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse)
1747      return((PixelPacket *) NULL);
1748  return(pixels);
1749}
1750
1751/*
1752%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1753%                                                                             %
1754%                                                                             %
1755%                                                                             %
1756+   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                     %
1757%                                                                             %
1758%                                                                             %
1759%                                                                             %
1760%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1761%
1762%  GetAuthenticPixelsFromCache() returns the pixels associated with the last
1763%  call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1764%
1765%  The format of the GetAuthenticPixelsFromCache() method is:
1766%
1767%      PixelPacket *GetAuthenticPixelsFromCache(const Image image)
1768%
1769%  A description of each parameter follows:
1770%
1771%    o image: the image.
1772%
1773*/
1774static PixelPacket *GetAuthenticPixelsFromCache(const Image *image)
1775{
1776  CacheInfo
1777    *cache_info;
1778
1779  const int
1780    id = GetOpenMPThreadId();
1781
1782  assert(image != (const Image *) NULL);
1783  assert(image->signature == MagickSignature);
1784  assert(image->cache != (Cache) NULL);
1785  cache_info=(CacheInfo *) image->cache;
1786  assert(cache_info->signature == MagickSignature);
1787  assert(id < (int) cache_info->number_threads);
1788  return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
1789}
1790
1791/*
1792%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1793%                                                                             %
1794%                                                                             %
1795%                                                                             %
1796%   G e t A u t h e n t i c P i x e l Q u e u e                               %
1797%                                                                             %
1798%                                                                             %
1799%                                                                             %
1800%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1801%
1802%  GetAuthenticPixelQueue() returns the authentic pixels associated with the
1803%  last call to QueueAuthenticPixels() or GetAuthenticPixels().
1804%
1805%  The format of the GetAuthenticPixelQueue() method is:
1806%
1807%      PixelPacket *GetAuthenticPixelQueue(const Image image)
1808%
1809%  A description of each parameter follows:
1810%
1811%    o image: the image.
1812%
1813*/
1814MagickExport PixelPacket *GetAuthenticPixelQueue(const Image *image)
1815{
1816  CacheInfo
1817    *cache_info;
1818
1819  const int
1820    id = GetOpenMPThreadId();
1821
1822  assert(image != (const Image *) NULL);
1823  assert(image->signature == MagickSignature);
1824  assert(image->cache != (Cache) NULL);
1825  cache_info=(CacheInfo *) image->cache;
1826  assert(cache_info->signature == MagickSignature);
1827  if (cache_info->methods.get_authentic_pixels_from_handler !=
1828       (GetAuthenticPixelsFromHandler) NULL)
1829    return(cache_info->methods.get_authentic_pixels_from_handler(image));
1830  assert(id < (int) cache_info->number_threads);
1831  return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
1832}
1833
1834/*
1835%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1836%                                                                             %
1837%                                                                             %
1838%                                                                             %
1839%   G e t A u t h e n t i c P i x e l s                                       %
1840%                                                                             %
1841%                                                                             %
1842%                                                                             %
1843%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1844%
1845%  GetAuthenticPixels() obtains a pixel region for read/write access. If the
1846%  region is successfully accessed, a pointer to a PixelPacket array
1847%  representing the region is returned, otherwise NULL is returned.
1848%
1849%  The returned pointer may point to a temporary working copy of the pixels
1850%  or it may point to the original pixels in memory. Performance is maximized
1851%  if the selected region is part of one row, or one or more full rows, since
1852%  then there is opportunity to access the pixels in-place (without a copy)
1853%  if the image is in memory, or in a memory-mapped file. The returned pointer
1854%  must *never* be deallocated by the user.
1855%
1856%  Pixels accessed via the returned pointer represent a simple array of type
1857%  PixelPacket. If the image type is CMYK or if the storage class is
1858%  PseduoClass, call GetAuthenticIndexQueue() after invoking
1859%  GetAuthenticPixels() to obtain the black color component or colormap indexes
1860%  (of type IndexPacket) corresponding to the region.  Once the PixelPacket
1861%  (and/or IndexPacket) array has been updated, the changes must be saved back
1862%  to the underlying image using SyncAuthenticPixels() or they may be lost.
1863%
1864%  The format of the GetAuthenticPixels() method is:
1865%
1866%      PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1867%        const ssize_t y,const size_t columns,const size_t rows,
1868%        ExceptionInfo *exception)
1869%
1870%  A description of each parameter follows:
1871%
1872%    o image: the image.
1873%
1874%    o x,y,columns,rows:  These values define the perimeter of a region of
1875%      pixels.
1876%
1877%    o exception: return any errors or warnings in this structure.
1878%
1879*/
1880MagickExport PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1881  const ssize_t y,const size_t columns,const size_t rows,
1882  ExceptionInfo *exception)
1883{
1884  CacheInfo
1885    *cache_info;
1886
1887  const int
1888    id = GetOpenMPThreadId();
1889
1890  assert(image != (Image *) NULL);
1891  assert(image->signature == MagickSignature);
1892  assert(image->cache != (Cache) NULL);
1893  cache_info=(CacheInfo *) image->cache;
1894  assert(cache_info->signature == MagickSignature);
1895  if (cache_info->methods.get_authentic_pixels_handler !=
1896       (GetAuthenticPixelsHandler) NULL)
1897    return(cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1898      rows,exception));
1899  assert(id < (int) cache_info->number_threads);
1900  return(GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1901    cache_info->nexus_info[id],exception));
1902}
1903
1904/*
1905%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1906%                                                                             %
1907%                                                                             %
1908%                                                                             %
1909+   G e t A u t h e n t i c P i x e l s C a c h e                             %
1910%                                                                             %
1911%                                                                             %
1912%                                                                             %
1913%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1914%
1915%  GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1916%  as defined by the geometry parameters.   A pointer to the pixels is returned
1917%  if the pixels are transferred, otherwise a NULL is returned.
1918%
1919%  The format of the GetAuthenticPixelsCache() method is:
1920%
1921%      PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1922%        const ssize_t y,const size_t columns,const size_t rows,
1923%        ExceptionInfo *exception)
1924%
1925%  A description of each parameter follows:
1926%
1927%    o image: the image.
1928%
1929%    o x,y,columns,rows:  These values define the perimeter of a region of
1930%      pixels.
1931%
1932%    o exception: return any errors or warnings in this structure.
1933%
1934*/
1935static PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1936  const ssize_t y,const size_t columns,const size_t rows,
1937  ExceptionInfo *exception)
1938{
1939  CacheInfo
1940    *cache_info;
1941
1942  const int
1943    id = GetOpenMPThreadId();
1944
1945  assert(image != (const Image *) NULL);
1946  assert(image->signature == MagickSignature);
1947  assert(image->cache != (Cache) NULL);
1948  cache_info=(CacheInfo *) image->cache;
1949  if (cache_info == (Cache) NULL)
1950    return((PixelPacket *) NULL);
1951  assert(cache_info->signature == MagickSignature);
1952  assert(id < (int) cache_info->number_threads);
1953  return(GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1954    cache_info->nexus_info[id],exception));
1955}
1956
1957/*
1958%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1959%                                                                             %
1960%                                                                             %
1961%                                                                             %
1962+   G e t I m a g e E x t e n t                                               %
1963%                                                                             %
1964%                                                                             %
1965%                                                                             %
1966%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1967%
1968%  GetImageExtent() returns the extent of the pixels associated with the
1969%  last call to QueueAuthenticPixels() or GetAuthenticPixels().
1970%
1971%  The format of the GetImageExtent() method is:
1972%
1973%      MagickSizeType GetImageExtent(const Image *image)
1974%
1975%  A description of each parameter follows:
1976%
1977%    o image: the image.
1978%
1979*/
1980MagickExport MagickSizeType GetImageExtent(const Image *image)
1981{
1982  CacheInfo
1983    *cache_info;
1984
1985  const int
1986    id = GetOpenMPThreadId();
1987
1988  assert(image != (Image *) NULL);
1989  assert(image->signature == MagickSignature);
1990  if (image->debug != MagickFalse)
1991    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1992  assert(image->cache != (Cache) NULL);
1993  cache_info=(CacheInfo *) image->cache;
1994  assert(cache_info->signature == MagickSignature);
1995  assert(id < (int) cache_info->number_threads);
1996  return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1997}
1998
1999/*
2000%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2001%                                                                             %
2002%                                                                             %
2003%                                                                             %
2004+   G e t I m a g e P i x e l C a c h e                                       %
2005%                                                                             %
2006%                                                                             %
2007%                                                                             %
2008%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2009%
2010%  GetImagePixelCache() ensures that there is only a single reference to the
2011%  pixel cache to be modified, updating the provided cache pointer to point to
2012%  a clone of the original pixel cache if necessary.
2013%
2014%  The format of the GetImagePixelCache method is:
2015%
2016%      Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2017%        ExceptionInfo *exception)
2018%
2019%  A description of each parameter follows:
2020%
2021%    o image: the image.
2022%
2023%    o clone: any value other than MagickFalse clones the cache pixels.
2024%
2025%    o exception: return any errors or warnings in this structure.
2026%
2027*/
2028static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
2029{
2030  CacheInfo
2031    *cache_info;
2032
2033  /*
2034    Does the image match the pixel cache morphology?
2035  */
2036  cache_info=(CacheInfo *) image->cache;
2037  if ((image->storage_class != cache_info->storage_class) ||
2038      (image->colorspace != cache_info->colorspace) ||
2039      (image->channels != cache_info->channels) ||
2040      (image->columns != cache_info->columns) ||
2041      (image->rows != cache_info->rows) ||
2042      (cache_info->nexus_info == (NexusInfo **) NULL) ||
2043      (cache_info->number_threads < GetOpenMPMaximumThreads()))
2044    return(MagickFalse);
2045  return(MagickTrue);
2046}
2047
2048static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2049  ExceptionInfo *exception)
2050{
2051  CacheInfo
2052    *cache_info;
2053
2054  MagickBooleanType
2055    destroy,
2056    status;
2057
2058  static MagickSizeType
2059    cpu_throttle = 0,
2060    cycles = 0,
2061    time_limit = 0;
2062
2063  static time_t
2064    cache_genesis = 0;
2065
2066  status=MagickTrue;
2067  LockSemaphoreInfo(image->semaphore);
2068  if (cpu_throttle == 0)
2069    {
2070      char
2071        *limit;
2072
2073      /*
2074        Set CPU throttle in milleseconds.
2075      */
2076      cpu_throttle=MagickResourceInfinity;
2077      limit=GetEnvironmentValue("MAGICK_THROTTLE");
2078      if (limit == (char *) NULL)
2079        limit=GetPolicyValue("throttle");
2080      if (limit != (char *) NULL)
2081        {
2082          cpu_throttle=(MagickSizeType) StringToInteger(limit);
2083          limit=DestroyString(limit);
2084        }
2085    }
2086  if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2087    MagickDelay(cpu_throttle);
2088  if (time_limit == 0)
2089    {
2090      /*
2091        Set the exire time in seconds.
2092      */
2093      time_limit=GetMagickResourceLimit(TimeResource);
2094      cache_genesis=time((time_t *) NULL);
2095    }
2096  if ((time_limit != MagickResourceInfinity) &&
2097      ((MagickSizeType) (time((time_t *) NULL)-cache_genesis) >= time_limit))
2098    ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
2099  assert(image->cache != (Cache) NULL);
2100  cache_info=(CacheInfo *) image->cache;
2101  destroy=MagickFalse;
2102  if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
2103    {
2104      LockSemaphoreInfo(cache_info->semaphore);
2105      if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
2106        {
2107          Image
2108            clone_image;
2109
2110          CacheInfo
2111            *clone_info;
2112
2113          /*
2114            Clone pixel cache.
2115          */
2116          clone_image=(*image);
2117          clone_image.semaphore=AllocateSemaphoreInfo();
2118          clone_image.reference_count=1;
2119          clone_image.cache=ClonePixelCache(cache_info);
2120          clone_info=(CacheInfo *) clone_image.cache;
2121          status=OpenPixelCache(&clone_image,IOMode,exception);
2122          if (status != MagickFalse)
2123            {
2124              if (clone != MagickFalse)
2125                status=ClonePixelCachePixels(clone_info,cache_info,exception);
2126              if (status != MagickFalse)
2127                {
2128                  destroy=MagickTrue;
2129                  image->cache=clone_image.cache;
2130                }
2131            }
2132          DestroySemaphoreInfo(&clone_image.semaphore);
2133        }
2134      UnlockSemaphoreInfo(cache_info->semaphore);
2135    }
2136  if (destroy != MagickFalse)
2137    cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
2138  if (status != MagickFalse)
2139    {
2140      /*
2141        Ensure the image matches the pixel cache morphology.
2142      */
2143      image->taint=MagickTrue;
2144      image->type=UndefinedType;
2145      if (image->colorspace == GRAYColorspace)
2146        image->colorspace=RGBColorspace;
2147      if (ValidatePixelCacheMorphology(image) == MagickFalse)
2148        status=OpenPixelCache(image,IOMode,exception);
2149    }
2150  UnlockSemaphoreInfo(image->semaphore);
2151  if (status == MagickFalse)
2152    return((Cache) NULL);
2153  return(image->cache);
2154}
2155
2156/*
2157%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2158%                                                                             %
2159%                                                                             %
2160%                                                                             %
2161%   G e t O n e A u t h e n t i c P i x e l                                   %
2162%                                                                             %
2163%                                                                             %
2164%                                                                             %
2165%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2166%
2167%  GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2168%  location.  The image background color is returned if an error occurs.
2169%
2170%  The format of the GetOneAuthenticPixel() method is:
2171%
2172%      MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2173%        const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
2174%
2175%  A description of each parameter follows:
2176%
2177%    o image: the image.
2178%
2179%    o x,y:  These values define the location of the pixel to return.
2180%
2181%    o pixel: return a pixel at the specified (x,y) location.
2182%
2183%    o exception: return any errors or warnings in this structure.
2184%
2185*/
2186MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2187  const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
2188{
2189  CacheInfo
2190    *cache_info;
2191
2192  PixelPacket
2193    *pixels;
2194
2195  assert(image != (Image *) NULL);
2196  assert(image->signature == MagickSignature);
2197  assert(image->cache != (Cache) NULL);
2198  cache_info=(CacheInfo *) image->cache;
2199  assert(cache_info->signature == MagickSignature);
2200  *pixel=image->background_color;
2201  if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2202       (GetOneAuthenticPixelFromHandler) NULL)
2203    return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2204      pixel,exception));
2205  pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2206  if (pixels == (PixelPacket *) NULL)
2207    return(MagickFalse);
2208  *pixel=(*pixels);
2209  return(MagickTrue);
2210}
2211
2212/*
2213%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2214%                                                                             %
2215%                                                                             %
2216%                                                                             %
2217+   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                 %
2218%                                                                             %
2219%                                                                             %
2220%                                                                             %
2221%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2222%
2223%  GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2224%  location.  The image background color is returned if an error occurs.
2225%
2226%  The format of the GetOneAuthenticPixelFromCache() method is:
2227%
2228%      MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
2229%        const ssize_t x,const ssize_t y,PixelPacket *pixel,
2230%        ExceptionInfo *exception)
2231%
2232%  A description of each parameter follows:
2233%
2234%    o image: the image.
2235%
2236%    o x,y:  These values define the location of the pixel to return.
2237%
2238%    o pixel: return a pixel at the specified (x,y) location.
2239%
2240%    o exception: return any errors or warnings in this structure.
2241%
2242*/
2243static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
2244  const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
2245{
2246  CacheInfo
2247    *cache_info;
2248
2249  const int
2250    id = GetOpenMPThreadId();
2251
2252  PixelPacket
2253    *pixels;
2254
2255  assert(image != (const Image *) NULL);
2256  assert(image->signature == MagickSignature);
2257  assert(image->cache != (Cache) NULL);
2258  cache_info=(CacheInfo *) image->cache;
2259  assert(cache_info->signature == MagickSignature);
2260  *pixel=image->background_color;
2261  assert(id < (int) cache_info->number_threads);
2262  pixels=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,
2263    cache_info->nexus_info[id],exception);
2264  if (pixels == (PixelPacket *) NULL)
2265    return(MagickFalse);
2266  *pixel=(*pixels);
2267  return(MagickTrue);
2268}
2269
2270/*
2271%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2272%                                                                             %
2273%                                                                             %
2274%                                                                             %
2275%   G e t O n e V i r t u a l M a g i c k P i x e l                           %
2276%                                                                             %
2277%                                                                             %
2278%                                                                             %
2279%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2280%
2281%  GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2282%  location.  The image background color is returned if an error occurs.  If
2283%  you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2284%
2285%  The format of the GetOneVirtualMagickPixel() method is:
2286%
2287%      MagickBooleanType GetOneVirtualMagickPixel(const Image image,
2288%        const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
2289%        ExceptionInfo exception)
2290%
2291%  A description of each parameter follows:
2292%
2293%    o image: the image.
2294%
2295%    o x,y:  these values define the location of the pixel to return.
2296%
2297%    o pixel: return a pixel at the specified (x,y) location.
2298%
2299%    o exception: return any errors or warnings in this structure.
2300%
2301*/
2302MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
2303  const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
2304  ExceptionInfo *exception)
2305{
2306  CacheInfo
2307    *cache_info;
2308
2309  const int
2310    id = GetOpenMPThreadId();
2311
2312  register const IndexPacket
2313    *indexes;
2314
2315  register const PixelPacket
2316    *pixels;
2317
2318  assert(image != (const Image *) NULL);
2319  assert(image->signature == MagickSignature);
2320  assert(image->cache != (Cache) NULL);
2321  cache_info=(CacheInfo *) image->cache;
2322  assert(cache_info->signature == MagickSignature);
2323  assert(id < (int) cache_info->number_threads);
2324  pixels=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2325    1UL,1UL,cache_info->nexus_info[id],exception);
2326  GetMagickPixelPacket(image,pixel);
2327  if (pixels == (const PixelPacket *) NULL)
2328    return(MagickFalse);
2329  indexes=GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]);
2330  SetMagickPixelPacket(image,pixels,indexes,pixel);
2331  return(MagickTrue);
2332}
2333
2334/*
2335%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2336%                                                                             %
2337%                                                                             %
2338%                                                                             %
2339%   G e t O n e V i r t u a l M e t h o d P i x e l                           %
2340%                                                                             %
2341%                                                                             %
2342%                                                                             %
2343%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2344%
2345%  GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2346%  location as defined by specified pixel method.  The image background color
2347%  is returned if an error occurs.  If you plan to modify the pixel, use
2348%  GetOneAuthenticPixel() instead.
2349%
2350%  The format of the GetOneVirtualMethodPixel() method is:
2351%
2352%      MagickBooleanType GetOneVirtualMethodPixel(const Image image,
2353%        const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2354%        const ssize_t y,Pixelpacket *pixel,ExceptionInfo exception)
2355%
2356%  A description of each parameter follows:
2357%
2358%    o image: the image.
2359%
2360%    o virtual_pixel_method: the virtual pixel method.
2361%
2362%    o x,y:  These values define the location of the pixel to return.
2363%
2364%    o pixel: return a pixel at the specified (x,y) location.
2365%
2366%    o exception: return any errors or warnings in this structure.
2367%
2368*/
2369MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
2370  const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2371  PixelPacket *pixel,ExceptionInfo *exception)
2372{
2373  CacheInfo
2374    *cache_info;
2375
2376  const int
2377    id = GetOpenMPThreadId();
2378
2379  const PixelPacket
2380    *pixels;
2381
2382  assert(image != (const Image *) NULL);
2383  assert(image->signature == MagickSignature);
2384  assert(image->cache != (Cache) NULL);
2385  cache_info=(CacheInfo *) image->cache;
2386  assert(cache_info->signature == MagickSignature);
2387  *pixel=image->background_color;
2388  if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2389       (GetOneVirtualPixelFromHandler) NULL)
2390    return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2391      virtual_pixel_method,x,y,pixel,exception));
2392  assert(id < (int) cache_info->number_threads);
2393  pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2394    cache_info->nexus_info[id],exception);
2395  if (pixels == (const PixelPacket *) NULL)
2396    return(MagickFalse);
2397  *pixel=(*pixels);
2398  return(MagickTrue);
2399}
2400
2401/*
2402%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2403%                                                                             %
2404%                                                                             %
2405%                                                                             %
2406%   G e t O n e V i r t u a l P i x e l                                       %
2407%                                                                             %
2408%                                                                             %
2409%                                                                             %
2410%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2411%
2412%  GetOneVirtualPixel() returns a single virtual pixel at the specified
2413%  (x,y) location.  The image background color is returned if an error occurs.
2414%  If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2415%
2416%  The format of the GetOneVirtualPixel() method is:
2417%
2418%      MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2419%        const ssize_t y,PixelPacket *pixel,ExceptionInfo exception)
2420%
2421%  A description of each parameter follows:
2422%
2423%    o image: the image.
2424%
2425%    o x,y:  These values define the location of the pixel to return.
2426%
2427%    o pixel: return a pixel at the specified (x,y) location.
2428%
2429%    o exception: return any errors or warnings in this structure.
2430%
2431*/
2432MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
2433  const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
2434{
2435  CacheInfo
2436    *cache_info;
2437
2438  const int
2439    id = GetOpenMPThreadId();
2440
2441  const PixelPacket
2442    *pixels;
2443
2444  assert(image != (const Image *) NULL);
2445  assert(image->signature == MagickSignature);
2446  assert(image->cache != (Cache) NULL);
2447  cache_info=(CacheInfo *) image->cache;
2448  assert(cache_info->signature == MagickSignature);
2449  *pixel=image->background_color;
2450  if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2451       (GetOneVirtualPixelFromHandler) NULL)
2452    return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2453      GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
2454  assert(id < (int) cache_info->number_threads);
2455  pixels=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2456    1UL,1UL,cache_info->nexus_info[id],exception);
2457  if (pixels == (const PixelPacket *) NULL)
2458    return(MagickFalse);
2459  *pixel=(*pixels);
2460  return(MagickTrue);
2461}
2462
2463/*
2464%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2465%                                                                             %
2466%                                                                             %
2467%                                                                             %
2468+   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                     %
2469%                                                                             %
2470%                                                                             %
2471%                                                                             %
2472%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2473%
2474%  GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2475%  specified (x,y) location.  The image background color is returned if an
2476%  error occurs.
2477%
2478%  The format of the GetOneVirtualPixelFromCache() method is:
2479%
2480%      MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
2481%        const VirtualPixelPacket method,const ssize_t x,const ssize_t y,
2482%        PixelPacket *pixel,ExceptionInfo *exception)
2483%
2484%  A description of each parameter follows:
2485%
2486%    o image: the image.
2487%
2488%    o virtual_pixel_method: the virtual pixel method.
2489%
2490%    o x,y:  These values define the location of the pixel to return.
2491%
2492%    o pixel: return a pixel at the specified (x,y) location.
2493%
2494%    o exception: return any errors or warnings in this structure.
2495%
2496*/
2497static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
2498  const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2499  PixelPacket *pixel,ExceptionInfo *exception)
2500{
2501  CacheInfo
2502    *cache_info;
2503
2504  const int
2505    id = GetOpenMPThreadId();
2506
2507  const PixelPacket
2508    *pixels;
2509
2510  assert(image != (const Image *) NULL);
2511  assert(image->signature == MagickSignature);
2512  assert(image->cache != (Cache) NULL);
2513  cache_info=(CacheInfo *) image->cache;
2514  assert(cache_info->signature == MagickSignature);
2515  assert(id < (int) cache_info->number_threads);
2516  *pixel=image->background_color;
2517  pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2518    cache_info->nexus_info[id],exception);
2519  if (pixels == (const PixelPacket *) NULL)
2520    return(MagickFalse);
2521  *pixel=(*pixels);
2522  return(MagickTrue);
2523}
2524
2525/*
2526%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2527%                                                                             %
2528%                                                                             %
2529%                                                                             %
2530+   G e t P i x e l C a c h e C h a n n e l s                                 %
2531%                                                                             %
2532%                                                                             %
2533%                                                                             %
2534%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2535%
2536%  GetPixelCacheChannels() returns the number of pixel channels associated
2537%  with this instance of the pixel cache.
2538%
2539%  The format of the GetPixelCacheChannels() method is:
2540%
2541%      size_t GetPixelCacheChannels(Cache cache)
2542%
2543%  A description of each parameter follows:
2544%
2545%    o type: GetPixelCacheChannels returns DirectClass or PseudoClass.
2546%
2547%    o cache: the pixel cache.
2548%
2549*/
2550MagickExport size_t GetPixelCacheChannels(const Cache cache)
2551{
2552  CacheInfo
2553    *cache_info;
2554
2555  assert(cache != (Cache) NULL);
2556  cache_info=(CacheInfo *) cache;
2557  assert(cache_info->signature == MagickSignature);
2558  if (cache_info->debug != MagickFalse)
2559    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2560      cache_info->filename);
2561  return(cache_info->channels);
2562}
2563
2564/*
2565%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2566%                                                                             %
2567%                                                                             %
2568%                                                                             %
2569+   G e t P i x e l C a c h e C o l o r s p a c e                             %
2570%                                                                             %
2571%                                                                             %
2572%                                                                             %
2573%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2574%
2575%  GetPixelCacheColorspace() returns the class type of the pixel cache.
2576%
2577%  The format of the GetPixelCacheColorspace() method is:
2578%
2579%      Colorspace GetPixelCacheColorspace(Cache cache)
2580%
2581%  A description of each parameter follows:
2582%
2583%    o cache: the pixel cache.
2584%
2585*/
2586MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
2587{
2588  CacheInfo
2589    *cache_info;
2590
2591  assert(cache != (Cache) NULL);
2592  cache_info=(CacheInfo *) cache;
2593  assert(cache_info->signature == MagickSignature);
2594  if (cache_info->debug != MagickFalse)
2595    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2596      cache_info->filename);
2597  return(cache_info->colorspace);
2598}
2599
2600/*
2601%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2602%                                                                             %
2603%                                                                             %
2604%                                                                             %
2605+   G e t P i x e l C a c h e M e t h o d s                                   %
2606%                                                                             %
2607%                                                                             %
2608%                                                                             %
2609%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2610%
2611%  GetPixelCacheMethods() initializes the CacheMethods structure.
2612%
2613%  The format of the GetPixelCacheMethods() method is:
2614%
2615%      void GetPixelCacheMethods(CacheMethods *cache_methods)
2616%
2617%  A description of each parameter follows:
2618%
2619%    o cache_methods: Specifies a pointer to a CacheMethods structure.
2620%
2621*/
2622MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
2623{
2624  assert(cache_methods != (CacheMethods *) NULL);
2625  (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2626  cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2627  cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2628  cache_methods->get_virtual_indexes_from_handler=GetVirtualIndexesFromCache;
2629  cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2630  cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2631  cache_methods->get_authentic_indexes_from_handler=
2632    GetAuthenticIndexesFromCache;
2633  cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2634  cache_methods->get_one_authentic_pixel_from_handler=
2635    GetOneAuthenticPixelFromCache;
2636  cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2637  cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2638  cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2639}
2640
2641/*
2642%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2643%                                                                             %
2644%                                                                             %
2645%                                                                             %
2646+   G e t P i x e l C a c h e N e x u s E x t e n t                           %
2647%                                                                             %
2648%                                                                             %
2649%                                                                             %
2650%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2651%
2652%  GetPixelCacheNexusExtent() returns the extent of the pixels associated with
2653%  the last call to SetPixelCacheNexusPixels() or GetPixelCacheNexusPixels().
2654%
2655%  The format of the GetPixelCacheNexusExtent() method is:
2656%
2657%      MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2658%        NexusInfo *nexus_info)
2659%
2660%  A description of each parameter follows:
2661%
2662%    o nexus_info: the nexus info.
2663%
2664*/
2665MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2666  NexusInfo *nexus_info)
2667{
2668  CacheInfo
2669    *cache_info;
2670
2671  MagickSizeType
2672    extent;
2673
2674  assert(cache != (const Cache) NULL);
2675  cache_info=(CacheInfo *) cache;
2676  assert(cache_info->signature == MagickSignature);
2677  extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2678  if (extent == 0)
2679    return((MagickSizeType) cache_info->columns*cache_info->rows);
2680  return(extent);
2681}
2682
2683/*
2684%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2685%                                                                             %
2686%                                                                             %
2687%                                                                             %
2688+   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                         %
2689%                                                                             %
2690%                                                                             %
2691%                                                                             %
2692%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2693%
2694%  GetPixelCacheNexusIndexes() returns the indexes associated with the
2695%  specified cache nexus.
2696%
2697%  The format of the GetPixelCacheNexusIndexes() method is:
2698%
2699%      IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2700%        NexusInfo *nexus_info)
2701%
2702%  A description of each parameter follows:
2703%
2704%    o cache: the pixel cache.
2705%
2706%    o nexus_info: the cache nexus to return the colormap indexes.
2707%
2708*/
2709MagickExport IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2710  NexusInfo *nexus_info)
2711{
2712  CacheInfo
2713    *cache_info;
2714
2715  assert(cache != (const Cache) NULL);
2716  cache_info=(CacheInfo *) cache;
2717  assert(cache_info->signature == MagickSignature);
2718  if (cache_info->storage_class == UndefinedClass)
2719    return((IndexPacket *) NULL);
2720  return(nexus_info->indexes);
2721}
2722
2723/*
2724%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2725%                                                                             %
2726%                                                                             %
2727%                                                                             %
2728+   G e t P i x e l C a c h e N e x u s P i x e l s                           %
2729%                                                                             %
2730%                                                                             %
2731%                                                                             %
2732%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2733%
2734%  GetPixelCacheNexusPixels() returns the pixels associated with the specified
2735%  cache nexus.
2736%
2737%  The format of the GetPixelCacheNexusPixels() method is:
2738%
2739%      PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2740%        NexusInfo *nexus_info)
2741%
2742%  A description of each parameter follows:
2743%
2744%    o cache: the pixel cache.
2745%
2746%    o nexus_info: the cache nexus to return the pixels.
2747%
2748*/
2749MagickExport PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2750  NexusInfo *nexus_info)
2751{
2752  CacheInfo
2753    *cache_info;
2754
2755  assert(cache != (const Cache) NULL);
2756  cache_info=(CacheInfo *) cache;
2757  assert(cache_info->signature == MagickSignature);
2758  if (cache_info->storage_class == UndefinedClass)
2759    return((PixelPacket *) NULL);
2760  return(nexus_info->pixels);
2761}
2762
2763/*
2764%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2765%                                                                             %
2766%                                                                             %
2767%                                                                             %
2768+   G e t P i x e l C a c h e P i x e l s                                     %
2769%                                                                             %
2770%                                                                             %
2771%                                                                             %
2772%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2773%
2774%  GetPixelCachePixels() returns the pixels associated with the specified image.
2775%
2776%  The format of the GetPixelCachePixels() method is:
2777%
2778%      void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2779%        ExceptionInfo *exception)
2780%
2781%  A description of each parameter follows:
2782%
2783%    o image: the image.
2784%
2785%    o length: the pixel cache length.
2786%
2787%    o exception: return any errors or warnings in this structure.
2788%
2789*/
2790MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2791  ExceptionInfo *exception)
2792{
2793  CacheInfo
2794    *cache_info;
2795
2796  assert(image != (const Image *) NULL);
2797  assert(image->signature == MagickSignature);
2798  assert(image->cache != (Cache) NULL);
2799  assert(length != (MagickSizeType *) NULL);
2800  assert(exception != (ExceptionInfo *) NULL);
2801  assert(exception->signature == MagickSignature);
2802  cache_info=(CacheInfo *) image->cache;
2803  assert(cache_info->signature == MagickSignature);
2804  *length=0;
2805  if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2806    return((void *) NULL);
2807  *length=cache_info->length;
2808  return((void *) cache_info->pixels);
2809}
2810
2811/*
2812%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2813%                                                                             %
2814%                                                                             %
2815%                                                                             %
2816+   G e t P i x e l C a c h e S t o r a g e C l a s s                         %
2817%                                                                             %
2818%                                                                             %
2819%                                                                             %
2820%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2821%
2822%  GetPixelCacheStorageClass() returns the class type of the pixel cache.
2823%
2824%  The format of the GetPixelCacheStorageClass() method is:
2825%
2826%      ClassType GetPixelCacheStorageClass(Cache cache)
2827%
2828%  A description of each parameter follows:
2829%
2830%    o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2831%
2832%    o cache: the pixel cache.
2833%
2834*/
2835MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
2836{
2837  CacheInfo
2838    *cache_info;
2839
2840  assert(cache != (Cache) NULL);
2841  cache_info=(CacheInfo *) cache;
2842  assert(cache_info->signature == MagickSignature);
2843  if (cache_info->debug != MagickFalse)
2844    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2845      cache_info->filename);
2846  return(cache_info->storage_class);
2847}
2848
2849/*
2850%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2851%                                                                             %
2852%                                                                             %
2853%                                                                             %
2854+   G e t P i x e l C a c h e T i l e S i z e                                 %
2855%                                                                             %
2856%                                                                             %
2857%                                                                             %
2858%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2859%
2860%  GetPixelCacheTileSize() returns the pixel cache tile size.
2861%
2862%  The format of the GetPixelCacheTileSize() method is:
2863%
2864%      void GetPixelCacheTileSize(const Image *image,size_t *width,
2865%        size_t *height)
2866%
2867%  A description of each parameter follows:
2868%
2869%    o image: the image.
2870%
2871%    o width: the optimize cache tile width in pixels.
2872%
2873%    o height: the optimize cache tile height in pixels.
2874%
2875*/
2876MagickExport void GetPixelCacheTileSize(const Image *image,size_t *width,
2877  size_t *height)
2878{
2879  assert(image != (Image *) NULL);
2880  assert(image->signature == MagickSignature);
2881  if (image->debug != MagickFalse)
2882    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2883  *width=2048UL/sizeof(PixelPacket);
2884  if (GetPixelCacheType(image) == DiskCache)
2885    *width=8192UL/sizeof(PixelPacket);
2886  *height=(*width);
2887}
2888
2889/*
2890%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2891%                                                                             %
2892%                                                                             %
2893%                                                                             %
2894+   G e t P i x e l C a c h e T y p e                                         %
2895%                                                                             %
2896%                                                                             %
2897%                                                                             %
2898%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2899%
2900%  GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2901%
2902%  The format of the GetPixelCacheType() method is:
2903%
2904%      CacheType GetPixelCacheType(const Image *image)
2905%
2906%  A description of each parameter follows:
2907%
2908%    o image: the image.
2909%
2910*/
2911MagickExport CacheType GetPixelCacheType(const Image *image)
2912{
2913  CacheInfo
2914    *cache_info;
2915
2916  assert(image != (Image *) NULL);
2917  assert(image->signature == MagickSignature);
2918  assert(image->cache != (Cache) NULL);
2919  cache_info=(CacheInfo *) image->cache;
2920  assert(cache_info->signature == MagickSignature);
2921  return(cache_info->type);
2922}
2923
2924/*
2925%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2926%                                                                             %
2927%                                                                             %
2928%                                                                             %
2929+   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                       %
2930%                                                                             %
2931%                                                                             %
2932%                                                                             %
2933%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2934%
2935%  GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2936%  pixel cache.  A virtual pixel is any pixel access that is outside the
2937%  boundaries of the image cache.
2938%
2939%  The format of the GetPixelCacheVirtualMethod() method is:
2940%
2941%      VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2942%
2943%  A description of each parameter follows:
2944%
2945%    o image: the image.
2946%
2947*/
2948MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2949{
2950  CacheInfo
2951    *cache_info;
2952
2953  assert(image != (Image *) NULL);
2954  assert(image->signature == MagickSignature);
2955  assert(image->cache != (Cache) NULL);
2956  cache_info=(CacheInfo *) image->cache;
2957  assert(cache_info->signature == MagickSignature);
2958  return(cache_info->virtual_pixel_method);
2959}
2960
2961/*
2962%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2963%                                                                             %
2964%                                                                             %
2965%                                                                             %
2966+   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                       %
2967%                                                                             %
2968%                                                                             %
2969%                                                                             %
2970%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2971%
2972%  GetVirtualIndexesFromCache() returns the indexes associated with the last
2973%  call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2974%
2975%  The format of the GetVirtualIndexesFromCache() method is:
2976%
2977%      IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2978%
2979%  A description of each parameter follows:
2980%
2981%    o image: the image.
2982%
2983*/
2984static const IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2985{
2986  CacheInfo
2987    *cache_info;
2988
2989  const int
2990    id = GetOpenMPThreadId();
2991
2992  assert(image != (const Image *) NULL);
2993  assert(image->signature == MagickSignature);
2994  assert(image->cache != (Cache) NULL);
2995  cache_info=(CacheInfo *) image->cache;
2996  assert(cache_info->signature == MagickSignature);
2997  assert(id < (int) cache_info->number_threads);
2998  return(GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]));
2999}
3000
3001/*
3002%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3003%                                                                             %
3004%                                                                             %
3005%                                                                             %
3006+   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                       %
3007%                                                                             %
3008%                                                                             %
3009%                                                                             %
3010%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3011%
3012%  GetVirtualIndexesFromNexus() returns the indexes associated with the
3013%  specified cache nexus.
3014%
3015%  The format of the GetVirtualIndexesFromNexus() method is:
3016%
3017%      const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
3018%        NexusInfo *nexus_info)
3019%
3020%  A description of each parameter follows:
3021%
3022%    o cache: the pixel cache.
3023%
3024%    o nexus_info: the cache nexus to return the colormap indexes.
3025%
3026*/
3027MagickExport const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
3028  NexusInfo *nexus_info)
3029{
3030  CacheInfo
3031    *cache_info;
3032
3033  assert(cache != (Cache) NULL);
3034  cache_info=(CacheInfo *) cache;
3035  assert(cache_info->signature == MagickSignature);
3036  if (cache_info->storage_class == UndefinedClass)
3037    return((IndexPacket *) NULL);
3038  return(nexus_info->indexes);
3039}
3040
3041/*
3042%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3043%                                                                             %
3044%                                                                             %
3045%                                                                             %
3046%   G e t V i r t u a l I n d e x Q u e u e                                   %
3047%                                                                             %
3048%                                                                             %
3049%                                                                             %
3050%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3051%
3052%  GetVirtualIndexQueue() returns the virtual black channel or the
3053%  colormap indexes associated with the last call to QueueAuthenticPixels() or
3054%  GetVirtualPixels().  NULL is returned if the black channel or colormap
3055%  indexes are not available.
3056%
3057%  The format of the GetVirtualIndexQueue() method is:
3058%
3059%      const IndexPacket *GetVirtualIndexQueue(const Image *image)
3060%
3061%  A description of each parameter follows:
3062%
3063%    o image: the image.
3064%
3065*/
3066MagickExport const IndexPacket *GetVirtualIndexQueue(const Image *image)
3067{
3068  CacheInfo
3069    *cache_info;
3070
3071  const int
3072    id = GetOpenMPThreadId();
3073
3074  assert(image != (const Image *) NULL);
3075  assert(image->signature == MagickSignature);
3076  assert(image->cache != (Cache) NULL);
3077  cache_info=(CacheInfo *) image->cache;
3078  assert(cache_info->signature == MagickSignature);
3079  if (cache_info->methods.get_virtual_indexes_from_handler !=
3080       (GetVirtualIndexesFromHandler) NULL)
3081    return(cache_info->methods.get_virtual_indexes_from_handler(image));
3082  assert(id < (int) cache_info->number_threads);
3083  return(GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]));
3084}
3085
3086/*
3087%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3088%                                                                             %
3089%                                                                             %
3090%                                                                             %
3091+   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                         %
3092%                                                                             %
3093%                                                                             %
3094%                                                                             %
3095%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3096%
3097%  GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3098%  pixel cache as defined by the geometry parameters.   A pointer to the pixels
3099%  is returned if the pixels are transferred, otherwise a NULL is returned.
3100%
3101%  The format of the GetVirtualPixelsFromNexus() method is:
3102%
3103%      PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
3104%        const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
3105%        const size_t columns,const size_t rows,NexusInfo *nexus_info,
3106%        ExceptionInfo *exception)
3107%
3108%  A description of each parameter follows:
3109%
3110%    o image: the image.
3111%
3112%    o virtual_pixel_method: the virtual pixel method.
3113%
3114%    o x,y,columns,rows:  These values define the perimeter of a region of
3115%      pixels.
3116%
3117%    o nexus_info: the cache nexus to acquire.
3118%
3119%    o exception: return any errors or warnings in this structure.
3120%
3121*/
3122
3123static ssize_t
3124  DitherMatrix[64] =
3125  {
3126     0,  48,  12,  60,   3,  51,  15,  63,
3127    32,  16,  44,  28,  35,  19,  47,  31,
3128     8,  56,   4,  52,  11,  59,   7,  55,
3129    40,  24,  36,  20,  43,  27,  39,  23,
3130     2,  50,  14,  62,   1,  49,  13,  61,
3131    34,  18,  46,  30,  33,  17,  45,  29,
3132    10,  58,   6,  54,   9,  57,   5,  53,
3133    42,  26,  38,  22,  41,  25,  37,  21
3134  };
3135
3136static inline ssize_t DitherX(const ssize_t x,const size_t columns)
3137{
3138  ssize_t
3139    index;
3140
3141  index=x+DitherMatrix[x & 0x07]-32L;
3142  if (index < 0L)
3143    return(0L);
3144  if (index >= (ssize_t) columns)
3145    return((ssize_t) columns-1L);
3146  return(index);
3147}
3148
3149static inline ssize_t DitherY(const ssize_t y,const size_t rows)
3150{
3151  ssize_t
3152    index;
3153
3154  index=y+DitherMatrix[y & 0x07]-32L;
3155  if (index < 0L)
3156    return(0L);
3157  if (index >= (ssize_t) rows)
3158    return((ssize_t) rows-1L);
3159  return(index);
3160}
3161
3162static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
3163{
3164  if (x < 0L)
3165    return(0L);
3166  if (x >= (ssize_t) columns)
3167    return((ssize_t) (columns-1));
3168  return(x);
3169}
3170
3171static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
3172{
3173  if (y < 0L)
3174    return(0L);
3175  if (y >= (ssize_t) rows)
3176    return((ssize_t) (rows-1));
3177  return(y);
3178}
3179
3180static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
3181{
3182  return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
3183}
3184
3185static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
3186{
3187  return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
3188}
3189
3190/*
3191  VirtualPixelModulo() computes the remainder of dividing offset by extent.  It
3192  returns not only the quotient (tile the offset falls in) but also the positive
3193  remainer within that tile such that 0 <= remainder < extent.  This method is
3194  essentially a ldiv() using a floored modulo division rather than the normal
3195  default truncated modulo division.
3196*/
3197static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3198  const size_t extent)
3199{
3200  MagickModulo
3201    modulo;
3202
3203  modulo.quotient=offset/(ssize_t) extent;
3204  if (offset < 0L)
3205    modulo.quotient--;
3206  modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
3207  return(modulo);
3208}
3209
3210MagickExport const PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
3211  const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3212  const size_t columns,const size_t rows,NexusInfo *nexus_info,
3213  ExceptionInfo *exception)
3214{
3215  CacheInfo
3216    *cache_info;
3217
3218  IndexPacket
3219    virtual_index;
3220
3221  MagickOffsetType
3222    offset;
3223
3224  MagickSizeType
3225    length,
3226    number_pixels;
3227
3228  NexusInfo
3229    **virtual_nexus;
3230
3231  PixelPacket
3232    *pixels,
3233    virtual_pixel;
3234
3235  RectangleInfo
3236    region;
3237
3238  register const IndexPacket
3239    *restrict virtual_indexes;
3240
3241  register const PixelPacket
3242    *restrict p;
3243
3244  register IndexPacket
3245    *restrict indexes;
3246
3247  register PixelPacket
3248    *restrict q;
3249
3250  register ssize_t
3251    u,
3252    v;
3253
3254  /*
3255    Acquire pixels.
3256  */
3257  assert(image != (const Image *) NULL);
3258  assert(image->signature == MagickSignature);
3259  assert(image->cache != (Cache) NULL);
3260  cache_info=(CacheInfo *) image->cache;
3261  assert(cache_info->signature == MagickSignature);
3262  if (cache_info->type == UndefinedCache)
3263    return((const PixelPacket *) NULL);
3264  region.x=x;
3265  region.y=y;
3266  region.width=columns;
3267  region.height=rows;
3268  pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
3269  if (pixels == (PixelPacket *) NULL)
3270    return((const PixelPacket *) NULL);
3271  offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3272    nexus_info->region.x;
3273  length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3274    nexus_info->region.width-1L;
3275  number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3276  if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
3277    if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3278        (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
3279      {
3280        MagickBooleanType
3281          status;
3282
3283        /*
3284          Pixel request is inside cache extents.
3285        */
3286        if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
3287          return(pixels);
3288        status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3289        if (status == MagickFalse)
3290          return((const PixelPacket *) NULL);
3291        if ((cache_info->storage_class == PseudoClass) ||
3292            (cache_info->colorspace == CMYKColorspace))
3293          {
3294            status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
3295            if (status == MagickFalse)
3296              return((const PixelPacket *) NULL);
3297          }
3298        return(pixels);
3299      }
3300  /*
3301    Pixel request is outside cache extents.
3302  */
3303  q=pixels;
3304  indexes=GetPixelCacheNexusIndexes(cache_info,nexus_info);
3305  virtual_nexus=AcquirePixelCacheNexus(1);
3306  if (virtual_nexus == (NexusInfo **) NULL)
3307    {
3308      (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3309        "UnableToGetCacheNexus","`%s'",image->filename);
3310      return((const PixelPacket *) NULL);
3311    }
3312  switch (virtual_pixel_method)
3313  {
3314    case BlackVirtualPixelMethod:
3315    {
3316      SetPixelRed(&virtual_pixel,0);
3317      SetPixelGreen(&virtual_pixel,0);
3318      SetPixelBlue(&virtual_pixel,0);
3319      SetPixelOpacity(&virtual_pixel,OpaqueOpacity);
3320      break;
3321    }
3322    case GrayVirtualPixelMethod:
3323    {
3324      SetPixelRed(&virtual_pixel,QuantumRange/2);
3325      SetPixelGreen(&virtual_pixel,QuantumRange/2);
3326      SetPixelBlue(&virtual_pixel,QuantumRange/2);
3327      SetPixelOpacity(&virtual_pixel,OpaqueOpacity);
3328      break;
3329    }
3330    case TransparentVirtualPixelMethod:
3331    {
3332      SetPixelRed(&virtual_pixel,0);
3333      SetPixelGreen(&virtual_pixel,0);
3334      SetPixelBlue(&virtual_pixel,0);
3335      SetPixelOpacity(&virtual_pixel,TransparentOpacity);
3336      break;
3337    }
3338    case MaskVirtualPixelMethod:
3339    case WhiteVirtualPixelMethod:
3340    {
3341      SetPixelRed(&virtual_pixel,QuantumRange);
3342      SetPixelGreen(&virtual_pixel,QuantumRange);
3343      SetPixelBlue(&virtual_pixel,QuantumRange);
3344      SetPixelOpacity(&virtual_pixel,OpaqueOpacity);
3345      break;
3346    }
3347    default:
3348    {
3349      virtual_pixel=image->background_color;
3350      break;
3351    }
3352  }
3353  virtual_index=0;
3354  for (v=0; v < (ssize_t) rows; v++)
3355  {
3356    for (u=0; u < (ssize_t) columns; u+=length)
3357    {
3358      length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
3359      if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
3360          (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3361          (length == 0))
3362        {
3363          MagickModulo
3364            x_modulo,
3365            y_modulo;
3366
3367          /*
3368            Transfer a single pixel.
3369          */
3370          length=(MagickSizeType) 1;
3371          switch (virtual_pixel_method)
3372          {
3373            case BackgroundVirtualPixelMethod:
3374            case ConstantVirtualPixelMethod:
3375            case BlackVirtualPixelMethod:
3376            case GrayVirtualPixelMethod:
3377            case TransparentVirtualPixelMethod:
3378            case MaskVirtualPixelMethod:
3379            case WhiteVirtualPixelMethod:
3380            {
3381              p=(&virtual_pixel);
3382              virtual_indexes=(&virtual_index);
3383              break;
3384            }
3385            case EdgeVirtualPixelMethod:
3386            default:
3387            {
3388              p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3389                EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
3390                1UL,1UL,*virtual_nexus,exception);
3391              virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3392                *virtual_nexus);
3393              break;
3394            }
3395            case RandomVirtualPixelMethod:
3396            {
3397              if (cache_info->random_info == (RandomInfo *) NULL)
3398                cache_info->random_info=AcquireRandomInfo();
3399              p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3400                RandomX(cache_info->random_info,cache_info->columns),
3401                RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
3402                *virtual_nexus,exception);
3403              virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3404                *virtual_nexus);
3405              break;
3406            }
3407            case DitherVirtualPixelMethod:
3408            {
3409              p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3410                DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
3411                1UL,1UL,*virtual_nexus,exception);
3412              virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3413                *virtual_nexus);
3414              break;
3415            }
3416            case TileVirtualPixelMethod:
3417            {
3418              x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3419              y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3420              p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3421                x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3422                exception);
3423              virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3424                *virtual_nexus);
3425              break;
3426            }
3427            case MirrorVirtualPixelMethod:
3428            {
3429              x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3430              if ((x_modulo.quotient & 0x01) == 1L)
3431                x_modulo.remainder=(ssize_t) cache_info->columns-
3432                  x_modulo.remainder-1L;
3433              y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3434              if ((y_modulo.quotient & 0x01) == 1L)
3435                y_modulo.remainder=(ssize_t) cache_info->rows-
3436                  y_modulo.remainder-1L;
3437              p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3438                x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3439                exception);
3440              virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3441                *virtual_nexus);
3442              break;
3443            }
3444            case CheckerTileVirtualPixelMethod:
3445            {
3446              x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3447              y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3448              if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3449                {
3450                  p=(&virtual_pixel);
3451                  virtual_indexes=(&virtual_index);
3452                  break;
3453                }
3454              p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3455                x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3456                exception);
3457              virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3458                *virtual_nexus);
3459              break;
3460            }
3461            case HorizontalTileVirtualPixelMethod:
3462            {
3463              if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3464                {
3465                  p=(&virtual_pixel);
3466                  virtual_indexes=(&virtual_index);
3467                  break;
3468                }
3469              x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3470              y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3471              p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3472                x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3473                exception);
3474              virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3475                *virtual_nexus);
3476              break;
3477            }
3478            case VerticalTileVirtualPixelMethod:
3479            {
3480              if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3481                {
3482                  p=(&virtual_pixel);
3483                  virtual_indexes=(&virtual_index);
3484                  break;
3485                }
3486              x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3487              y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3488              p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3489                x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3490                exception);
3491              virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3492                *virtual_nexus);
3493              break;
3494            }
3495            case HorizontalTileEdgeVirtualPixelMethod:
3496            {
3497              x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3498              p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3499                x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
3500                *virtual_nexus,exception);
3501              virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3502                *virtual_nexus);
3503              break;
3504            }
3505            case VerticalTileEdgeVirtualPixelMethod:
3506            {
3507              y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3508              p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3509                EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
3510                *virtual_nexus,exception);
3511              virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3512                *virtual_nexus);
3513              break;
3514            }
3515          }
3516          if (p == (const PixelPacket *) NULL)
3517            break;
3518          *q++=(*p);
3519          if ((indexes != (IndexPacket *) NULL) &&
3520              (virtual_indexes != (const IndexPacket *) NULL))
3521            *indexes++=(*virtual_indexes);
3522          continue;
3523        }
3524      /*
3525        Transfer a run of pixels.
3526      */
3527      p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,
3528        (size_t) length,1UL,*virtual_nexus,exception);
3529      if (p == (const PixelPacket *) NULL)
3530        break;
3531      virtual_indexes=GetVirtualIndexesFromNexus(cache_info,*virtual_nexus);
3532      (void) memcpy(q,p,(size_t) length*sizeof(*p));
3533      q+=length;
3534      if ((indexes != (IndexPacket *) NULL) &&
3535          (virtual_indexes != (const IndexPacket *) NULL))
3536        {
3537          (void) memcpy(indexes,virtual_indexes,(size_t) length*
3538            sizeof(*virtual_indexes));
3539          indexes+=length;
3540        }
3541    }
3542  }
3543  virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3544  return(pixels);
3545}
3546
3547/*
3548%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3549%                                                                             %
3550%                                                                             %
3551%                                                                             %
3552+   G e t V i r t u a l P i x e l C a c h e                                   %
3553%                                                                             %
3554%                                                                             %
3555%                                                                             %
3556%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3557%
3558%  GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3559%  cache as defined by the geometry parameters.   A pointer to the pixels
3560%  is returned if the pixels are transferred, otherwise a NULL is returned.
3561%
3562%  The format of the GetVirtualPixelCache() method is:
3563%
3564%      const PixelPacket *GetVirtualPixelCache(const Image *image,
3565%        const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3566%        const ssize_t y,const size_t columns,const size_t rows,
3567%        ExceptionInfo *exception)
3568%
3569%  A description of each parameter follows:
3570%
3571%    o image: the image.
3572%
3573%    o virtual_pixel_method: the virtual pixel method.
3574%
3575%    o x,y,columns,rows:  These values define the perimeter of a region of
3576%      pixels.
3577%
3578%    o exception: return any errors or warnings in this structure.
3579%
3580*/
3581static const PixelPacket *GetVirtualPixelCache(const Image *image,
3582  const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3583  const size_t columns,const size_t rows,ExceptionInfo *exception)
3584{
3585  CacheInfo
3586    *cache_info;
3587
3588  const int
3589    id = GetOpenMPThreadId();
3590
3591  assert(image != (const Image *) NULL);
3592  assert(image->signature == MagickSignature);
3593  assert(image->cache != (Cache) NULL);
3594  cache_info=(CacheInfo *) image->cache;
3595  assert(cache_info->signature == MagickSignature);
3596  assert(id < (int) cache_info->number_threads);
3597  return(GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3598    cache_info->nexus_info[id],exception));
3599}
3600
3601/*
3602%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3603%                                                                             %
3604%                                                                             %
3605%                                                                             %
3606%   G e t V i r t u a l P i x e l Q u e u e                                   %
3607%                                                                             %
3608%                                                                             %
3609%                                                                             %
3610%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3611%
3612%  GetVirtualPixelQueue() returns the virtual pixels associated with the
3613%  last call to QueueAuthenticPixels() or GetVirtualPixels().
3614%
3615%  The format of the GetVirtualPixelQueue() method is:
3616%
3617%      const PixelPacket *GetVirtualPixelQueue(const Image image)
3618%
3619%  A description of each parameter follows:
3620%
3621%    o image: the image.
3622%
3623*/
3624MagickExport const PixelPacket *GetVirtualPixelQueue(const Image *image)
3625{
3626  CacheInfo
3627    *cache_info;
3628
3629  const int
3630    id = GetOpenMPThreadId();
3631
3632  assert(image != (const Image *) NULL);
3633  assert(image->signature == MagickSignature);
3634  assert(image->cache != (Cache) NULL);
3635  cache_info=(CacheInfo *) image->cache;
3636  assert(cache_info->signature == MagickSignature);
3637  if (cache_info->methods.get_virtual_pixels_handler !=
3638       (GetVirtualPixelsHandler) NULL)
3639    return(cache_info->methods.get_virtual_pixels_handler(image));
3640  assert(id < (int) cache_info->number_threads);
3641  return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3642}
3643
3644/*
3645%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3646%                                                                             %
3647%                                                                             %
3648%                                                                             %
3649%   G e t V i r t u a l P i x e l s                                           %
3650%                                                                             %
3651%                                                                             %
3652%                                                                             %
3653%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3654%
3655%  GetVirtualPixels() returns an immutable pixel region. If the
3656%  region is successfully accessed, a pointer to it is returned, otherwise
3657%  NULL is returned.  The returned pointer may point to a temporary working
3658%  copy of the pixels or it may point to the original pixels in memory.
3659%  Performance is maximized if the selected region is part of one row, or one
3660%  or more full rows, since there is opportunity to access the pixels in-place
3661%  (without a copy) if the image is in memory, or in a memory-mapped file.  The
3662%  returned pointer must *never* be deallocated by the user.
3663%
3664%  Pixels accessed via the returned pointer represent a simple array of type
3665%  PixelPacket.  If the image type is CMYK or the storage class is PseudoClass,
3666%  call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access
3667%  the black color component or to obtain the colormap indexes (of type
3668%  IndexPacket) corresponding to the region.
3669%
3670%  If you plan to modify the pixels, use GetAuthenticPixels() instead.
3671%
3672%  Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3673%  safe.  In a threaded environment, use GetCacheViewVirtualPixels() or
3674%  GetCacheViewAuthenticPixels() instead.
3675%
3676%  The format of the GetVirtualPixels() method is:
3677%
3678%      const PixelPacket *GetVirtualPixels(const Image *image,const ssize_t x,
3679%        const ssize_t y,const size_t columns,const size_t rows,
3680%        ExceptionInfo *exception)
3681%
3682%  A description of each parameter follows:
3683%
3684%    o image: the image.
3685%
3686%    o x,y,columns,rows:  These values define the perimeter of a region of
3687%      pixels.
3688%
3689%    o exception: return any errors or warnings in this structure.
3690%
3691*/
3692MagickExport const PixelPacket *GetVirtualPixels(const Image *image,
3693  const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3694  ExceptionInfo *exception)
3695{
3696  CacheInfo
3697    *cache_info;
3698
3699  const int
3700    id = GetOpenMPThreadId();
3701
3702  assert(image != (const Image *) NULL);
3703  assert(image->signature == MagickSignature);
3704  assert(image->cache != (Cache) NULL);
3705  cache_info=(CacheInfo *) image->cache;
3706  assert(cache_info->signature == MagickSignature);
3707  if (cache_info->methods.get_virtual_pixel_handler !=
3708       (GetVirtualPixelHandler) NULL)
3709    return(cache_info->methods.get_virtual_pixel_handler(image,
3710      GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3711  assert(id < (int) cache_info->number_threads);
3712  return(GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3713    columns,rows,cache_info->nexus_info[id],exception));
3714}
3715
3716/*
3717%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3718%                                                                             %
3719%                                                                             %
3720%                                                                             %
3721+   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                         %
3722%                                                                             %
3723%                                                                             %
3724%                                                                             %
3725%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3726%
3727%  GetVirtualPixelsCache() returns the pixels associated with the last call
3728%  to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3729%
3730%  The format of the GetVirtualPixelsCache() method is:
3731%
3732%      PixelPacket *GetVirtualPixelsCache(const Image *image)
3733%
3734%  A description of each parameter follows:
3735%
3736%    o image: the image.
3737%
3738*/
3739static const PixelPacket *GetVirtualPixelsCache(const Image *image)
3740{
3741  CacheInfo
3742    *cache_info;
3743
3744  const int
3745    id = GetOpenMPThreadId();
3746
3747  assert(image != (const Image *) NULL);
3748  assert(image->signature == MagickSignature);
3749  assert(image->cache != (Cache) NULL);
3750  cache_info=(CacheInfo *) image->cache;
3751  assert(cache_info->signature == MagickSignature);
3752  assert(id < (int) cache_info->number_threads);
3753  return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3754}
3755
3756/*
3757%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3758%                                                                             %
3759%                                                                             %
3760%                                                                             %
3761+   G e t V i r t u a l P i x e l s N e x u s                                 %
3762%                                                                             %
3763%                                                                             %
3764%                                                                             %
3765%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3766%
3767%  GetVirtualPixelsNexus() returns the pixels associated with the specified
3768%  cache nexus.
3769%
3770%  The format of the GetVirtualPixelsNexus() method is:
3771%
3772%      const IndexPacket *GetVirtualPixelsNexus(const Cache cache,
3773%        NexusInfo *nexus_info)
3774%
3775%  A description of each parameter follows:
3776%
3777%    o cache: the pixel cache.
3778%
3779%    o nexus_info: the cache nexus to return the colormap pixels.
3780%
3781*/
3782MagickExport const PixelPacket *GetVirtualPixelsNexus(const Cache cache,
3783  NexusInfo *nexus_info)
3784{
3785  CacheInfo
3786    *cache_info;
3787
3788  assert(cache != (Cache) NULL);
3789  cache_info=(CacheInfo *) cache;
3790  assert(cache_info->signature == MagickSignature);
3791  if (cache_info->storage_class == UndefinedClass)
3792    return((PixelPacket *) NULL);
3793  return((const PixelPacket *) nexus_info->pixels);
3794}
3795
3796/*
3797%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3798%                                                                             %
3799%                                                                             %
3800%                                                                             %
3801+   M a s k P i x e l C a c h e N e x u s                                     %
3802%                                                                             %
3803%                                                                             %
3804%                                                                             %
3805%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3806%
3807%  MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3808%  The method returns MagickTrue if the pixel region is masked, otherwise
3809%  MagickFalse.
3810%
3811%  The format of the MaskPixelCacheNexus() method is:
3812%
3813%      MagickBooleanType MaskPixelCacheNexus(Image *image,
3814%        NexusInfo *nexus_info,ExceptionInfo *exception)
3815%
3816%  A description of each parameter follows:
3817%
3818%    o image: the image.
3819%
3820%    o nexus_info: the cache nexus to clip.
3821%
3822%    o exception: return any errors or warnings in this structure.
3823%
3824*/
3825
3826static inline void MagickPixelCompositeMask(const MagickPixelPacket *p,
3827  const MagickRealType alpha,const MagickPixelPacket *q,
3828  const MagickRealType beta,MagickPixelPacket *composite)
3829{
3830  MagickRealType
3831    gamma;
3832
3833  if (alpha == TransparentOpacity)
3834    {
3835      *composite=(*q);
3836      return;
3837    }
3838  gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3839  gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3840  composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3841  composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3842  composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3843  if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3844    composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
3845}
3846
3847static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3848  ExceptionInfo *exception)
3849{
3850  CacheInfo
3851    *cache_info;
3852
3853  MagickPixelPacket
3854    alpha,
3855    beta;
3856
3857  MagickSizeType
3858    number_pixels;
3859
3860  NexusInfo
3861    **clip_nexus,
3862    **image_nexus;
3863
3864  register const PixelPacket
3865    *restrict r;
3866
3867  register IndexPacket
3868    *restrict nexus_indexes,
3869    *restrict indexes;
3870
3871  register PixelPacket
3872    *restrict p,
3873    *restrict q;
3874
3875  register ssize_t
3876    i;
3877
3878  /*
3879    Apply clip mask.
3880  */
3881  if (image->debug != MagickFalse)
3882    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3883  if (image->mask == (Image *) NULL)
3884    return(MagickFalse);
3885  cache_info=(CacheInfo *) image->cache;
3886  if (cache_info == (Cache) NULL)
3887    return(MagickFalse);
3888  image_nexus=AcquirePixelCacheNexus(1);
3889  clip_nexus=AcquirePixelCacheNexus(1);
3890  if ((image_nexus == (NexusInfo **) NULL) ||
3891      (clip_nexus == (NexusInfo **) NULL))
3892    ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
3893  p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,
3894    nexus_info->region.y,nexus_info->region.width,nexus_info->region.height,
3895    image_nexus[0],exception);
3896  indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
3897  q=nexus_info->pixels;
3898  nexus_indexes=nexus_info->indexes;
3899  r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3900    nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3901    nexus_info->region.height,clip_nexus[0],&image->exception);
3902  GetMagickPixelPacket(image,&alpha);
3903  GetMagickPixelPacket(image,&beta);
3904  number_pixels=(MagickSizeType) nexus_info->region.width*
3905    nexus_info->region.height;
3906  for (i=0; i < (ssize_t) number_pixels; i++)
3907  {
3908    if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
3909      break;
3910    SetMagickPixelPacket(image,p,indexes+i,&alpha);
3911    SetMagickPixelPacket(image,q,nexus_indexes+i,&beta);
3912    MagickPixelCompositeMask(&beta,(MagickRealType) PixelIntensityToQuantum(r),
3913      &alpha,alpha.opacity,&beta);
3914    SetPixelRed(q,ClampToQuantum(beta.red));
3915    SetPixelGreen(q,ClampToQuantum(beta.green));
3916    SetPixelBlue(q,ClampToQuantum(beta.blue));
3917    SetPixelOpacity(q,ClampToQuantum(beta.opacity));
3918    if (cache_info->active_index_channel != MagickFalse)
3919      SetPixelIndex(nexus_indexes+i,GetPixelIndex(indexes+i));
3920    p++;
3921    q++;
3922    r++;
3923  }
3924  clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3925  image_nexus=DestroyPixelCacheNexus(image_nexus,1);
3926  if (i < (ssize_t) number_pixels)
3927    return(MagickFalse);
3928  return(MagickTrue);
3929}
3930
3931/*
3932%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3933%                                                                             %
3934%                                                                             %
3935%                                                                             %
3936+   O p e n P i x e l C a c h e                                               %
3937%                                                                             %
3938%                                                                             %
3939%                                                                             %
3940%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3941%
3942%  OpenPixelCache() allocates the pixel cache.  This includes defining the cache
3943%  dimensions, allocating space for the image pixels and optionally the
3944%  colormap indexes, and memory mapping the cache if it is disk based.  The
3945%  cache nexus array is initialized as well.
3946%
3947%  The format of the OpenPixelCache() method is:
3948%
3949%      MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3950%        ExceptionInfo *exception)
3951%
3952%  A description of each parameter follows:
3953%
3954%    o image: the image.
3955%
3956%    o mode: ReadMode, WriteMode, or IOMode.
3957%
3958%    o exception: return any errors or warnings in this structure.
3959%
3960*/
3961
3962static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3963{
3964  cache_info->mapped=MagickFalse;
3965  cache_info->pixels=(PixelPacket *) AcquireMagickMemory((size_t)
3966    cache_info->length);
3967  if (cache_info->pixels == (PixelPacket *) NULL)
3968    {
3969      cache_info->mapped=MagickTrue;
3970      cache_info->pixels=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
3971        cache_info->length);
3972    }
3973}
3974
3975static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3976{
3977  CacheInfo
3978    *cache_info;
3979
3980  MagickOffsetType
3981    count,
3982    extent,
3983    offset;
3984
3985  cache_info=(CacheInfo *) image->cache;
3986  if (image->debug != MagickFalse)
3987    {
3988      char
3989        format[MaxTextExtent],
3990        message[MaxTextExtent];
3991
3992      (void) FormatMagickSize(length,MagickFalse,format);
3993      (void) FormatLocaleString(message,MaxTextExtent,
3994        "extend %s (%s[%d], disk, %s)",cache_info->filename,
3995        cache_info->cache_filename,cache_info->file,format);
3996      (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3997    }
3998  if (length != (MagickSizeType) ((MagickOffsetType) length))
3999    return(MagickFalse);
4000  extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
4001  if (extent < 0)
4002    return(MagickFalse);
4003  if ((MagickSizeType) extent >= length)
4004    return(MagickTrue);
4005  offset=(MagickOffsetType) length-1;
4006  count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
4007  return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
4008}
4009
4010static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
4011  ExceptionInfo *exception)
4012{
4013  CacheInfo
4014    *cache_info,
4015    source_info;
4016
4017  char
4018    format[MaxTextExtent],
4019    message[MaxTextExtent];
4020
4021  MagickSizeType
4022    length,
4023    number_pixels;
4024
4025  MagickStatusType
4026    status;
4027
4028  size_t
4029    columns,
4030    packet_size;
4031
4032  assert(image != (const Image *) NULL);
4033  assert(image->signature == MagickSignature);
4034  assert(image->cache != (Cache) NULL);
4035  if (image->debug != MagickFalse)
4036    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4037  if ((image->columns == 0) || (image->rows == 0))
4038    ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
4039  cache_info=(CacheInfo *) image->cache;
4040  assert(cache_info->signature == MagickSignature);
4041  source_info=(*cache_info);
4042  source_info.file=(-1);
4043  (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
4044    image->filename,(double) GetImageIndexInList(image));
4045  cache_info->mode=mode;
4046  cache_info->rows=image->rows;
4047  cache_info->columns=image->columns;
4048  cache_info->channels=image->channels;
4049  cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
4050    (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
4051  if (image->ping != MagickFalse)
4052    {
4053      cache_info->storage_class=image->storage_class;
4054      cache_info->colorspace=image->colorspace;
4055      cache_info->type=PingCache;
4056      cache_info->pixels=(PixelPacket *) NULL;
4057      cache_info->indexes=(IndexPacket *) NULL;
4058      cache_info->length=0;
4059      return(MagickTrue);
4060    }
4061  number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4062  packet_size=sizeof(PixelPacket);
4063  if (cache_info->active_index_channel != MagickFalse)
4064    packet_size+=sizeof(IndexPacket);
4065  length=number_pixels*packet_size;
4066  columns=(size_t) (length/cache_info->rows/packet_size);
4067  if (cache_info->columns != columns)
4068    ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4069      image->filename);
4070  cache_info->length=length;
4071  status=AcquireMagickResource(AreaResource,cache_info->length);
4072  length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4073  if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4074    {
4075      status=AcquireMagickResource(MemoryResource,cache_info->length);
4076      if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4077          (cache_info->type == MemoryCache))
4078        {
4079          AllocatePixelCachePixels(cache_info);
4080          if (cache_info->pixels == (PixelPacket *) NULL)
4081            cache_info->pixels=source_info.pixels;
4082          else
4083            {
4084              /*
4085                Create memory pixel cache.
4086              */
4087              if (image->debug != MagickFalse)
4088                {
4089                  (void) FormatMagickSize(cache_info->length,MagickTrue,
4090                    format);
4091                  (void) FormatLocaleString(message,MaxTextExtent,
4092                    "open %s (%s memory, %.20gx%.20g %s)",cache_info->filename,
4093                    cache_info->mapped != MagickFalse ? "anonymous" : "heap",
4094                    (double) cache_info->columns,(double) cache_info->rows,
4095                    format);
4096                  (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4097                    message);
4098                }
4099              cache_info->storage_class=image->storage_class;
4100              cache_info->colorspace=image->colorspace;
4101              cache_info->type=MemoryCache;
4102              cache_info->indexes=(IndexPacket *) NULL;
4103              if (cache_info->active_index_channel != MagickFalse)
4104                cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4105                  number_pixels);
4106              if (source_info.storage_class != UndefinedClass)
4107                {
4108                  status|=ClonePixelCachePixels(cache_info,&source_info,
4109                    exception);
4110                  RelinquishPixelCachePixels(&source_info);
4111                }
4112              return(MagickTrue);
4113            }
4114        }
4115      RelinquishMagickResource(MemoryResource,cache_info->length);
4116    }
4117  /*
4118    Create pixel cache on disk.
4119  */
4120  status=AcquireMagickResource(DiskResource,cache_info->length);
4121  if (status == MagickFalse)
4122    {
4123      (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4124        "CacheResourcesExhausted","`%s'",image->filename);
4125      return(MagickFalse);
4126    }
4127  if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4128    {
4129      RelinquishMagickResource(DiskResource,cache_info->length);
4130      ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4131        image->filename);
4132      return(MagickFalse);
4133    }
4134  status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4135    cache_info->length);
4136  if (status == MagickFalse)
4137    {
4138      ThrowFileException(exception,CacheError,"UnableToExtendCache",
4139        image->filename);
4140      return(MagickFalse);
4141    }
4142  cache_info->storage_class=image->storage_class;
4143  cache_info->colorspace=image->colorspace;
4144  length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4145  status=AcquireMagickResource(AreaResource,cache_info->length);
4146  if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4147    cache_info->type=DiskCache;
4148  else
4149    {
4150      status=AcquireMagickResource(MapResource,cache_info->length);
4151      if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4152          (cache_info->type != MemoryCache))
4153        cache_info->type=DiskCache;
4154      else
4155        {
4156          cache_info->pixels=(PixelPacket *) MapBlob(cache_info->file,mode,
4157            cache_info->offset,(size_t) cache_info->length);
4158          if (cache_info->pixels == (PixelPacket *) NULL)
4159            {
4160              cache_info->pixels=source_info.pixels;
4161              cache_info->type=DiskCache;
4162            }
4163          else
4164            {
4165              /*
4166                Create file-backed memory-mapped pixel cache.
4167              */
4168              (void) ClosePixelCacheOnDisk(cache_info);
4169              cache_info->type=MapCache;
4170              cache_info->mapped=MagickTrue;
4171              cache_info->indexes=(IndexPacket *) NULL;
4172              if (cache_info->active_index_channel != MagickFalse)
4173                cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4174                  number_pixels);
4175              if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4176                {
4177                  status=ClonePixelCachePixels(cache_info,&source_info,
4178                    exception);
4179                  RelinquishPixelCachePixels(&source_info);
4180                }
4181              if (image->debug != MagickFalse)
4182                {
4183                  (void) FormatMagickSize(cache_info->length,MagickTrue,
4184                    format);
4185                  (void) FormatLocaleString(message,MaxTextExtent,
4186                    "open %s (%s[%d], memory-mapped, %.20gx%.20g %s)",
4187                    cache_info->filename,cache_info->cache_filename,
4188                    cache_info->file,(double) cache_info->columns,(double)
4189                    cache_info->rows,format);
4190                  (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4191                    message);
4192                }
4193              return(MagickTrue);
4194            }
4195        }
4196      RelinquishMagickResource(MapResource,cache_info->length);
4197    }
4198  if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4199    {
4200      status=ClonePixelCachePixels(cache_info,&source_info,exception);
4201      RelinquishPixelCachePixels(&source_info);
4202    }
4203  if (image->debug != MagickFalse)
4204    {
4205      (void) FormatMagickSize(cache_info->length,MagickFalse,format);
4206      (void) FormatLocaleString(message,MaxTextExtent,
4207        "open %s (%s[%d], disk, %.20gx%.20g %s)",cache_info->filename,
4208        cache_info->cache_filename,cache_info->file,(double)
4209        cache_info->columns,(double) cache_info->rows,format);
4210      (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4211    }
4212  return(MagickTrue);
4213}
4214
4215/*
4216%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4217%                                                                             %
4218%                                                                             %
4219%                                                                             %
4220+   P e r s i s t P i x e l C a c h e                                         %
4221%                                                                             %
4222%                                                                             %
4223%                                                                             %
4224%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4225%
4226%  PersistPixelCache() attaches to or initializes a persistent pixel cache.  A
4227%  persistent pixel cache is one that resides on disk and is not destroyed
4228%  when the program exits.
4229%
4230%  The format of the PersistPixelCache() method is:
4231%
4232%      MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4233%        const MagickBooleanType attach,MagickOffsetType *offset,
4234%        ExceptionInfo *exception)
4235%
4236%  A description of each parameter follows:
4237%
4238%    o image: the image.
4239%
4240%    o filename: the persistent pixel cache filename.
4241%
4242%    o attach: A value other than zero initializes the persistent pixel cache.
4243%
4244%    o initialize: A value other than zero initializes the persistent pixel
4245%      cache.
4246%
4247%    o offset: the offset in the persistent cache to store pixels.
4248%
4249%    o exception: return any errors or warnings in this structure.
4250%
4251*/
4252MagickExport MagickBooleanType PersistPixelCache(Image *image,
4253  const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4254  ExceptionInfo *exception)
4255{
4256  CacheInfo
4257    *cache_info,
4258    *clone_info;
4259
4260  Image
4261    clone_image;
4262
4263  MagickBooleanType
4264    status;
4265
4266  ssize_t
4267    page_size;
4268
4269  assert(image != (Image *) NULL);
4270  assert(image->signature == MagickSignature);
4271  if (image->debug != MagickFalse)
4272    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4273  assert(image->cache != (void *) NULL);
4274  assert(filename != (const char *) NULL);
4275  assert(offset != (MagickOffsetType *) NULL);
4276  page_size=GetMagickPageSize();
4277  cache_info=(CacheInfo *) image->cache;
4278  assert(cache_info->signature == MagickSignature);
4279  if (attach != MagickFalse)
4280    {
4281      /*
4282        Attach existing persistent pixel cache.
4283      */
4284      if (image->debug != MagickFalse)
4285        (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4286          "attach persistent cache");
4287      (void) CopyMagickString(cache_info->cache_filename,filename,
4288        MaxTextExtent);
4289      cache_info->type=DiskCache;
4290      cache_info->offset=(*offset);
4291      if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4292        return(MagickFalse);
4293      *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4294      return(MagickTrue);
4295    }
4296  if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4297      (cache_info->reference_count == 1))
4298    {
4299      LockSemaphoreInfo(cache_info->semaphore);
4300      if ((cache_info->mode != ReadMode) &&
4301          (cache_info->type != MemoryCache) &&
4302          (cache_info->reference_count == 1))
4303        {
4304          int
4305            status;
4306
4307          /*
4308            Usurp existing persistent pixel cache.
4309          */
4310          status=rename(cache_info->cache_filename,filename);
4311          if (status == 0)
4312            {
4313              (void) CopyMagickString(cache_info->cache_filename,filename,
4314                MaxTextExtent);
4315              *offset+=cache_info->length+page_size-(cache_info->length %
4316                page_size);
4317              UnlockSemaphoreInfo(cache_info->semaphore);
4318              cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
4319              if (image->debug != MagickFalse)
4320                (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4321                  "Usurp resident persistent cache");
4322              return(MagickTrue);
4323            }
4324        }
4325      UnlockSemaphoreInfo(cache_info->semaphore);
4326    }
4327  /*
4328    Clone persistent pixel cache.
4329  */
4330  clone_image=(*image);
4331  clone_info=(CacheInfo *) clone_image.cache;
4332  image->cache=ClonePixelCache(cache_info);
4333  cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4334  (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4335  cache_info->type=DiskCache;
4336  cache_info->offset=(*offset);
4337  cache_info=(CacheInfo *) image->cache;
4338  status=OpenPixelCache(image,IOMode,exception);
4339  if (status != MagickFalse)
4340    status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
4341  *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4342  clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4343  return(status);
4344}
4345
4346/*
4347%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4348%                                                                             %
4349%                                                                             %
4350%                                                                             %
4351+   Q u e u e A u t h e n t i c N e x u s                                     %
4352%                                                                             %
4353%                                                                             %
4354%                                                                             %
4355%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4356%
4357%  QueueAuthenticNexus() allocates an region to store image pixels as defined
4358%  by the region rectangle and returns a pointer to the region.  This region is
4359%  subsequently transferred from the pixel cache with
4360%  SyncAuthenticPixelsCache().  A pointer to the pixels is returned if the
4361%  pixels are transferred, otherwise a NULL is returned.
4362%
4363%  The format of the QueueAuthenticNexus() method is:
4364%
4365%      PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
4366%        const ssize_t y,const size_t columns,const size_t rows,
4367%        NexusInfo *nexus_info,ExceptionInfo *exception)
4368%
4369%  A description of each parameter follows:
4370%
4371%    o image: the image.
4372%
4373%    o x,y,columns,rows:  These values define the perimeter of a region of
4374%      pixels.
4375%
4376%    o nexus_info: the cache nexus to set.
4377%
4378%    o exception: return any errors or warnings in this structure.
4379%
4380*/
4381MagickExport PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
4382  const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
4383  ExceptionInfo *exception)
4384{
4385  CacheInfo
4386    *cache_info;
4387
4388  MagickOffsetType
4389    offset;
4390
4391  MagickSizeType
4392    number_pixels;
4393
4394  RectangleInfo
4395    region;
4396
4397  /*
4398    Validate pixel cache geometry.
4399  */
4400  assert(image != (const Image *) NULL);
4401  assert(image->signature == MagickSignature);
4402  assert(image->cache != (Cache) NULL);
4403  cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
4404  assert(cache_info->signature == MagickSignature);
4405  if (cache_info == (Cache) NULL)
4406    return((PixelPacket *) NULL);
4407  if ((cache_info->columns == 0) && (cache_info->rows == 0))
4408    {
4409      (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4410        "NoPixelsDefinedInCache","`%s'",image->filename);
4411      return((PixelPacket *) NULL);
4412    }
4413  if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4414      (y >= (ssize_t) cache_info->rows))
4415    {
4416      (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4417        "PixelsAreNotAuthentic","`%s'",image->filename);
4418      return((PixelPacket *) NULL);
4419    }
4420  offset=(MagickOffsetType) y*cache_info->columns+x;
4421  if (offset < 0)
4422    return((PixelPacket *) NULL);
4423  number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4424  offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4425  if ((MagickSizeType) offset >= number_pixels)
4426    return((PixelPacket *) NULL);
4427  /*
4428    Return pixel cache.
4429  */
4430  region.x=x;
4431  region.y=y;
4432  region.width=columns;
4433  region.height=rows;
4434  return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4435}
4436
4437/*
4438%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4439%                                                                             %
4440%                                                                             %
4441%                                                                             %
4442+   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                         %
4443%                                                                             %
4444%                                                                             %
4445%                                                                             %
4446%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4447%
4448%  QueueAuthenticPixelsCache() allocates an region to store image pixels as
4449%  defined by the region rectangle and returns a pointer to the region.  This
4450%  region is subsequently transferred from the pixel cache with
4451%  SyncAuthenticPixelsCache().  A pointer to the pixels is returned if the
4452%  pixels are transferred, otherwise a NULL is returned.
4453%
4454%  The format of the QueueAuthenticPixelsCache() method is:
4455%
4456%      PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4457%        const ssize_t y,const size_t columns,const size_t rows,
4458%        ExceptionInfo *exception)
4459%
4460%  A description of each parameter follows:
4461%
4462%    o image: the image.
4463%
4464%    o x,y,columns,rows:  These values define the perimeter of a region of
4465%      pixels.
4466%
4467%    o exception: return any errors or warnings in this structure.
4468%
4469*/
4470static PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4471  const ssize_t y,const size_t columns,const size_t rows,
4472  ExceptionInfo *exception)
4473{
4474  CacheInfo
4475    *cache_info;
4476
4477  const int
4478    id = GetOpenMPThreadId();
4479
4480  assert(image != (const Image *) NULL);
4481  assert(image->signature == MagickSignature);
4482  assert(image->cache != (Cache) NULL);
4483  cache_info=(CacheInfo *) image->cache;
4484  assert(cache_info->signature == MagickSignature);
4485  assert(id < (int) cache_info->number_threads);
4486  return(QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4487    exception));
4488}
4489
4490/*
4491%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4492%                                                                             %
4493%                                                                             %
4494%                                                                             %
4495%   Q u e u e A u t h e n t i c P i x e l s                                   %
4496%                                                                             %
4497%                                                                             %
4498%                                                                             %
4499%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4500%
4501%  QueueAuthenticPixels() queues a mutable pixel region.  If the region is
4502%  successfully initialized a pointer to a PixelPacket array representing the
4503%  region is returned, otherwise NULL is returned.  The returned pointer may
4504%  point to a temporary working buffer for the pixels or it may point to the
4505%  final location of the pixels in memory.
4506%
4507%  Write-only access means that any existing pixel values corresponding to
4508%  the region are ignored.  This is useful if the initial image is being
4509%  created from scratch, or if the existing pixel values are to be
4510%  completely replaced without need to refer to their pre-existing values.
4511%  The application is free to read and write the pixel buffer returned by
4512%  QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4513%  initialize the pixel array values. Initializing pixel array values is the
4514%  application's responsibility.
4515%
4516%  Performance is maximized if the selected region is part of one row, or
4517%  one or more full rows, since then there is opportunity to access the
4518%  pixels in-place (without a copy) if the image is in memory, or in a
4519%  memory-mapped file. The returned pointer must *never* be deallocated
4520%  by the user.
4521%
4522%  Pixels accessed via the returned pointer represent a simple array of type
4523%  PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
4524%  call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
4525%  the black color component or the colormap indexes (of type IndexPacket)
4526%  corresponding to the region.  Once the PixelPacket (and/or IndexPacket)
4527%  array has been updated, the changes must be saved back to the underlying
4528%  image using SyncAuthenticPixels() or they may be lost.
4529%
4530%  The format of the QueueAuthenticPixels() method is:
4531%
4532%      PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4533%        const ssize_t y,const size_t columns,const size_t rows,
4534%        ExceptionInfo *exception)
4535%
4536%  A description of each parameter follows:
4537%
4538%    o image: the image.
4539%
4540%    o x,y,columns,rows:  These values define the perimeter of a region of
4541%      pixels.
4542%
4543%    o exception: return any errors or warnings in this structure.
4544%
4545*/
4546MagickExport PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4547  const ssize_t y,const size_t columns,const size_t rows,
4548  ExceptionInfo *exception)
4549{
4550  CacheInfo
4551    *cache_info;
4552
4553  const int
4554    id = GetOpenMPThreadId();
4555
4556  assert(image != (Image *) NULL);
4557  assert(image->signature == MagickSignature);
4558  assert(image->cache != (Cache) NULL);
4559  cache_info=(CacheInfo *) image->cache;
4560  assert(cache_info->signature == MagickSignature);
4561  if (cache_info->methods.queue_authentic_pixels_handler !=
4562       (QueueAuthenticPixelsHandler) NULL)
4563    return(cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4564      rows,exception));
4565  assert(id < (int) cache_info->number_threads);
4566  return(QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4567    exception));
4568}
4569
4570/*
4571%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4572%                                                                             %
4573%                                                                             %
4574%                                                                             %
4575+   R e a d P i x e l C a c h e I n d e x e s                                 %
4576%                                                                             %
4577%                                                                             %
4578%                                                                             %
4579%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4580%
4581%  ReadPixelCacheIndexes() reads colormap indexes from the specified region of
4582%  the pixel cache.
4583%
4584%  The format of the ReadPixelCacheIndexes() method is:
4585%
4586%      MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4587%        NexusInfo *nexus_info,ExceptionInfo *exception)
4588%
4589%  A description of each parameter follows:
4590%
4591%    o cache_info: the pixel cache.
4592%
4593%    o nexus_info: the cache nexus to read the colormap indexes.
4594%
4595%    o exception: return any errors or warnings in this structure.
4596%
4597*/
4598static MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4599  NexusInfo *nexus_info,ExceptionInfo *exception)
4600{
4601  MagickOffsetType
4602    count,
4603    offset;
4604
4605  MagickSizeType
4606    extent,
4607    length;
4608
4609  register IndexPacket
4610    *restrict q;
4611
4612  register ssize_t
4613    y;
4614
4615  size_t
4616    rows;
4617
4618  if (cache_info->active_index_channel == MagickFalse)
4619    return(MagickFalse);
4620  if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4621    return(MagickTrue);
4622  offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4623    nexus_info->region.x;
4624  length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
4625  rows=nexus_info->region.height;
4626  extent=length*rows;
4627  q=nexus_info->indexes;
4628  switch (cache_info->type)
4629  {
4630    case MemoryCache:
4631    case MapCache:
4632    {
4633      register IndexPacket
4634        *restrict p;
4635
4636      /*
4637        Read indexes from memory.
4638      */
4639      if ((cache_info->columns == nexus_info->region.width) &&
4640          (extent == (MagickSizeType) ((size_t) extent)))
4641        {
4642          length=extent;
4643          rows=1UL;
4644        }
4645      p=cache_info->indexes+offset;
4646      for (y=0; y < (ssize_t) rows; y++)
4647      {
4648        (void) memcpy(q,p,(size_t) length);
4649        p+=cache_info->columns;
4650        q+=nexus_info->region.width;
4651      }
4652      break;
4653    }
4654    case DiskCache:
4655    {
4656      /*
4657        Read indexes from disk.
4658      */
4659      if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4660        {
4661          ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4662            cache_info->cache_filename);
4663          return(MagickFalse);
4664        }
4665      if ((cache_info->columns == nexus_info->region.width) &&
4666          (extent <= MagickMaxBufferExtent))
4667        {
4668          length=extent;
4669          rows=1UL;
4670        }
4671      extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4672      for (y=0; y < (ssize_t) rows; y++)
4673      {
4674        count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4675          sizeof(PixelPacket)+offset*sizeof(*q),length,(unsigned char *) q);
4676        if ((MagickSizeType) count < length)
4677          break;
4678        offset+=cache_info->columns;
4679        q+=nexus_info->region.width;
4680      }
4681      if (y < (ssize_t) rows)
4682        {
4683          ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4684            cache_info->cache_filename);
4685          return(MagickFalse);
4686        }
4687      break;
4688    }
4689    default:
4690      break;
4691  }
4692  if ((cache_info->debug != MagickFalse) &&
4693      (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4694    (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4695      "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4696      nexus_info->region.width,(double) nexus_info->region.height,(double)
4697      nexus_info->region.x,(double) nexus_info->region.y);
4698  return(MagickTrue);
4699}
4700
4701/*
4702%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4703%                                                                             %
4704%                                                                             %
4705%                                                                             %
4706+   R e a d P i x e l C a c h e P i x e l s                                   %
4707%                                                                             %
4708%                                                                             %
4709%                                                                             %
4710%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4711%
4712%  ReadPixelCachePixels() reads pixels from the specified region of the pixel
4713%  cache.
4714%
4715%  The format of the ReadPixelCachePixels() method is:
4716%
4717%      MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4718%        NexusInfo *nexus_info,ExceptionInfo *exception)
4719%
4720%  A description of each parameter follows:
4721%
4722%    o cache_info: the pixel cache.
4723%
4724%    o nexus_info: the cache nexus to read the pixels.
4725%
4726%    o exception: return any errors or warnings in this structure.
4727%
4728*/
4729static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4730  NexusInfo *nexus_info,ExceptionInfo *exception)
4731{
4732  MagickOffsetType
4733    count,
4734    offset;
4735
4736  MagickSizeType
4737    extent,
4738    length;
4739
4740  register PixelPacket
4741    *restrict q;
4742
4743  register ssize_t
4744    y;
4745
4746  size_t
4747    rows;
4748
4749  if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4750    return(MagickTrue);
4751  offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4752    nexus_info->region.x;
4753  length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
4754  rows=nexus_info->region.height;
4755  extent=length*rows;
4756  q=nexus_info->pixels;
4757  switch (cache_info->type)
4758  {
4759    case MemoryCache:
4760    case MapCache:
4761    {
4762      register PixelPacket
4763        *restrict p;
4764
4765      /*
4766        Read pixels from memory.
4767      */
4768      if ((cache_info->columns == nexus_info->region.width) &&
4769          (extent == (MagickSizeType) ((size_t) extent)))
4770        {
4771          length=extent;
4772          rows=1UL;
4773        }
4774      p=cache_info->pixels+offset;
4775      for (y=0; y < (ssize_t) rows; y++)
4776      {
4777        (void) memcpy(q,p,(size_t) length);
4778        p+=cache_info->columns;
4779        q+=nexus_info->region.width;
4780      }
4781      break;
4782    }
4783    case DiskCache:
4784    {
4785      /*
4786        Read pixels from disk.
4787      */
4788      if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4789        {
4790          ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4791            cache_info->cache_filename);
4792          return(MagickFalse);
4793        }
4794      if ((cache_info->columns == nexus_info->region.width) &&
4795          (extent <= MagickMaxBufferExtent))
4796        {
4797          length=extent;
4798          rows=1UL;
4799        }
4800      for (y=0; y < (ssize_t) rows; y++)
4801      {
4802        count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4803          sizeof(*q),length,(unsigned char *) q);
4804        if ((MagickSizeType) count < length)
4805          break;
4806        offset+=cache_info->columns;
4807        q+=nexus_info->region.width;
4808      }
4809      if (y < (ssize_t) rows)
4810        {
4811          ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4812            cache_info->cache_filename);
4813          return(MagickFalse);
4814        }
4815      break;
4816    }
4817    default:
4818      break;
4819  }
4820  if ((cache_info->debug != MagickFalse) &&
4821      (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4822    (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4823      "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4824      nexus_info->region.width,(double) nexus_info->region.height,(double)
4825      nexus_info->region.x,(double) nexus_info->region.y);
4826  return(MagickTrue);
4827}
4828
4829/*
4830%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4831%                                                                             %
4832%                                                                             %
4833%                                                                             %
4834+   R e f e r e n c e P i x e l C a c h e                                     %
4835%                                                                             %
4836%                                                                             %
4837%                                                                             %
4838%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4839%
4840%  ReferencePixelCache() increments the reference count associated with the
4841%  pixel cache returning a pointer to the cache.
4842%
4843%  The format of the ReferencePixelCache method is:
4844%
4845%      Cache ReferencePixelCache(Cache cache_info)
4846%
4847%  A description of each parameter follows:
4848%
4849%    o cache_info: the pixel cache.
4850%
4851*/
4852MagickExport Cache ReferencePixelCache(Cache cache)
4853{
4854  CacheInfo
4855    *cache_info;
4856
4857  assert(cache != (Cache *) NULL);
4858  cache_info=(CacheInfo *) cache;
4859  assert(cache_info->signature == MagickSignature);
4860  LockSemaphoreInfo(cache_info->semaphore);
4861  cache_info->reference_count++;
4862  UnlockSemaphoreInfo(cache_info->semaphore);
4863  return(cache_info);
4864}
4865
4866/*
4867%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4868%                                                                             %
4869%                                                                             %
4870%                                                                             %
4871+   S e t P i x e l C a c h e M e t h o d s                                   %
4872%                                                                             %
4873%                                                                             %
4874%                                                                             %
4875%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4876%
4877%  SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4878%
4879%  The format of the SetPixelCacheMethods() method is:
4880%
4881%      SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4882%
4883%  A description of each parameter follows:
4884%
4885%    o cache: the pixel cache.
4886%
4887%    o cache_methods: Specifies a pointer to a CacheMethods structure.
4888%
4889*/
4890MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4891{
4892  CacheInfo
4893    *cache_info;
4894
4895  GetOneAuthenticPixelFromHandler
4896    get_one_authentic_pixel_from_handler;
4897
4898  GetOneVirtualPixelFromHandler
4899    get_one_virtual_pixel_from_handler;
4900
4901  /*
4902    Set cache pixel methods.
4903  */
4904  assert(cache != (Cache) NULL);
4905  assert(cache_methods != (CacheMethods *) NULL);
4906  cache_info=(CacheInfo *) cache;
4907  assert(cache_info->signature == MagickSignature);
4908  if (cache_info->debug != MagickFalse)
4909    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4910      cache_info->filename);
4911  if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4912    cache_info->methods.get_virtual_pixel_handler=
4913      cache_methods->get_virtual_pixel_handler;
4914  if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4915    cache_info->methods.destroy_pixel_handler=
4916      cache_methods->destroy_pixel_handler;
4917  if (cache_methods->get_virtual_indexes_from_handler !=
4918      (GetVirtualIndexesFromHandler) NULL)
4919    cache_info->methods.get_virtual_indexes_from_handler=
4920      cache_methods->get_virtual_indexes_from_handler;
4921  if (cache_methods->get_authentic_pixels_handler !=
4922      (GetAuthenticPixelsHandler) NULL)
4923    cache_info->methods.get_authentic_pixels_handler=
4924      cache_methods->get_authentic_pixels_handler;
4925  if (cache_methods->queue_authentic_pixels_handler !=
4926      (QueueAuthenticPixelsHandler) NULL)
4927    cache_info->methods.queue_authentic_pixels_handler=
4928      cache_methods->queue_authentic_pixels_handler;
4929  if (cache_methods->sync_authentic_pixels_handler !=
4930      (SyncAuthenticPixelsHandler) NULL)
4931    cache_info->methods.sync_authentic_pixels_handler=
4932      cache_methods->sync_authentic_pixels_handler;
4933  if (cache_methods->get_authentic_pixels_from_handler !=
4934      (GetAuthenticPixelsFromHandler) NULL)
4935    cache_info->methods.get_authentic_pixels_from_handler=
4936      cache_methods->get_authentic_pixels_from_handler;
4937  if (cache_methods->get_authentic_indexes_from_handler !=
4938      (GetAuthenticIndexesFromHandler) NULL)
4939    cache_info->methods.get_authentic_indexes_from_handler=
4940      cache_methods->get_authentic_indexes_from_handler;
4941  get_one_virtual_pixel_from_handler=
4942    cache_info->methods.get_one_virtual_pixel_from_handler;
4943  if (get_one_virtual_pixel_from_handler !=
4944      (GetOneVirtualPixelFromHandler) NULL)
4945    cache_info->methods.get_one_virtual_pixel_from_handler=
4946      cache_methods->get_one_virtual_pixel_from_handler;
4947  get_one_authentic_pixel_from_handler=
4948    cache_methods->get_one_authentic_pixel_from_handler;
4949  if (get_one_authentic_pixel_from_handler !=
4950      (GetOneAuthenticPixelFromHandler) NULL)
4951    cache_info->methods.get_one_authentic_pixel_from_handler=
4952      cache_methods->get_one_authentic_pixel_from_handler;
4953}
4954
4955/*
4956%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4957%                                                                             %
4958%                                                                             %
4959%                                                                             %
4960+   S e t P i x e l C a c h e N e x u s P i x e l s                           %
4961%                                                                             %
4962%                                                                             %
4963%                                                                             %
4964%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4965%
4966%  SetPixelCacheNexusPixels() defines the region of the cache for the
4967%  specified cache nexus.
4968%
4969%  The format of the SetPixelCacheNexusPixels() method is:
4970%
4971%      PixelPacket SetPixelCacheNexusPixels(const Image *image,
4972%        const RectangleInfo *region,NexusInfo *nexus_info,
4973%        ExceptionInfo *exception)
4974%
4975%  A description of each parameter follows:
4976%
4977%    o image: the image.
4978%
4979%    o region: A pointer to the RectangleInfo structure that defines the
4980%      region of this particular cache nexus.
4981%
4982%    o nexus_info: the cache nexus to set.
4983%
4984%    o exception: return any errors or warnings in this structure.
4985%
4986*/
4987
4988static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4989  NexusInfo *nexus_info,ExceptionInfo *exception)
4990{
4991  if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4992    return(MagickFalse);
4993  nexus_info->mapped=MagickFalse;
4994  nexus_info->cache=(PixelPacket *) AcquireMagickMemory((size_t)
4995    nexus_info->length);
4996  if (nexus_info->cache == (PixelPacket *) NULL)
4997    {
4998      nexus_info->mapped=MagickTrue;
4999      nexus_info->cache=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
5000        nexus_info->length);
5001    }
5002  if (nexus_info->cache == (PixelPacket *) NULL)
5003    {
5004      (void) ThrowMagickException(exception,GetMagickModule(),
5005        ResourceLimitError,"MemoryAllocationFailed","`%s'",
5006        cache_info->filename);
5007      return(MagickFalse);
5008    }
5009  return(MagickTrue);
5010}
5011
5012static PixelPacket *SetPixelCacheNexusPixels(const Image *image,
5013  const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
5014{
5015  CacheInfo
5016    *cache_info;
5017
5018  MagickBooleanType
5019    status;
5020
5021  MagickSizeType
5022    length,
5023    number_pixels;
5024
5025  cache_info=(CacheInfo *) image->cache;
5026  assert(cache_info->signature == MagickSignature);
5027  if (cache_info->type == UndefinedCache)
5028    return((PixelPacket *) NULL);
5029  nexus_info->region=(*region);
5030  if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
5031      (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
5032    {
5033      ssize_t
5034        x,
5035        y;
5036
5037      x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
5038      y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
5039      if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5040           (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
5041          ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
5042           ((nexus_info->region.width == cache_info->columns) ||
5043            ((nexus_info->region.width % cache_info->columns) == 0)))))
5044        {
5045          MagickOffsetType
5046            offset;
5047
5048          /*
5049            Pixels are accessed directly from memory.
5050          */
5051          offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5052            nexus_info->region.x;
5053          nexus_info->pixels=cache_info->pixels+offset;
5054          nexus_info->indexes=(IndexPacket *) NULL;
5055          if (cache_info->active_index_channel != MagickFalse)
5056            nexus_info->indexes=cache_info->indexes+offset;
5057          return(nexus_info->pixels);
5058        }
5059    }
5060  /*
5061    Pixels are stored in a cache region until they are synced to the cache.
5062  */
5063  number_pixels=(MagickSizeType) nexus_info->region.width*
5064    nexus_info->region.height;
5065  length=number_pixels*sizeof(PixelPacket);
5066  if (cache_info->active_index_channel != MagickFalse)
5067    length+=number_pixels*sizeof(IndexPacket);
5068  if (nexus_info->cache == (PixelPacket *) NULL)
5069    {
5070      nexus_info->length=length;
5071      status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5072      if (status == MagickFalse)
5073        {
5074          nexus_info->length=0;
5075          return((PixelPacket *) NULL);
5076        }
5077    }
5078  else
5079    if (nexus_info->length != length)
5080      {
5081        RelinquishCacheNexusPixels(nexus_info);
5082        nexus_info->length=length;
5083        status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5084        if (status == MagickFalse)
5085          {
5086            nexus_info->length=0;
5087            return((PixelPacket *) NULL);
5088          }
5089      }
5090  nexus_info->pixels=nexus_info->cache;
5091  nexus_info->indexes=(IndexPacket *) NULL;
5092  if (cache_info->active_index_channel != MagickFalse)
5093    nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
5094  return(nexus_info->pixels);
5095}
5096
5097/*
5098%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5099%                                                                             %
5100%                                                                             %
5101%                                                                             %
5102%   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                       %
5103%                                                                             %
5104%                                                                             %
5105%                                                                             %
5106%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5107%
5108%  SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5109%  pixel cache and returns the previous setting.  A virtual pixel is any pixel
5110%  access that is outside the boundaries of the image cache.
5111%
5112%  The format of the SetPixelCacheVirtualMethod() method is:
5113%
5114%      VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5115%        const VirtualPixelMethod virtual_pixel_method)
5116%
5117%  A description of each parameter follows:
5118%
5119%    o image: the image.
5120%
5121%    o virtual_pixel_method: choose the type of virtual pixel.
5122%
5123*/
5124MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5125  const VirtualPixelMethod virtual_pixel_method)
5126{
5127  CacheInfo
5128    *cache_info;
5129
5130  VirtualPixelMethod
5131    method;
5132
5133  assert(image != (Image *) NULL);
5134  assert(image->signature == MagickSignature);
5135  if (image->debug != MagickFalse)
5136    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5137  assert(image->cache != (Cache) NULL);
5138  cache_info=(CacheInfo *) image->cache;
5139  assert(cache_info->signature == MagickSignature);
5140  method=cache_info->virtual_pixel_method;
5141  cache_info->virtual_pixel_method=virtual_pixel_method;
5142  return(method);
5143}
5144
5145/*
5146%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5147%                                                                             %
5148%                                                                             %
5149%                                                                             %
5150+   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                   %
5151%                                                                             %
5152%                                                                             %
5153%                                                                             %
5154%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5155%
5156%  SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5157%  in-memory or disk cache.  The method returns MagickTrue if the pixel region
5158%  is synced, otherwise MagickFalse.
5159%
5160%  The format of the SyncAuthenticPixelCacheNexus() method is:
5161%
5162%      MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5163%        NexusInfo *nexus_info,ExceptionInfo *exception)
5164%
5165%  A description of each parameter follows:
5166%
5167%    o image: the image.
5168%
5169%    o nexus_info: the cache nexus to sync.
5170%
5171%    o exception: return any errors or warnings in this structure.
5172%
5173*/
5174MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5175  NexusInfo *nexus_info,ExceptionInfo *exception)
5176{
5177  CacheInfo
5178    *cache_info;
5179
5180  MagickBooleanType
5181    status;
5182
5183  /*
5184    Transfer pixels to the cache.
5185  */
5186  assert(image != (Image *) NULL);
5187  assert(image->signature == MagickSignature);
5188  if (image->cache == (Cache) NULL)
5189    ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5190  cache_info=(CacheInfo *) image->cache;
5191  assert(cache_info->signature == MagickSignature);
5192  if (cache_info->type == UndefinedCache)
5193    return(MagickFalse);
5194  if ((image->clip_mask != (Image *) NULL) &&
5195      (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5196    return(MagickFalse);
5197  if ((image->mask != (Image *) NULL) &&
5198      (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5199    return(MagickFalse);
5200  if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5201    return(MagickTrue);
5202  assert(cache_info->signature == MagickSignature);
5203  status=WritePixelCachePixels(cache_info,nexus_info,exception);
5204  if ((cache_info->active_index_channel != MagickFalse) &&
5205      (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
5206    return(MagickFalse);
5207  return(status);
5208}
5209
5210/*
5211%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5212%                                                                             %
5213%                                                                             %
5214%                                                                             %
5215+   S y n c A u t h e n t i c P i x e l C a c h e                             %
5216%                                                                             %
5217%                                                                             %
5218%                                                                             %
5219%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5220%
5221%  SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5222%  or disk cache.  The method returns MagickTrue if the pixel region is synced,
5223%  otherwise MagickFalse.
5224%
5225%  The format of the SyncAuthenticPixelsCache() method is:
5226%
5227%      MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5228%        ExceptionInfo *exception)
5229%
5230%  A description of each parameter follows:
5231%
5232%    o image: the image.
5233%
5234%    o exception: return any errors or warnings in this structure.
5235%
5236*/
5237static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5238  ExceptionInfo *exception)
5239{
5240  CacheInfo
5241    *cache_info;
5242
5243  const int
5244    id = GetOpenMPThreadId();
5245
5246  assert(image != (Image *) NULL);
5247  assert(image->signature == MagickSignature);
5248  assert(image->cache != (Cache) NULL);
5249  cache_info=(CacheInfo *) image->cache;
5250  assert(cache_info->signature == MagickSignature);
5251  assert(id < (int) cache_info->number_threads);
5252  return(SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5253    exception));
5254}
5255
5256/*
5257%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5258%                                                                             %
5259%                                                                             %
5260%                                                                             %
5261%   S y n c A u t h e n t i c P i x e l s                                     %
5262%                                                                             %
5263%                                                                             %
5264%                                                                             %
5265%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5266%
5267%  SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5268%  The method returns MagickTrue if the pixel region is flushed, otherwise
5269%  MagickFalse.
5270%
5271%  The format of the SyncAuthenticPixels() method is:
5272%
5273%      MagickBooleanType SyncAuthenticPixels(Image *image,
5274%        ExceptionInfo *exception)
5275%
5276%  A description of each parameter follows:
5277%
5278%    o image: the image.
5279%
5280%    o exception: return any errors or warnings in this structure.
5281%
5282*/
5283MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5284  ExceptionInfo *exception)
5285{
5286  CacheInfo
5287    *cache_info;
5288
5289  const int
5290    id = GetOpenMPThreadId();
5291
5292  assert(image != (Image *) NULL);
5293  assert(image->signature == MagickSignature);
5294  assert(image->cache != (Cache) NULL);
5295  cache_info=(CacheInfo *) image->cache;
5296  assert(cache_info->signature == MagickSignature);
5297  if (cache_info->methods.sync_authentic_pixels_handler !=
5298       (SyncAuthenticPixelsHandler) NULL)
5299    return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
5300  assert(id < (int) cache_info->number_threads);
5301  return(SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5302    exception));
5303}
5304
5305/*
5306%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5307%                                                                             %
5308%                                                                             %
5309%                                                                             %
5310+   W r i t e P i x e l C a c h e I n d e x e s                               %
5311%                                                                             %
5312%                                                                             %
5313%                                                                             %
5314%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5315%
5316%  WritePixelCacheIndexes() writes the colormap indexes to the specified
5317%  region of the pixel cache.
5318%
5319%  The format of the WritePixelCacheIndexes() method is:
5320%
5321%      MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5322%        NexusInfo *nexus_info,ExceptionInfo *exception)
5323%
5324%  A description of each parameter follows:
5325%
5326%    o cache_info: the pixel cache.
5327%
5328%    o nexus_info: the cache nexus to write the colormap indexes.
5329%
5330%    o exception: return any errors or warnings in this structure.
5331%
5332*/
5333static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5334  NexusInfo *nexus_info,ExceptionInfo *exception)
5335{
5336  MagickOffsetType
5337    count,
5338    offset;
5339
5340  MagickSizeType
5341    extent,
5342    length;
5343
5344  register const IndexPacket
5345    *restrict p;
5346
5347  register ssize_t
5348    y;
5349
5350  size_t
5351    rows;
5352
5353  if (cache_info->active_index_channel == MagickFalse)
5354    return(MagickFalse);
5355  if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5356    return(MagickTrue);
5357  offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5358    nexus_info->region.x;
5359  length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
5360  rows=nexus_info->region.height;
5361  extent=(MagickSizeType) length*rows;
5362  p=nexus_info->indexes;
5363  switch (cache_info->type)
5364  {
5365    case MemoryCache:
5366    case MapCache:
5367    {
5368      register IndexPacket
5369        *restrict q;
5370
5371      /*
5372        Write indexes to memory.
5373      */
5374      if ((cache_info->columns == nexus_info->region.width) &&
5375          (extent == (MagickSizeType) ((size_t) extent)))
5376        {
5377          length=extent;
5378          rows=1UL;
5379        }
5380      q=cache_info->indexes+offset;
5381      for (y=0; y < (ssize_t) rows; y++)
5382      {
5383        (void) memcpy(q,p,(size_t) length);
5384        p+=nexus_info->region.width;
5385        q+=cache_info->columns;
5386      }
5387      break;
5388    }
5389    case DiskCache:
5390    {
5391      /*
5392        Write indexes to disk.
5393      */
5394      if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5395        {
5396          ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5397            cache_info->cache_filename);
5398          return(MagickFalse);
5399        }
5400      if ((cache_info->columns == nexus_info->region.width) &&
5401          (extent <= MagickMaxBufferExtent))
5402        {
5403          length=extent;
5404          rows=1UL;
5405        }
5406      extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5407      for (y=0; y < (ssize_t) rows; y++)
5408      {
5409        count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5410          sizeof(PixelPacket)+offset*sizeof(*p),length,(const unsigned char *)
5411          p);
5412        if ((MagickSizeType) count < length)
5413          break;
5414        p+=nexus_info->region.width;
5415        offset+=cache_info->columns;
5416      }
5417      if (y < (ssize_t) rows)
5418        {
5419          ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5420            cache_info->cache_filename);
5421          return(MagickFalse);
5422        }
5423      break;
5424    }
5425    default:
5426      break;
5427  }
5428  if ((cache_info->debug != MagickFalse) &&
5429      (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5430    (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5431      "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5432      nexus_info->region.width,(double) nexus_info->region.height,(double)
5433      nexus_info->region.x,(double) nexus_info->region.y);
5434  return(MagickTrue);
5435}
5436
5437/*
5438%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5439%                                                                             %
5440%                                                                             %
5441%                                                                             %
5442+   W r i t e C a c h e P i x e l s                                           %
5443%                                                                             %
5444%                                                                             %
5445%                                                                             %
5446%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5447%
5448%  WritePixelCachePixels() writes image pixels to the specified region of the
5449%  pixel cache.
5450%
5451%  The format of the WritePixelCachePixels() method is:
5452%
5453%      MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5454%        NexusInfo *nexus_info,ExceptionInfo *exception)
5455%
5456%  A description of each parameter follows:
5457%
5458%    o cache_info: the pixel cache.
5459%
5460%    o nexus_info: the cache nexus to write the pixels.
5461%
5462%    o exception: return any errors or warnings in this structure.
5463%
5464*/
5465static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5466  NexusInfo *nexus_info,ExceptionInfo *exception)
5467{
5468  MagickOffsetType
5469    count,
5470    offset;
5471
5472  MagickSizeType
5473    extent,
5474    length;
5475
5476  register const PixelPacket
5477    *restrict p;
5478
5479  register ssize_t
5480    y;
5481
5482  size_t
5483    rows;
5484
5485  if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5486    return(MagickTrue);
5487  offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5488    nexus_info->region.x;
5489  length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
5490  rows=nexus_info->region.height;
5491  extent=length*rows;
5492  p=nexus_info->pixels;
5493  switch (cache_info->type)
5494  {
5495    case MemoryCache:
5496    case MapCache:
5497    {
5498      register PixelPacket
5499        *restrict q;
5500
5501      /*
5502        Write pixels to memory.
5503      */
5504      if ((cache_info->columns == nexus_info->region.width) &&
5505          (extent == (MagickSizeType) ((size_t) extent)))
5506        {
5507          length=extent;
5508          rows=1UL;
5509        }
5510      q=cache_info->pixels+offset;
5511      for (y=0; y < (ssize_t) rows; y++)
5512      {
5513        (void) memcpy(q,p,(size_t) length);
5514        p+=nexus_info->region.width;
5515        q+=cache_info->columns;
5516      }
5517      break;
5518    }
5519    case DiskCache:
5520    {
5521      /*
5522        Write pixels to disk.
5523      */
5524      if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5525        {
5526          ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5527            cache_info->cache_filename);
5528          return(MagickFalse);
5529        }
5530      if ((cache_info->columns == nexus_info->region.width) &&
5531          (extent <= MagickMaxBufferExtent))
5532        {
5533          length=extent;
5534          rows=1UL;
5535        }
5536      for (y=0; y < (ssize_t) rows; y++)
5537      {
5538        count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5539          sizeof(*p),length,(const unsigned char *) p);
5540        if ((MagickSizeType) count < length)
5541          break;
5542        p+=nexus_info->region.width;
5543        offset+=cache_info->columns;
5544      }
5545      if (y < (ssize_t) rows)
5546        {
5547          ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5548            cache_info->cache_filename);
5549          return(MagickFalse);
5550        }
5551      break;
5552    }
5553    default:
5554      break;
5555  }
5556  if ((cache_info->debug != MagickFalse) &&
5557      (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5558    (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5559      "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5560      nexus_info->region.width,(double) nexus_info->region.height,(double)
5561      nexus_info->region.x,(double) nexus_info->region.y);
5562  return(MagickTrue);
5563}
Note: See TracBrowser for help on using the repository browser.