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