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