MagickCore 6.9.13
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(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 (image->type != UndefinedType)
1941 image->type=UndefinedType;
1942 if (ValidatePixelCacheMorphology(image) == MagickFalse)
1943 {
1944 status=OpenPixelCache(image,IOMode,exception);
1945 cache_info=(CacheInfo *) image->cache;
1946 if (cache_info->file != -1)
1947 (void) ClosePixelCacheOnDisk(cache_info);
1948 }
1949 }
1950 UnlockSemaphoreInfo(image->semaphore);
1951 if (status == MagickFalse)
1952 return((Cache) NULL);
1953 return(image->cache);
1954}
1955
1956/*
1957%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1958% %
1959% %
1960% %
1961+ G e t I m a g e P i x e l C a c h e T y p e %
1962% %
1963% %
1964% %
1965%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1966%
1967% GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1968% DiskCache, MapCache, MemoryCache, or PingCache.
1969%
1970% The format of the GetImagePixelCacheType() method is:
1971%
1972% CacheType GetImagePixelCacheType(const Image *image)
1973%
1974% A description of each parameter follows:
1975%
1976% o image: the image.
1977%
1978*/
1979
1980MagickExport CacheType GetPixelCacheType(const Image *image)
1981{
1982 return(GetImagePixelCacheType(image));
1983}
1984
1985MagickExport CacheType GetImagePixelCacheType(const Image *image)
1986{
1987 CacheInfo
1988 *magick_restrict cache_info;
1989
1990 assert(image != (Image *) NULL);
1991 assert(image->signature == MagickCoreSignature);
1992 assert(image->cache != (Cache) NULL);
1993 cache_info=(CacheInfo *) image->cache;
1994 assert(cache_info->signature == MagickCoreSignature);
1995 return(cache_info->type);
1996}
1997
1998/*
1999%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2000% %
2001% %
2002% %
2003% G e t O n e A u t h e n t i c P i x e l %
2004% %
2005% %
2006% %
2007%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2008%
2009% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2010% location. The image background color is returned if an error occurs.
2011%
2012% The format of the GetOneAuthenticPixel() method is:
2013%
2014% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2015% const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
2016%
2017% A description of each parameter follows:
2018%
2019% o image: the image.
2020%
2021% o x,y: These values define the location of the pixel to return.
2022%
2023% o pixel: return a pixel at the specified (x,y) location.
2024%
2025% o exception: return any errors or warnings in this structure.
2026%
2027*/
2028MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2029 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
2030{
2031 CacheInfo
2032 *magick_restrict cache_info;
2033
2034 PixelPacket
2035 *magick_restrict pixels;
2036
2037 assert(image != (Image *) NULL);
2038 assert(image->signature == MagickCoreSignature);
2039 assert(image->cache != (Cache) NULL);
2040 cache_info=(CacheInfo *) image->cache;
2041 assert(cache_info->signature == MagickCoreSignature);
2042 *pixel=image->background_color;
2043 if (cache_info->methods.get_one_authentic_pixel_from_handler != (GetOneAuthenticPixelFromHandler) NULL)
2044 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,pixel,exception));
2045 pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2046 if (pixels == (PixelPacket *) NULL)
2047 return(MagickFalse);
2048 *pixel=(*pixels);
2049 return(MagickTrue);
2050}
2051
2052/*
2053%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2054% %
2055% %
2056% %
2057+ 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 %
2058% %
2059% %
2060% %
2061%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2062%
2063% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2064% location. The image background color is returned if an error occurs.
2065%
2066% The format of the GetOneAuthenticPixelFromCache() method is:
2067%
2068% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
2069% const ssize_t x,const ssize_t y,PixelPacket *pixel,
2070% ExceptionInfo *exception)
2071%
2072% A description of each parameter follows:
2073%
2074% o image: the image.
2075%
2076% o x,y: These values define the location of the pixel to return.
2077%
2078% o pixel: return a pixel at the specified (x,y) location.
2079%
2080% o exception: return any errors or warnings in this structure.
2081%
2082*/
2083static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
2084 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
2085{
2086 CacheInfo
2087 *magick_restrict cache_info;
2088
2089 const int
2090 id = GetOpenMPThreadId();
2091
2092 PixelPacket
2093 *magick_restrict pixels;
2094
2095 assert(image != (const Image *) NULL);
2096 assert(image->signature == MagickCoreSignature);
2097 assert(image->cache != (Cache) NULL);
2098 cache_info=(CacheInfo *) image->cache;
2099 assert(cache_info->signature == MagickCoreSignature);
2100 *pixel=image->background_color;
2101 assert(id < (int) cache_info->number_threads);
2102 pixels=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,
2103 cache_info->nexus_info[id],exception);
2104 if (pixels == (PixelPacket *) NULL)
2105 return(MagickFalse);
2106 *pixel=(*pixels);
2107 return(MagickTrue);
2108}
2109
2110/*
2111%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2112% %
2113% %
2114% %
2115% G e t O n e V i r t u a l M a g i c k P i x e l %
2116% %
2117% %
2118% %
2119%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2120%
2121% GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2122% location. The image background color is returned if an error occurs. If
2123% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2124%
2125% The format of the GetOneVirtualMagickPixel() method is:
2126%
2127% MagickBooleanType GetOneVirtualMagickPixel(const Image image,
2128% const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
2129% ExceptionInfo exception)
2130%
2131% A description of each parameter follows:
2132%
2133% o image: the image.
2134%
2135% o x,y: these values define the location of the pixel to return.
2136%
2137% o pixel: return a pixel at the specified (x,y) location.
2138%
2139% o exception: return any errors or warnings in this structure.
2140%
2141*/
2142MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
2143 const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
2144 ExceptionInfo *exception)
2145{
2146 CacheInfo
2147 *magick_restrict cache_info;
2148
2149 const int
2150 id = GetOpenMPThreadId();
2151
2152 const IndexPacket
2153 *magick_restrict indexes;
2154
2155 const PixelPacket
2156 *magick_restrict pixels;
2157
2158 assert(image != (const Image *) NULL);
2159 assert(image->signature == MagickCoreSignature);
2160 assert(image->cache != (Cache) NULL);
2161 cache_info=(CacheInfo *) image->cache;
2162 assert(cache_info->signature == MagickCoreSignature);
2163 assert(id < (int) cache_info->number_threads);
2164 pixels=GetVirtualPixelCacheNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2165 1UL,1UL,cache_info->nexus_info[id],exception);
2166 GetMagickPixelPacket(image,pixel);
2167 if (pixels == (const PixelPacket *) NULL)
2168 return(MagickFalse);
2169 indexes=GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]);
2170 SetMagickPixelPacket(image,pixels,indexes,pixel);
2171 return(MagickTrue);
2172}
2173
2174/*
2175%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2176% %
2177% %
2178% %
2179% G e t O n e V i r t u a l M e t h o d P i x e l %
2180% %
2181% %
2182% %
2183%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2184%
2185% GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2186% location as defined by specified pixel method. The image background color
2187% is returned if an error occurs. If you plan to modify the pixel, use
2188% GetOneAuthenticPixel() instead.
2189%
2190% The format of the GetOneVirtualMethodPixel() method is:
2191%
2192% MagickBooleanType GetOneVirtualMethodPixel(const Image image,
2193% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2194% const ssize_t y,Pixelpacket *pixel,ExceptionInfo exception)
2195%
2196% A description of each parameter follows:
2197%
2198% o image: the image.
2199%
2200% o virtual_pixel_method: the virtual pixel method.
2201%
2202% o x,y: These values define the location of the pixel to return.
2203%
2204% o pixel: return a pixel at the specified (x,y) location.
2205%
2206% o exception: return any errors or warnings in this structure.
2207%
2208*/
2209MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
2210 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2211 PixelPacket *pixel,ExceptionInfo *exception)
2212{
2213 CacheInfo
2214 *magick_restrict cache_info;
2215
2216 const int
2217 id = GetOpenMPThreadId();
2218
2219 const PixelPacket
2220 *magick_restrict pixels;
2221
2222 assert(image != (const Image *) NULL);
2223 assert(image->signature == MagickCoreSignature);
2224 assert(image->cache != (Cache) NULL);
2225 cache_info=(CacheInfo *) image->cache;
2226 assert(cache_info->signature == MagickCoreSignature);
2227 *pixel=image->background_color;
2228 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2229 (GetOneVirtualPixelFromHandler) NULL)
2230 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2231 virtual_pixel_method,x,y,pixel,exception));
2232 assert(id < (int) cache_info->number_threads);
2233 pixels=GetVirtualPixelCacheNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2234 cache_info->nexus_info[id],exception);
2235 if (pixels == (const PixelPacket *) NULL)
2236 return(MagickFalse);
2237 *pixel=(*pixels);
2238 return(MagickTrue);
2239}
2240
2241/*
2242%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2243% %
2244% %
2245% %
2246% G e t O n e V i r t u a l P i x e l %
2247% %
2248% %
2249% %
2250%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2251%
2252% GetOneVirtualPixel() returns a single virtual pixel at the specified
2253% (x,y) location. The image background color is returned if an error occurs.
2254% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2255%
2256% The format of the GetOneVirtualPixel() method is:
2257%
2258% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2259% const ssize_t y,PixelPacket *pixel,ExceptionInfo exception)
2260%
2261% A description of each parameter follows:
2262%
2263% o image: the image.
2264%
2265% o x,y: These values define the location of the pixel to return.
2266%
2267% o pixel: return a pixel at the specified (x,y) location.
2268%
2269% o exception: return any errors or warnings in this structure.
2270%
2271*/
2272MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
2273 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
2274{
2275 CacheInfo
2276 *magick_restrict cache_info;
2277
2278 const int
2279 id = GetOpenMPThreadId();
2280
2281 const PixelPacket
2282 *magick_restrict pixels;
2283
2284 assert(image != (const Image *) NULL);
2285 assert(image->signature == MagickCoreSignature);
2286 assert(image->cache != (Cache) NULL);
2287 cache_info=(CacheInfo *) image->cache;
2288 assert(cache_info->signature == MagickCoreSignature);
2289 *pixel=image->background_color;
2290 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2291 (GetOneVirtualPixelFromHandler) NULL)
2292 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2293 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
2294 assert(id < (int) cache_info->number_threads);
2295 pixels=GetVirtualPixelCacheNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2296 1UL,1UL,cache_info->nexus_info[id],exception);
2297 if (pixels == (const PixelPacket *) NULL)
2298 return(MagickFalse);
2299 *pixel=(*pixels);
2300 return(MagickTrue);
2301}
2302
2303/*
2304%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2305% %
2306% %
2307% %
2308+ 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 %
2309% %
2310% %
2311% %
2312%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2313%
2314% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2315% specified (x,y) location. The image background color is returned if an
2316% error occurs.
2317%
2318% The format of the GetOneVirtualPixelFromCache() method is:
2319%
2320% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
2321% const VirtualPixelPacket method,const ssize_t x,const ssize_t y,
2322% PixelPacket *pixel,ExceptionInfo *exception)
2323%
2324% A description of each parameter follows:
2325%
2326% o image: the image.
2327%
2328% o virtual_pixel_method: the virtual pixel method.
2329%
2330% o x,y: These values define the location of the pixel to return.
2331%
2332% o pixel: return a pixel at the specified (x,y) location.
2333%
2334% o exception: return any errors or warnings in this structure.
2335%
2336*/
2337static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
2338 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2339 PixelPacket *pixel,ExceptionInfo *exception)
2340{
2341 CacheInfo
2342 *magick_restrict cache_info;
2343
2344 const int
2345 id = GetOpenMPThreadId();
2346
2347 const PixelPacket
2348 *magick_restrict pixels;
2349
2350 assert(image != (const Image *) NULL);
2351 assert(image->signature == MagickCoreSignature);
2352 assert(image->cache != (Cache) NULL);
2353 cache_info=(CacheInfo *) image->cache;
2354 assert(cache_info->signature == MagickCoreSignature);
2355 assert(id < (int) cache_info->number_threads);
2356 *pixel=image->background_color;
2357 pixels=GetVirtualPixelCacheNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2358 cache_info->nexus_info[id],exception);
2359 if (pixels == (const PixelPacket *) NULL)
2360 return(MagickFalse);
2361 *pixel=(*pixels);
2362 return(MagickTrue);
2363}
2364
2365/*
2366%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2367% %
2368% %
2369% %
2370+ G e t P i x e l C a c h e C h a n n e l s %
2371% %
2372% %
2373% %
2374%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2375%
2376% GetPixelCacheChannels() returns the number of pixel channels associated
2377% with this instance of the pixel cache.
2378%
2379% The format of the GetPixelCacheChannels() method is:
2380%
2381% size_t GetPixelCacheChannels(Cache cache)
2382%
2383% A description of each parameter follows:
2384%
2385% o type: GetPixelCacheChannels returns DirectClass or PseudoClass.
2386%
2387% o cache: the pixel cache.
2388%
2389*/
2390MagickExport size_t GetPixelCacheChannels(const Cache cache)
2391{
2392 CacheInfo
2393 *magick_restrict cache_info;
2394
2395 assert(cache != (Cache) NULL);
2396 cache_info=(CacheInfo *) cache;
2397 assert(cache_info->signature == MagickCoreSignature);
2398 if (IsEventLogging() != MagickFalse)
2399 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2400 cache_info->filename);
2401 return(cache_info->channels);
2402}
2403
2404/*
2405%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2406% %
2407% %
2408% %
2409+ G e t P i x e l C a c h e C o l o r s p a c e %
2410% %
2411% %
2412% %
2413%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2414%
2415% GetPixelCacheColorspace() returns the colorspace of the pixel cache.
2416%
2417% The format of the GetPixelCacheColorspace() method is:
2418%
2419% Colorspace GetPixelCacheColorspace(const Cache cache)
2420%
2421% A description of each parameter follows:
2422%
2423% o cache: the pixel cache.
2424%
2425*/
2426MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
2427{
2428 CacheInfo
2429 *magick_restrict cache_info;
2430
2431 assert(cache != (Cache) NULL);
2432 cache_info=(CacheInfo *) cache;
2433 assert(cache_info->signature == MagickCoreSignature);
2434 if (IsEventLogging() != MagickFalse)
2435 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2436 cache_info->filename);
2437 return(cache_info->colorspace);
2438}
2439
2440/*
2441%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2442% %
2443% %
2444% %
2445+ G e t P i x e l C a c h e F i l e n a m e %
2446% %
2447% %
2448% %
2449%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2450%
2451% GetPixelCacheFilename() returns the filename associated with the pixel
2452% cache.
2453%
2454% The format of the GetPixelCacheFilename() method is:
2455%
2456% const char *GetPixelCacheFilename(const Image *image)
2457%
2458% A description of each parameter follows:
2459%
2460% o image: the image.
2461%
2462*/
2463MagickExport const char *GetPixelCacheFilename(const Image *image)
2464{
2465 CacheInfo
2466 *magick_restrict cache_info;
2467
2468 assert(image != (const Image *) NULL);
2469 assert(image->signature == MagickCoreSignature);
2470 assert(image->cache != (Cache) NULL);
2471 cache_info=(CacheInfo *) image->cache;
2472 assert(cache_info->signature == MagickCoreSignature);
2473 return(cache_info->cache_filename);
2474}
2475
2476/*
2477%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2478% %
2479% %
2480% %
2481+ G e t P i x e l C a c h e M e t h o d s %
2482% %
2483% %
2484% %
2485%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2486%
2487% GetPixelCacheMethods() initializes the CacheMethods structure.
2488%
2489% The format of the GetPixelCacheMethods() method is:
2490%
2491% void GetPixelCacheMethods(CacheMethods *cache_methods)
2492%
2493% A description of each parameter follows:
2494%
2495% o cache_methods: Specifies a pointer to a CacheMethods structure.
2496%
2497*/
2498MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
2499{
2500 assert(cache_methods != (CacheMethods *) NULL);
2501 (void) memset(cache_methods,0,sizeof(*cache_methods));
2502 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2503 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2504 cache_methods->get_virtual_indexes_from_handler=GetVirtualIndexesFromCache;
2505 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2506 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2507 cache_methods->get_authentic_indexes_from_handler=
2508 GetAuthenticIndexesFromCache;
2509 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2510 cache_methods->get_one_authentic_pixel_from_handler=
2511 GetOneAuthenticPixelFromCache;
2512 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2513 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2514 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2515}
2516
2517/*
2518%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2519% %
2520% %
2521% %
2522+ G e t P i x e l C a c h e N e x u s E x t e n t %
2523% %
2524% %
2525% %
2526%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2527%
2528% GetPixelCacheNexusExtent() returns the extent of the pixels associated with
2529% the last call to SetPixelCacheNexusPixels() or GetPixelCacheNexusPixels().
2530%
2531% The format of the GetPixelCacheNexusExtent() method is:
2532%
2533% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2534% NexusInfo *nexus_info)
2535%
2536% A description of each parameter follows:
2537%
2538% o nexus_info: the nexus info.
2539%
2540*/
2541MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2542 NexusInfo *nexus_info)
2543{
2544 CacheInfo
2545 *magick_restrict cache_info;
2546
2547 MagickSizeType
2548 extent;
2549
2550 assert(cache != NULL);
2551 cache_info=(CacheInfo *) cache;
2552 assert(cache_info->signature == MagickCoreSignature);
2553 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2554 if (extent == 0)
2555 return((MagickSizeType) cache_info->columns*cache_info->rows);
2556 return(extent);
2557}
2558
2559/*
2560%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2561% %
2562% %
2563% %
2564+ G e t P i x e l C a c h e P i x e l s %
2565% %
2566% %
2567% %
2568%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2569%
2570% GetPixelCachePixels() returns the pixels associated with the specified image.
2571%
2572% The format of the GetPixelCachePixels() method is:
2573%
2574% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2575% ExceptionInfo *exception)
2576%
2577% A description of each parameter follows:
2578%
2579% o image: the image.
2580%
2581% o length: the pixel cache length.
2582%
2583% o exception: return any errors or warnings in this structure.
2584%
2585*/
2586MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2587 ExceptionInfo *exception)
2588{
2589 CacheInfo
2590 *magick_restrict cache_info;
2591
2592 assert(image != (const Image *) NULL);
2593 assert(image->signature == MagickCoreSignature);
2594 assert(image->cache != (Cache) NULL);
2595 assert(length != (MagickSizeType *) NULL);
2596 assert(exception != (ExceptionInfo *) NULL);
2597 assert(exception->signature == MagickCoreSignature);
2598 cache_info=(CacheInfo *) image->cache;
2599 assert(cache_info->signature == MagickCoreSignature);
2600 (void) exception;
2601 *length=cache_info->length;
2602 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2603 return((void *) NULL);
2604 return((void *) cache_info->pixels);
2605}
2606
2607/*
2608%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2609% %
2610% %
2611% %
2612+ 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 %
2613% %
2614% %
2615% %
2616%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2617%
2618% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2619%
2620% The format of the GetPixelCacheStorageClass() method is:
2621%
2622% ClassType GetPixelCacheStorageClass(Cache cache)
2623%
2624% A description of each parameter follows:
2625%
2626% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2627%
2628% o cache: the pixel cache.
2629%
2630*/
2631MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
2632{
2633 CacheInfo
2634 *magick_restrict cache_info;
2635
2636 assert(cache != (Cache) NULL);
2637 cache_info=(CacheInfo *) cache;
2638 assert(cache_info->signature == MagickCoreSignature);
2639 if (IsEventLogging() != MagickFalse)
2640 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2641 cache_info->filename);
2642 return(cache_info->storage_class);
2643}
2644
2645/*
2646%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2647% %
2648% %
2649% %
2650+ G e t P i x e l C a c h e T i l e S i z e %
2651% %
2652% %
2653% %
2654%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2655%
2656% GetPixelCacheTileSize() returns the pixel cache tile size.
2657%
2658% The format of the GetPixelCacheTileSize() method is:
2659%
2660% void GetPixelCacheTileSize(const Image *image,size_t *width,
2661% size_t *height)
2662%
2663% A description of each parameter follows:
2664%
2665% o image: the image.
2666%
2667% o width: the optimize cache tile width in pixels.
2668%
2669% o height: the optimize cache tile height in pixels.
2670%
2671*/
2672MagickExport void GetPixelCacheTileSize(const Image *image,size_t *width,
2673 size_t *height)
2674{
2675 assert(image != (Image *) NULL);
2676 assert(image->signature == MagickCoreSignature);
2677 if (IsEventLogging() != MagickFalse)
2678 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2679 *width=2048UL/sizeof(PixelPacket);
2680 if (GetImagePixelCacheType(image) == DiskCache)
2681 *width=8192UL/sizeof(PixelPacket);
2682 *height=(*width);
2683}
2684
2685/*
2686%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2687% %
2688% %
2689% %
2690+ 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 %
2691% %
2692% %
2693% %
2694%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2695%
2696% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2697% pixel cache. A virtual pixel is any pixel access that is outside the
2698% boundaries of the image cache.
2699%
2700% The format of the GetPixelCacheVirtualMethod() method is:
2701%
2702% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2703%
2704% A description of each parameter follows:
2705%
2706% o image: the image.
2707%
2708*/
2709MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2710{
2711 CacheInfo
2712 *magick_restrict cache_info;
2713
2714 assert(image != (Image *) NULL);
2715 assert(image->signature == MagickCoreSignature);
2716 assert(image->cache != (Cache) NULL);
2717 cache_info=(CacheInfo *) image->cache;
2718 assert(cache_info->signature == MagickCoreSignature);
2719 return(cache_info->virtual_pixel_method);
2720}
2721
2722/*
2723%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2724% %
2725% %
2726% %
2727+ 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 %
2728% %
2729% %
2730% %
2731%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2732%
2733% GetVirtualIndexesFromCache() returns the indexes associated with the last
2734% call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2735%
2736% The format of the GetVirtualIndexesFromCache() method is:
2737%
2738% IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2739%
2740% A description of each parameter follows:
2741%
2742% o image: the image.
2743%
2744*/
2745static const IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2746{
2747 CacheInfo
2748 *magick_restrict cache_info;
2749
2750 const int
2751 id = GetOpenMPThreadId();
2752
2753 assert(image != (const Image *) NULL);
2754 assert(image->signature == MagickCoreSignature);
2755 assert(image->cache != (Cache) NULL);
2756 cache_info=(CacheInfo *) image->cache;
2757 assert(cache_info->signature == MagickCoreSignature);
2758 assert(id < (int) cache_info->number_threads);
2759 return(GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]));
2760}
2761
2762/*
2763%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2764% %
2765% %
2766% %
2767+ 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 %
2768% %
2769% %
2770% %
2771%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2772%
2773% GetVirtualIndexesFromNexus() returns the indexes associated with the
2774% specified cache nexus.
2775%
2776% The format of the GetVirtualIndexesFromNexus() method is:
2777%
2778% const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2779% NexusInfo *nexus_info)
2780%
2781% A description of each parameter follows:
2782%
2783% o cache: the pixel cache.
2784%
2785% o nexus_info: the cache nexus to return the colormap indexes.
2786%
2787*/
2788MagickExport const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2789 NexusInfo *nexus_info)
2790{
2791 CacheInfo
2792 *magick_restrict cache_info;
2793
2794 assert(cache != (Cache) NULL);
2795 cache_info=(CacheInfo *) cache;
2796 assert(cache_info->signature == MagickCoreSignature);
2797 if (cache_info->storage_class == UndefinedClass)
2798 return((IndexPacket *) NULL);
2799 return(nexus_info->indexes);
2800}
2801
2802/*
2803%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2804% %
2805% %
2806% %
2807% G e t V i r t u a l I n d e x Q u e u e %
2808% %
2809% %
2810% %
2811%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2812%
2813% GetVirtualIndexQueue() returns the virtual black channel or the
2814% colormap indexes associated with the last call to QueueAuthenticPixels() or
2815% GetVirtualPixels(). NULL is returned if the black channel or colormap
2816% indexes are not available.
2817%
2818% The format of the GetVirtualIndexQueue() method is:
2819%
2820% const IndexPacket *GetVirtualIndexQueue(const Image *image)
2821%
2822% A description of each parameter follows:
2823%
2824% o image: the image.
2825%
2826*/
2827MagickExport const IndexPacket *GetVirtualIndexQueue(const Image *image)
2828{
2829 CacheInfo
2830 *magick_restrict cache_info;
2831
2832 const int
2833 id = GetOpenMPThreadId();
2834
2835 assert(image != (const Image *) NULL);
2836 assert(image->signature == MagickCoreSignature);
2837 assert(image->cache != (Cache) NULL);
2838 cache_info=(CacheInfo *) image->cache;
2839 assert(cache_info->signature == MagickCoreSignature);
2840 if (cache_info->methods.get_virtual_indexes_from_handler !=
2841 (GetVirtualIndexesFromHandler) NULL)
2842 {
2843 const IndexPacket
2844 *indexes;
2845
2846 indexes=cache_info->methods.get_virtual_indexes_from_handler(image);
2847 if (indexes != (IndexPacket *) NULL)
2848 return(indexes);
2849 }
2850 assert(id < (int) cache_info->number_threads);
2851 return(GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]));
2852}
2853
2854/*
2855%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2856% %
2857% %
2858% %
2859+ 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 %
2860% %
2861% %
2862% %
2863%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2864%
2865% GetVirtualPixelCacheNexus() gets virtual pixels from the in-memory or disk
2866% pixel cache as defined by the geometry parameters. A pointer to the pixels
2867% is returned if the pixels are transferred, otherwise a NULL is returned.
2868%
2869% The format of the GetVirtualPixelCacheNexus() method is:
2870%
2871% PixelPacket *GetVirtualPixelCacheNexus(const Image *image,
2872% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2873% const size_t columns,const size_t rows,NexusInfo *nexus_info,
2874% ExceptionInfo *exception)
2875%
2876% A description of each parameter follows:
2877%
2878% o image: the image.
2879%
2880% o virtual_pixel_method: the virtual pixel method.
2881%
2882% o x,y,columns,rows: These values define the perimeter of a region of
2883% pixels.
2884%
2885% o nexus_info: the cache nexus to acquire.
2886%
2887% o exception: return any errors or warnings in this structure.
2888%
2889*/
2890
2891static ssize_t
2892 DitherMatrix[64] =
2893 {
2894 0, 48, 12, 60, 3, 51, 15, 63,
2895 32, 16, 44, 28, 35, 19, 47, 31,
2896 8, 56, 4, 52, 11, 59, 7, 55,
2897 40, 24, 36, 20, 43, 27, 39, 23,
2898 2, 50, 14, 62, 1, 49, 13, 61,
2899 34, 18, 46, 30, 33, 17, 45, 29,
2900 10, 58, 6, 54, 9, 57, 5, 53,
2901 42, 26, 38, 22, 41, 25, 37, 21
2902 };
2903
2904static inline ssize_t DitherX(const ssize_t x,const size_t columns)
2905{
2906 ssize_t
2907 index;
2908
2909 index=x+DitherMatrix[x & 0x07]-32L;
2910 if (index < 0L)
2911 return(0L);
2912 if (index >= (ssize_t) columns)
2913 return((ssize_t) columns-1L);
2914 return(index);
2915}
2916
2917static inline ssize_t DitherY(const ssize_t y,const size_t rows)
2918{
2919 ssize_t
2920 index;
2921
2922 index=y+DitherMatrix[y & 0x07]-32L;
2923 if (index < 0L)
2924 return(0L);
2925 if (index >= (ssize_t) rows)
2926 return((ssize_t) rows-1L);
2927 return(index);
2928}
2929
2930static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
2931{
2932 if (x < 0L)
2933 return(0L);
2934 if (x >= (ssize_t) columns)
2935 return((ssize_t) (columns-1));
2936 return(x);
2937}
2938
2939static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
2940{
2941 if (y < 0L)
2942 return(0L);
2943 if (y >= (ssize_t) rows)
2944 return((ssize_t) (rows-1));
2945 return(y);
2946}
2947
2948static inline MagickBooleanType IsOffsetOverflow(const ssize_t x,
2949 const ssize_t y)
2950{
2951 if (((y > 0) && (x > (MAGICK_SSIZE_MAX-y))) ||
2952 ((y < 0) && (x < (MAGICK_SSIZE_MIN-y))))
2953 return(MagickFalse);
2954 return(MagickTrue);
2955}
2956
2957static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
2958{
2959 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
2960}
2961
2962static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
2963{
2964 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
2965}
2966
2967static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2968 const size_t extent)
2969{
2970 MagickModulo
2971 modulo;
2972
2973 modulo.quotient=offset;
2974 modulo.remainder=0;
2975 if (extent != 0)
2976 {
2977 modulo.quotient=offset/((ssize_t) extent);
2978 modulo.remainder=offset % ((ssize_t) extent);
2979 }
2980 if ((modulo.remainder != 0) && ((offset ^ ((ssize_t) extent)) < 0))
2981 {
2982 modulo.quotient-=1;
2983 modulo.remainder+=((ssize_t) extent);
2984 }
2985 return(modulo);
2986}
2987
2988MagickExport const PixelPacket *GetVirtualPixelCacheNexus(const Image *image,
2989 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2990 const size_t columns,const size_t rows,NexusInfo *nexus_info,
2991 ExceptionInfo *exception)
2992{
2993 CacheInfo
2994 *magick_restrict cache_info;
2995
2996 const IndexPacket
2997 *magick_restrict virtual_indexes;
2998
2999 const PixelPacket
3000 *magick_restrict p;
3001
3002 IndexPacket
3003 virtual_index,
3004 *magick_restrict indexes;
3005
3006 MagickOffsetType
3007 offset;
3008
3009 MagickSizeType
3010 length,
3011 number_pixels;
3012
3013 NexusInfo
3014 *magick_restrict virtual_nexus;
3015
3016 PixelPacket
3017 *magick_restrict pixels,
3018 *magick_restrict q,
3019 virtual_pixel;
3020
3021 ssize_t
3022 u,
3023 v;
3024
3025 /*
3026 Acquire pixels.
3027 */
3028 assert(image != (const Image *) NULL);
3029 assert(image->signature == MagickCoreSignature);
3030 assert(image->cache != (Cache) NULL);
3031 cache_info=(CacheInfo *) image->cache;
3032 assert(cache_info->signature == MagickCoreSignature);
3033 if (cache_info->type == UndefinedCache)
3034 return((const PixelPacket *) NULL);
3035#if defined(MAGICKCORE_OPENCL_SUPPORT)
3036 CopyOpenCLBuffer(cache_info);
3037#endif
3038 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,x,y,columns,rows,
3039 (image->clip_mask != (Image *) NULL) || (image->mask != (Image *) NULL) ?
3040 MagickTrue : MagickFalse,nexus_info,exception);
3041 if (pixels == (PixelPacket *) NULL)
3042 return((const PixelPacket *) NULL);
3043 if (IsValidPixelOffset(nexus_info->region.y,cache_info->columns) == MagickFalse)
3044 return((const PixelPacket *) NULL);
3045 offset=nexus_info->region.y*(MagickOffsetType) cache_info->columns;
3046 if (IsOffsetOverflow(offset,nexus_info->region.x) == MagickFalse)
3047 return((const PixelPacket *) NULL);
3048 offset+=nexus_info->region.x;
3049 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3050 nexus_info->region.width-1L;
3051 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3052 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
3053 if ((x >= 0) && ((x+(ssize_t) columns) <= (ssize_t) cache_info->columns) &&
3054 (y >= 0) && ((y+(ssize_t) rows) <= (ssize_t) cache_info->rows))
3055 {
3056 MagickBooleanType
3057 status;
3058
3059 /*
3060 Pixel request is inside cache extents.
3061 */
3062 if (nexus_info->authentic_pixel_cache != MagickFalse)
3063 return(pixels);
3064 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3065 if (status == MagickFalse)
3066 return((const PixelPacket *) NULL);
3067 if ((cache_info->storage_class == PseudoClass) ||
3068 (cache_info->colorspace == CMYKColorspace))
3069 {
3070 status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
3071 if (status == MagickFalse)
3072 return((const PixelPacket *) NULL);
3073 }
3074 return(pixels);
3075 }
3076 /*
3077 Pixel request is outside cache extents.
3078 */
3079 virtual_nexus=nexus_info->virtual_nexus;
3080 q=pixels;
3081 indexes=nexus_info->indexes;
3082 switch (virtual_pixel_method)
3083 {
3084 case BlackVirtualPixelMethod:
3085 {
3086 SetPixelRed(&virtual_pixel,0);
3087 SetPixelGreen(&virtual_pixel,0);
3088 SetPixelBlue(&virtual_pixel,0);
3089 SetPixelOpacity(&virtual_pixel,OpaqueOpacity);
3090 break;
3091 }
3092 case GrayVirtualPixelMethod:
3093 {
3094 SetPixelRed(&virtual_pixel,QuantumRange/2);
3095 SetPixelGreen(&virtual_pixel,QuantumRange/2);
3096 SetPixelBlue(&virtual_pixel,QuantumRange/2);
3097 SetPixelOpacity(&virtual_pixel,OpaqueOpacity);
3098 break;
3099 }
3100 case TransparentVirtualPixelMethod:
3101 {
3102 SetPixelRed(&virtual_pixel,0);
3103 SetPixelGreen(&virtual_pixel,0);
3104 SetPixelBlue(&virtual_pixel,0);
3105 SetPixelOpacity(&virtual_pixel,TransparentOpacity);
3106 break;
3107 }
3108 case MaskVirtualPixelMethod:
3109 case WhiteVirtualPixelMethod:
3110 {
3111 SetPixelRed(&virtual_pixel,QuantumRange);
3112 SetPixelGreen(&virtual_pixel,QuantumRange);
3113 SetPixelBlue(&virtual_pixel,QuantumRange);
3114 SetPixelOpacity(&virtual_pixel,OpaqueOpacity);
3115 break;
3116 }
3117 default:
3118 {
3119 virtual_pixel=image->background_color;
3120 break;
3121 }
3122 }
3123 virtual_index=(IndexPacket) 0;
3124 for (v=0; v < (ssize_t) rows; v++)
3125 {
3126 ssize_t
3127 y_offset;
3128
3129 y_offset=y+v;
3130 if ((virtual_pixel_method == EdgeVirtualPixelMethod) ||
3131 (virtual_pixel_method == UndefinedVirtualPixelMethod))
3132 y_offset=EdgeY(y_offset,cache_info->rows);
3133 for (u=0; u < (ssize_t) columns; u+=(ssize_t) length)
3134 {
3135 ssize_t
3136 x_offset;
3137
3138 x_offset=x+u;
3139 length=(MagickSizeType) MagickMin((ssize_t) cache_info->columns-x_offset,
3140 (ssize_t) columns-u);
3141 if (((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns)) ||
3142 ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows)) ||
3143 (length == 0))
3144 {
3145 MagickModulo
3146 x_modulo,
3147 y_modulo;
3148
3149 /*
3150 Transfer a single pixel.
3151 */
3152 length=(MagickSizeType) 1;
3153 switch (virtual_pixel_method)
3154 {
3155 case BackgroundVirtualPixelMethod:
3156 case ConstantVirtualPixelMethod:
3157 case BlackVirtualPixelMethod:
3158 case GrayVirtualPixelMethod:
3159 case TransparentVirtualPixelMethod:
3160 case MaskVirtualPixelMethod:
3161 case WhiteVirtualPixelMethod:
3162 {
3163 p=(&virtual_pixel);
3164 virtual_indexes=(&virtual_index);
3165 break;
3166 }
3167 case EdgeVirtualPixelMethod:
3168 default:
3169 {
3170 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3171 EdgeX(x_offset,cache_info->columns),
3172 EdgeY(y_offset,cache_info->rows),1UL,1UL,virtual_nexus,
3173 exception);
3174 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3175 virtual_nexus);
3176 break;
3177 }
3178 case RandomVirtualPixelMethod:
3179 {
3180 if (cache_info->random_info == (RandomInfo *) NULL)
3181 cache_info->random_info=AcquireRandomInfo();
3182 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3183 RandomX(cache_info->random_info,cache_info->columns),
3184 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
3185 virtual_nexus,exception);
3186 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3187 virtual_nexus);
3188 break;
3189 }
3190 case DitherVirtualPixelMethod:
3191 {
3192 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3193 DitherX(x_offset,cache_info->columns),
3194 DitherY(y_offset,cache_info->rows),1UL,1UL,virtual_nexus,
3195 exception);
3196 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3197 virtual_nexus);
3198 break;
3199 }
3200 case TileVirtualPixelMethod:
3201 {
3202 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
3203 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
3204 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3205 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus,
3206 exception);
3207 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3208 virtual_nexus);
3209 break;
3210 }
3211 case MirrorVirtualPixelMethod:
3212 {
3213 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
3214 if ((x_modulo.quotient & 0x01) == 1L)
3215 x_modulo.remainder=(ssize_t) cache_info->columns-
3216 x_modulo.remainder-1L;
3217 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
3218 if ((y_modulo.quotient & 0x01) == 1L)
3219 y_modulo.remainder=(ssize_t) cache_info->rows-
3220 y_modulo.remainder-1L;
3221 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3222 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus,
3223 exception);
3224 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3225 virtual_nexus);
3226 break;
3227 }
3228 case CheckerTileVirtualPixelMethod:
3229 {
3230 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
3231 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
3232 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3233 {
3234 p=(&virtual_pixel);
3235 virtual_indexes=(&virtual_index);
3236 break;
3237 }
3238 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3239 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus,
3240 exception);
3241 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3242 virtual_nexus);
3243 break;
3244 }
3245 case HorizontalTileVirtualPixelMethod:
3246 {
3247 if ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows))
3248 {
3249 p=(&virtual_pixel);
3250 virtual_indexes=(&virtual_index);
3251 break;
3252 }
3253 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
3254 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
3255 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3256 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus,
3257 exception);
3258 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3259 virtual_nexus);
3260 break;
3261 }
3262 case VerticalTileVirtualPixelMethod:
3263 {
3264 if ((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns))
3265 {
3266 p=(&virtual_pixel);
3267 virtual_indexes=(&virtual_index);
3268 break;
3269 }
3270 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
3271 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
3272 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3273 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus,
3274 exception);
3275 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3276 virtual_nexus);
3277 break;
3278 }
3279 case HorizontalTileEdgeVirtualPixelMethod:
3280 {
3281 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
3282 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3283 x_modulo.remainder,EdgeY(y_offset,cache_info->rows),1UL,1UL,
3284 virtual_nexus,exception);
3285 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3286 virtual_nexus);
3287 break;
3288 }
3289 case VerticalTileEdgeVirtualPixelMethod:
3290 {
3291 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
3292 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3293 EdgeX(x_offset,cache_info->columns),y_modulo.remainder,1UL,1UL,
3294 virtual_nexus,exception);
3295 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3296 virtual_nexus);
3297 break;
3298 }
3299 }
3300 if (p == (const PixelPacket *) NULL)
3301 break;
3302 *q++=(*p);
3303 if ((indexes != (IndexPacket *) NULL) &&
3304 (virtual_indexes != (const IndexPacket *) NULL))
3305 *indexes++=(*virtual_indexes);
3306 continue;
3307 }
3308 /*
3309 Transfer a run of pixels.
3310 */
3311 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,x_offset,y_offset,
3312 (size_t) length,1UL,virtual_nexus,exception);
3313 if (p == (const PixelPacket *) NULL)
3314 break;
3315 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,virtual_nexus);
3316 (void) memcpy(q,p,(size_t) length*sizeof(*p));
3317 q+=(ptrdiff_t) length;
3318 if ((indexes != (IndexPacket *) NULL) &&
3319 (virtual_indexes != (const IndexPacket *) NULL))
3320 {
3321 (void) memcpy(indexes,virtual_indexes,(size_t) length*
3322 sizeof(*virtual_indexes));
3323 indexes+=length;
3324 }
3325 }
3326 if (u < (ssize_t) columns)
3327 break;
3328 }
3329 /*
3330 Free resources.
3331 */
3332 if (v < (ssize_t) rows)
3333 return((const PixelPacket *) NULL);
3334 return(pixels);
3335}
3336
3337/*
3338%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3339% %
3340% %
3341% %
3342+ G e t V i r t u a l P i x e l C a c h e %
3343% %
3344% %
3345% %
3346%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3347%
3348% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3349% cache as defined by the geometry parameters. A pointer to the pixels
3350% is returned if the pixels are transferred, otherwise a NULL is returned.
3351%
3352% The format of the GetVirtualPixelCache() method is:
3353%
3354% const PixelPacket *GetVirtualPixelCache(const Image *image,
3355% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3356% const ssize_t y,const size_t columns,const size_t rows,
3357% ExceptionInfo *exception)
3358%
3359% A description of each parameter follows:
3360%
3361% o image: the image.
3362%
3363% o virtual_pixel_method: the virtual pixel method.
3364%
3365% o x,y,columns,rows: These values define the perimeter of a region of
3366% pixels.
3367%
3368% o exception: return any errors or warnings in this structure.
3369%
3370*/
3371static const PixelPacket *GetVirtualPixelCache(const Image *image,
3372 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3373 const size_t columns,const size_t rows,ExceptionInfo *exception)
3374{
3375 CacheInfo
3376 *magick_restrict cache_info;
3377
3378 const int
3379 id = GetOpenMPThreadId();
3380
3381 assert(image != (const Image *) NULL);
3382 assert(image->signature == MagickCoreSignature);
3383 assert(image->cache != (Cache) NULL);
3384 cache_info=(CacheInfo *) image->cache;
3385 assert(cache_info->signature == MagickCoreSignature);
3386 assert(id < (int) cache_info->number_threads);
3387 return(GetVirtualPixelCacheNexus(image,virtual_pixel_method,x,y,columns,rows,
3388 cache_info->nexus_info[id],exception));
3389}
3390
3391/*
3392%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3393% %
3394% %
3395% %
3396% G e t V i r t u a l P i x e l Q u e u e %
3397% %
3398% %
3399% %
3400%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3401%
3402% GetVirtualPixelQueue() returns the virtual pixels associated with the
3403% last call to QueueAuthenticPixels() or GetVirtualPixels().
3404%
3405% The format of the GetVirtualPixelQueue() method is:
3406%
3407% const PixelPacket *GetVirtualPixelQueue(const Image image)
3408%
3409% A description of each parameter follows:
3410%
3411% o image: the image.
3412%
3413*/
3414MagickExport const PixelPacket *GetVirtualPixelQueue(const Image *image)
3415{
3416 CacheInfo
3417 *magick_restrict cache_info;
3418
3419 const int
3420 id = GetOpenMPThreadId();
3421
3422 assert(image != (const Image *) NULL);
3423 assert(image->signature == MagickCoreSignature);
3424 assert(image->cache != (Cache) NULL);
3425 cache_info=(CacheInfo *) image->cache;
3426 assert(cache_info->signature == MagickCoreSignature);
3427 if (cache_info->methods.get_virtual_pixels_handler !=
3428 (GetVirtualPixelsHandler) NULL)
3429 return(cache_info->methods.get_virtual_pixels_handler(image));
3430 assert(id < (int) cache_info->number_threads);
3431 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3432}
3433
3434/*
3435%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3436% %
3437% %
3438% %
3439% G e t V i r t u a l P i x e l s %
3440% %
3441% %
3442% %
3443%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3444%
3445% GetVirtualPixels() returns an immutable pixel region. If the
3446% region is successfully accessed, a pointer to it is returned, otherwise
3447% NULL is returned. The returned pointer may point to a temporary working
3448% copy of the pixels or it may point to the original pixels in memory.
3449% Performance is maximized if the selected region is part of one row, or one
3450% or more full rows, since there is opportunity to access the pixels in-place
3451% (without a copy) if the image is in memory, or in a memory-mapped file. The
3452% returned pointer must *never* be deallocated by the user.
3453%
3454% Pixels accessed via the returned pointer represent a simple array of type
3455% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
3456% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access
3457% the black color component or to obtain the colormap indexes (of type
3458% IndexPacket) corresponding to the region.
3459%
3460% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3461%
3462% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3463% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3464% GetCacheViewAuthenticPixels() instead.
3465%
3466% The format of the GetVirtualPixels() method is:
3467%
3468% const PixelPacket *GetVirtualPixels(const Image *image,const ssize_t x,
3469% const ssize_t y,const size_t columns,const size_t rows,
3470% ExceptionInfo *exception)
3471%
3472% A description of each parameter follows:
3473%
3474% o image: the image.
3475%
3476% o x,y,columns,rows: These values define the perimeter of a region of
3477% pixels.
3478%
3479% o exception: return any errors or warnings in this structure.
3480%
3481*/
3482MagickExport const PixelPacket *GetVirtualPixels(const Image *image,
3483 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3484 ExceptionInfo *exception)
3485{
3486 CacheInfo
3487 *magick_restrict cache_info;
3488
3489 const int
3490 id = GetOpenMPThreadId();
3491
3492 assert(image != (const Image *) NULL);
3493 assert(image->signature == MagickCoreSignature);
3494 assert(image->cache != (Cache) NULL);
3495 cache_info=(CacheInfo *) image->cache;
3496 assert(cache_info->signature == MagickCoreSignature);
3497 if (cache_info->methods.get_virtual_pixel_handler !=
3498 (GetVirtualPixelHandler) NULL)
3499 return(cache_info->methods.get_virtual_pixel_handler(image,
3500 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3501 assert(id < (int) cache_info->number_threads);
3502 return(GetVirtualPixelCacheNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3503 columns,rows,cache_info->nexus_info[id],exception));
3504}
3505
3506/*
3507%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3508% %
3509% %
3510% %
3511+ 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 %
3512% %
3513% %
3514% %
3515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3516%
3517% GetVirtualPixelsCache() returns the pixels associated with the last call
3518% to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3519%
3520% The format of the GetVirtualPixelsCache() method is:
3521%
3522% PixelPacket *GetVirtualPixelsCache(const Image *image)
3523%
3524% A description of each parameter follows:
3525%
3526% o image: the image.
3527%
3528*/
3529static const PixelPacket *GetVirtualPixelsCache(const Image *image)
3530{
3531 CacheInfo
3532 *magick_restrict cache_info;
3533
3534 const int
3535 id = GetOpenMPThreadId();
3536
3537 assert(image != (const Image *) NULL);
3538 assert(image->signature == MagickCoreSignature);
3539 assert(image->cache != (Cache) NULL);
3540 cache_info=(CacheInfo *) image->cache;
3541 assert(cache_info->signature == MagickCoreSignature);
3542 assert(id < (int) cache_info->number_threads);
3543 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3544}
3545
3546/*
3547%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3548% %
3549% %
3550% %
3551+ G e t V i r t u a l P i x e l s N e x u s %
3552% %
3553% %
3554% %
3555%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3556%
3557% GetVirtualPixelsNexus() returns the pixels associated with the specified
3558% cache nexus.
3559%
3560% The format of the GetVirtualPixelsNexus() method is:
3561%
3562% const IndexPacket *GetVirtualPixelsNexus(const Cache cache,
3563% NexusInfo *nexus_info)
3564%
3565% A description of each parameter follows:
3566%
3567% o cache: the pixel cache.
3568%
3569% o nexus_info: the cache nexus to return the colormap pixels.
3570%
3571*/
3572MagickExport const PixelPacket *GetVirtualPixelsNexus(const Cache cache,
3573 NexusInfo *nexus_info)
3574{
3575 CacheInfo
3576 *magick_restrict cache_info;
3577
3578 assert(cache != (Cache) NULL);
3579 cache_info=(CacheInfo *) cache;
3580 assert(cache_info->signature == MagickCoreSignature);
3581 if (cache_info->storage_class == UndefinedClass)
3582 return((PixelPacket *) NULL);
3583 return((const PixelPacket *) nexus_info->pixels);
3584}
3585
3586/*
3587%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3588% %
3589% %
3590% %
3591+ M a s k P i x e l C a c h e N e x u s %
3592% %
3593% %
3594% %
3595%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3596%
3597% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3598% The method returns MagickTrue if the pixel region is masked, otherwise
3599% MagickFalse.
3600%
3601% The format of the MaskPixelCacheNexus() method is:
3602%
3603% MagickBooleanType MaskPixelCacheNexus(Image *image,
3604% NexusInfo *nexus_info,ExceptionInfo *exception)
3605%
3606% A description of each parameter follows:
3607%
3608% o image: the image.
3609%
3610% o nexus_info: the cache nexus to clip.
3611%
3612% o exception: return any errors or warnings in this structure.
3613%
3614*/
3615
3616static inline void ApplyPixelCompositeMask(const MagickPixelPacket *p,
3617 const MagickRealType alpha,const MagickPixelPacket *q,
3618 const MagickRealType beta,MagickPixelPacket *composite)
3619{
3620 double
3621 gamma;
3622
3623 if (fabs((double) alpha-(double) TransparentOpacity) < MagickEpsilon)
3624 {
3625 *composite=(*q);
3626 return;
3627 }
3628 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3629 gamma=MagickSafeReciprocal(gamma);
3630 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3631 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3632 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3633 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3634 composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
3635}
3636
3637static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3638 ExceptionInfo *exception)
3639{
3640 CacheInfo
3641 *magick_restrict cache_info;
3642
3643 const PixelPacket
3644 *magick_restrict r;
3645
3646 IndexPacket
3647 *magick_restrict nexus_indexes,
3648 *magick_restrict indexes;
3649
3650 MagickOffsetType
3651 n;
3652
3653 MagickPixelPacket
3654 alpha,
3655 beta;
3656
3657 NexusInfo
3658 **magick_restrict mask_nexus;
3659
3660 PixelPacket
3661 *magick_restrict p,
3662 *magick_restrict q;
3663
3664 ssize_t
3665 y;
3666
3667 /*
3668 Apply composite mask.
3669 */
3670 if (IsEventLogging() != MagickFalse)
3671 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3672 if ((image->mask == (Image *) NULL) || (image->storage_class == PseudoClass))
3673 return(MagickTrue);
3674 if ((nexus_info->region.width == 0) || (nexus_info->region.height == 0))
3675 return(MagickTrue);
3676 cache_info=(CacheInfo *) image->cache;
3677 if (cache_info == (Cache) NULL)
3678 return(MagickFalse);
3679 mask_nexus=AcquirePixelCacheNexus(1);
3680 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,nexus_info->region.y, nexus_info->region.width,nexus_info->region.height,
3681 nexus_info->virtual_nexus,exception);
3682 indexes=nexus_info->virtual_nexus->indexes;
3683 q=nexus_info->pixels;
3684 nexus_indexes=nexus_info->indexes;
3685 r=GetVirtualPixelCacheNexus(image->mask,MaskVirtualPixelMethod,
3686 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3687 nexus_info->region.height,mask_nexus[0],&image->exception);
3688 if ((p == (PixelPacket *) NULL) || (q == (PixelPacket *) NULL) ||
3689 (r == (const PixelPacket *) NULL))
3690 return(MagickFalse);
3691 n=0;
3692 GetMagickPixelPacket(image,&alpha);
3693 GetMagickPixelPacket(image,&beta);
3694 for (y=0; y < (ssize_t) nexus_info->region.height; y++)
3695 {
3696 ssize_t
3697 x;
3698
3699 for (x=0; x < (ssize_t) nexus_info->region.width; x++)
3700 {
3701 SetMagickPixelPacket(image,p,indexes+n,&alpha);
3702 SetMagickPixelPacket(image,q,nexus_indexes+n,&beta);
3703 ApplyPixelCompositeMask(&beta,GetPixelIntensity(image,r),&alpha,
3704 alpha.opacity,&beta);
3705 SetPixelRed(q,ClampToQuantum(beta.red));
3706 SetPixelGreen(q,ClampToQuantum(beta.green));
3707 SetPixelBlue(q,ClampToQuantum(beta.blue));
3708 SetPixelOpacity(q,ClampToQuantum(beta.opacity));
3709 if (cache_info->active_index_channel != MagickFalse)
3710 SetPixelIndex(nexus_indexes+n,GetPixelIndex(indexes+n));
3711 p++;
3712 q++;
3713 r++;
3714 n++;
3715 }
3716 }
3717 mask_nexus=DestroyPixelCacheNexus(mask_nexus,1);
3718 return(MagickTrue);
3719}
3720
3721/*
3722%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3723% %
3724% %
3725% %
3726+ O p e n P i x e l C a c h e %
3727% %
3728% %
3729% %
3730%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3731%
3732% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3733% dimensions, allocating space for the image pixels and optionally the
3734% colormap indexes, and memory mapping the cache if it is disk based. The
3735% cache nexus array is initialized as well.
3736%
3737% The format of the OpenPixelCache() method is:
3738%
3739% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3740% ExceptionInfo *exception)
3741%
3742% A description of each parameter follows:
3743%
3744% o image: the image.
3745%
3746% o mode: ReadMode, WriteMode, or IOMode.
3747%
3748% o exception: return any errors or warnings in this structure.
3749%
3750*/
3751
3752static inline MagickBooleanType CacheOverflowSanityCheckGetSize(
3753 const MagickSizeType count,const size_t quantum,MagickSizeType *const extent)
3754{
3755 MagickSizeType
3756 length;
3757
3758 if ((count == 0) || (quantum == 0))
3759 return(MagickTrue);
3760 length=count*quantum;
3761 if (quantum != (length/count))
3762 {
3763 errno=ENOMEM;
3764 return(MagickTrue);
3765 }
3766 if (extent != NULL)
3767 *extent=length;
3768 return(MagickFalse);
3769}
3770
3771static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
3772 const MapMode mode)
3773{
3774 int
3775 file;
3776
3777 /*
3778 Open pixel cache on disk.
3779 */
3780 if ((cache_info->file != -1) && (cache_info->disk_mode == mode))
3781 return(MagickTrue); /* cache already open and in the proper mode */
3782 if (*cache_info->cache_filename == '\0')
3783 file=AcquireUniqueFileResource(cache_info->cache_filename);
3784 else
3785 switch (mode)
3786 {
3787 case ReadMode:
3788 {
3789 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
3790 break;
3791 }
3792 case WriteMode:
3793 {
3794 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
3795 O_BINARY | O_EXCL,S_MODE);
3796 if (file == -1)
3797 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
3798 break;
3799 }
3800 case IOMode:
3801 default:
3802 {
3803 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
3804 O_EXCL,S_MODE);
3805 if (file == -1)
3806 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
3807 break;
3808 }
3809 }
3810 if (file == -1)
3811 return(MagickFalse);
3812 (void) AcquireMagickResource(FileResource,1);
3813 if (cache_info->file != -1)
3814 (void) ClosePixelCacheOnDisk(cache_info);
3815 cache_info->file=file;
3816 cache_info->disk_mode=mode;
3817 return(MagickTrue);
3818}
3819
3820static inline MagickOffsetType WritePixelCacheRegion(
3821 const CacheInfo *magick_restrict cache_info,const MagickOffsetType offset,
3822 const MagickSizeType length,const unsigned char *magick_restrict buffer)
3823{
3824 MagickOffsetType
3825 i;
3826
3827 ssize_t
3828 count = 0;
3829
3830#if !defined(MAGICKCORE_HAVE_PWRITE)
3831 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
3832 return((MagickOffsetType) -1);
3833#endif
3834 for (i=0; i < (MagickOffsetType) length; i+=count)
3835 {
3836#if !defined(MAGICKCORE_HAVE_PWRITE)
3837 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-
3838 (MagickSizeType) i,MagickMaxBufferExtent));
3839#else
3840 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-
3841 (MagickSizeType) i,MagickMaxBufferExtent),offset+i);
3842#endif
3843 if (count <= 0)
3844 {
3845 count=0;
3846 if (errno != EINTR)
3847 break;
3848 }
3849 }
3850 return(i);
3851}
3852
3853static MagickBooleanType SetPixelCacheExtent(Image *image,MagickSizeType length)
3854{
3855 CacheInfo
3856 *magick_restrict cache_info;
3857
3858 MagickOffsetType
3859 offset;
3860
3861 cache_info=(CacheInfo *) image->cache;
3862 if (cache_info->debug != MagickFalse)
3863 {
3864 char
3865 format[MaxTextExtent],
3866 message[MaxTextExtent];
3867
3868 (void) FormatMagickSize(length,MagickFalse,format);
3869 (void) FormatLocaleString(message,MaxTextExtent,
3870 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3871 cache_info->cache_filename,cache_info->file,format);
3872 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3873 }
3874 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3875 if (offset < 0)
3876 return(MagickFalse);
3877 if ((MagickSizeType) offset < length)
3878 {
3879 MagickOffsetType
3880 count,
3881 extent;
3882
3883 extent=(MagickOffsetType) length-1;
3884 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *)
3885 "");
3886 if (count != 1)
3887 return(MagickFalse);
3888#if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3889 if (cache_info->synchronize != MagickFalse)
3890 if (posix_fallocate(cache_info->file,offset+1,extent-offset) != 0)
3891 return(MagickFalse);
3892#endif
3893 }
3894 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_SET);
3895 if (offset < 0)
3896 return(MagickFalse);
3897 return(MagickTrue);
3898}
3899
3900static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3901 ExceptionInfo *exception)
3902{
3903 CacheInfo
3904 *magick_restrict cache_info,
3905 source_info;
3906
3907 char
3908 format[MaxTextExtent],
3909 message[MaxTextExtent];
3910
3911 const char
3912 *hosts,
3913 *type;
3914
3915 MagickSizeType
3916 length = 0,
3917 number_pixels;
3918
3919 MagickStatusType
3920 status;
3921
3922 size_t
3923 columns,
3924 packet_size;
3925
3926 assert(image != (const Image *) NULL);
3927 assert(image->signature == MagickCoreSignature);
3928 assert(image->cache != (Cache) NULL);
3929 if (IsEventLogging() != MagickFalse)
3930 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3931 if (cache_anonymous_memory < 0)
3932 {
3933 char
3934 *value;
3935
3936 /*
3937 Does the security policy require anonymous mapping for pixel cache?
3938 */
3939 cache_anonymous_memory=0;
3940 value=GetPolicyValue("pixel-cache-memory");
3941 if (value == (char *) NULL)
3942 value=GetPolicyValue("cache:memory-map");
3943 if (LocaleCompare(value,"anonymous") == 0)
3944 {
3945#if defined(MAGICKCORE_HAVE_MMAP) && defined(MAP_ANONYMOUS)
3946 cache_anonymous_memory=1;
3947#else
3948 (void) ThrowMagickException(exception,GetMagickModule(),
3949 MissingDelegateError,"DelegateLibrarySupportNotBuiltIn",
3950 "'%s' (policy requires anonymous memory mapping)",image->filename);
3951#endif
3952 }
3953 value=DestroyString(value);
3954 }
3955 if ((image->columns == 0) || (image->rows == 0))
3956 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3957 cache_info=(CacheInfo *) image->cache;
3958 assert(cache_info->signature == MagickCoreSignature);
3959 if (((MagickSizeType) image->columns > cache_info->width_limit) ||
3960 ((MagickSizeType) image->rows > cache_info->height_limit))
3961 ThrowBinaryException(ImageError,"WidthOrHeightExceedsLimit",
3962 image->filename);
3963 if (GetMagickResourceLimit(ListLengthResource) != MagickResourceInfinity)
3964 {
3965 length=GetImageListLength(image);
3966 if (AcquireMagickResource(ListLengthResource,length) == MagickFalse)
3967 ThrowBinaryException(ResourceLimitError,"ListLengthExceedsLimit",
3968 image->filename);
3969 }
3970 source_info=(*cache_info);
3971 source_info.file=(-1);
3972 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3973 image->filename,(double) image->scene);
3974 cache_info->storage_class=image->storage_class;
3975 cache_info->colorspace=image->colorspace;
3976 cache_info->rows=image->rows;
3977 cache_info->columns=image->columns;
3978 cache_info->channels=image->channels;
3979 cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
3980 (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
3981 cache_info->mode=mode;
3982 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3983 packet_size=sizeof(PixelPacket);
3984 if (cache_info->active_index_channel != MagickFalse)
3985 packet_size+=sizeof(IndexPacket);
3986 if (CacheOverflowSanityCheckGetSize(number_pixels,packet_size,&length) != MagickFalse)
3987 {
3988 cache_info->storage_class=UndefinedClass;
3989 cache_info->length=0;
3990 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3991 image->filename);
3992 }
3993 columns=(size_t) (length/cache_info->rows/packet_size);
3994 if ((cache_info->columns != columns) || ((ssize_t) cache_info->columns < 0) ||
3995 ((ssize_t) cache_info->rows < 0))
3996 {
3997 cache_info->storage_class=UndefinedClass;
3998 cache_info->length=0;
3999 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4000 image->filename);
4001 }
4002 cache_info->length=length;
4003 if (image->ping != MagickFalse)
4004 {
4005 cache_info->type=PingCache;
4006 return(MagickTrue);
4007 }
4008 status=AcquireMagickResource(AreaResource,(MagickSizeType)
4009 cache_info->columns*cache_info->rows);
4010 if (cache_info->mode == PersistMode)
4011 status=MagickFalse;
4012 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4013 if ((status != MagickFalse) &&
4014 (length == (MagickSizeType) ((size_t) length)) &&
4015 ((cache_info->type == UndefinedCache) ||
4016 (cache_info->type == MemoryCache)))
4017 {
4018 status=AcquireMagickResource(MemoryResource,cache_info->length);
4019 if (status != MagickFalse)
4020 {
4021 status=MagickTrue;
4022 if (cache_anonymous_memory <= 0)
4023 {
4024 cache_info->mapped=MagickFalse;
4025 cache_info->pixels=(PixelPacket *) MagickAssumeAligned(
4026 AcquireAlignedMemory(1,(size_t) cache_info->length));
4027 }
4028 else
4029 {
4030 cache_info->mapped=MagickTrue;
4031 cache_info->pixels=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
4032 cache_info->length);
4033 }
4034 if (cache_info->pixels == (PixelPacket *) NULL)
4035 {
4036 cache_info->mapped=source_info.mapped;
4037 cache_info->pixels=source_info.pixels;
4038 }
4039 else
4040 {
4041 /*
4042 Create memory pixel cache.
4043 */
4044 cache_info->colorspace=image->colorspace;
4045 cache_info->type=MemoryCache;
4046 cache_info->indexes=(IndexPacket *) NULL;
4047 if (cache_info->active_index_channel != MagickFalse)
4048 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4049 number_pixels);
4050 if ((source_info.storage_class != UndefinedClass) &&
4051 (mode != ReadMode))
4052 {
4053 status&=ClonePixelCacheRepository(cache_info,&source_info,
4054 exception);
4055 RelinquishPixelCachePixels(&source_info);
4056 }
4057 if (cache_info->debug != MagickFalse)
4058 {
4059 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
4060 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
4061 cache_info->type);
4062 (void) FormatLocaleString(message,MaxTextExtent,
4063 "open %s (%s %s, %.20gx%.20g %s)",cache_info->filename,
4064 cache_info->mapped != MagickFalse ? "Anonymous" : "Heap",
4065 type,(double) cache_info->columns,(double) cache_info->rows,
4066 format);
4067 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4068 message);
4069 }
4070 cache_info->storage_class=image->storage_class;
4071 if (status == 0)
4072 {
4073 if ((source_info.storage_class != UndefinedClass) &&
4074 (mode != ReadMode))
4075 RelinquishPixelCachePixels(&source_info);
4076 cache_info->type=UndefinedCache;
4077 return(MagickFalse);
4078 }
4079 return(MagickTrue);
4080 }
4081 }
4082 }
4083 status=AcquireMagickResource(DiskResource,cache_info->length);
4084 hosts=(const char *) GetImageRegistry(StringRegistryType,"cache:hosts",
4085 exception);
4086 if ((status == MagickFalse) && (hosts != (const char *) NULL))
4087 {
4088 DistributeCacheInfo
4089 *server_info;
4090
4091 /*
4092 Distribute the pixel cache to a remote server.
4093 */
4094 server_info=AcquireDistributeCacheInfo(exception);
4095 if (server_info != (DistributeCacheInfo *) NULL)
4096 {
4097 status=OpenDistributePixelCache(server_info,image);
4098 if (status == MagickFalse)
4099 {
4100 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4101 GetDistributeCacheHostname(server_info));
4102 server_info=DestroyDistributeCacheInfo(server_info);
4103 }
4104 else
4105 {
4106 /*
4107 Create a distributed pixel cache.
4108 */
4109 status=MagickTrue;
4110 cache_info->type=DistributedCache;
4111 cache_info->storage_class=image->storage_class;
4112 cache_info->colorspace=image->colorspace;
4113 cache_info->server_info=server_info;
4114 (void) FormatLocaleString(cache_info->cache_filename,
4115 MaxTextExtent,"%s:%d",GetDistributeCacheHostname(
4116 (DistributeCacheInfo *) cache_info->server_info),
4117 GetDistributeCachePort((DistributeCacheInfo *)
4118 cache_info->server_info));
4119 if ((source_info.storage_class != UndefinedClass) &&
4120 (mode != ReadMode))
4121 {
4122 status=ClonePixelCacheRepository(cache_info,&source_info,
4123 exception);
4124 RelinquishPixelCachePixels(&source_info);
4125 }
4126 if (cache_info->debug != MagickFalse)
4127 {
4128 (void) FormatMagickSize(cache_info->length,MagickFalse,
4129 format);
4130 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
4131 cache_info->type);
4132 (void) FormatLocaleString(message,MaxTextExtent,
4133 "open %s (%s[%d], %s, %.20gx%.20g %s)",cache_info->filename,
4134 cache_info->cache_filename,GetDistributeCacheFile(
4135 (DistributeCacheInfo *) cache_info->server_info),type,
4136 (double) cache_info->columns,(double) cache_info->rows,
4137 format);
4138 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4139 message);
4140 }
4141 if (status == 0)
4142 {
4143 if ((source_info.storage_class != UndefinedClass) &&
4144 (mode != ReadMode))
4145 RelinquishPixelCachePixels(&source_info);
4146 cache_info->type=UndefinedCache;
4147 return(MagickFalse);
4148 }
4149 return(MagickTrue);
4150 }
4151 }
4152 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
4153 RelinquishPixelCachePixels(&source_info);
4154 cache_info->type=UndefinedCache;
4155 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4156 "CacheResourcesExhausted","`%s'",image->filename);
4157 return(MagickFalse);
4158 }
4159 /*
4160 Create pixel cache on disk.
4161 */
4162 if (status == MagickFalse)
4163 {
4164 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
4165 RelinquishPixelCachePixels(&source_info);
4166 cache_info->type=UndefinedCache;
4167 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4168 "CacheResourcesExhausted","`%s'",image->filename);
4169 return(MagickFalse);
4170 }
4171 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode) &&
4172 (cache_info->mode != PersistMode))
4173 {
4174 (void) ClosePixelCacheOnDisk(cache_info);
4175 *cache_info->cache_filename='\0';
4176 }
4177 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4178 {
4179 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
4180 RelinquishPixelCachePixels(&source_info);
4181 cache_info->type=UndefinedCache;
4182 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4183 image->filename);
4184 return(MagickFalse);
4185 }
4186 status=SetPixelCacheExtent(image,(MagickSizeType) cache_info->offset+
4187 cache_info->length);
4188 if (status == MagickFalse)
4189 {
4190 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
4191 RelinquishPixelCachePixels(&source_info);
4192 cache_info->type=UndefinedCache;
4193 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4194 image->filename);
4195 return(MagickFalse);
4196 }
4197 cache_info->storage_class=image->storage_class;
4198 cache_info->colorspace=image->colorspace;
4199 cache_info->type=DiskCache;
4200 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4201 if (length == (MagickSizeType) ((size_t) length))
4202 {
4203 status=AcquireMagickResource(MapResource,cache_info->length);
4204 if (status != MagickFalse)
4205 {
4206 cache_info->pixels=(PixelPacket *) MapBlob(cache_info->file,mode,
4207 cache_info->offset,(size_t) cache_info->length);
4208 if (cache_info->pixels == (PixelPacket *) NULL)
4209 {
4210 cache_info->mapped=source_info.mapped;
4211 cache_info->pixels=source_info.pixels;
4212 RelinquishMagickResource(MapResource,cache_info->length);
4213 }
4214 else
4215 {
4216 /*
4217 Create file-backed memory-mapped pixel cache.
4218 */
4219 (void) ClosePixelCacheOnDisk(cache_info);
4220 cache_info->type=MapCache;
4221 cache_info->mapped=MagickTrue;
4222 cache_info->indexes=(IndexPacket *) NULL;
4223 if (cache_info->active_index_channel != MagickFalse)
4224 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4225 number_pixels);
4226 if ((source_info.storage_class != UndefinedClass) &&
4227 (mode != ReadMode))
4228 {
4229 status=ClonePixelCacheRepository(cache_info,&source_info,
4230 exception);
4231 RelinquishPixelCachePixels(&source_info);
4232 }
4233 if (cache_info->debug != MagickFalse)
4234 {
4235 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
4236 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
4237 cache_info->type);
4238 (void) FormatLocaleString(message,MaxTextExtent,
4239 "open %s (%s[%d], %s, %.20gx%.20g %s)",
4240 cache_info->filename,cache_info->cache_filename,
4241 cache_info->file,type,(double) cache_info->columns,
4242 (double) cache_info->rows,format);
4243 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4244 message);
4245 }
4246 if (status == 0)
4247 {
4248 if ((source_info.storage_class != UndefinedClass) &&
4249 (mode != ReadMode))
4250 RelinquishPixelCachePixels(&source_info);
4251 cache_info->type=UndefinedCache;
4252 return(MagickFalse);
4253 }
4254 return(MagickTrue);
4255 }
4256 }
4257 }
4258 status=MagickTrue;
4259 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
4260 {
4261 status=ClonePixelCacheRepository(cache_info,&source_info,exception);
4262 RelinquishPixelCachePixels(&source_info);
4263 }
4264 if (cache_info->debug != MagickFalse)
4265 {
4266 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
4267 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
4268 cache_info->type);
4269 (void) FormatLocaleString(message,MaxTextExtent,
4270 "open %s (%s[%d], %s, %.20gx%.20g %s)",cache_info->filename,
4271 cache_info->cache_filename,cache_info->file,type,(double)
4272 cache_info->columns,(double) cache_info->rows,format);
4273 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4274 }
4275 if (status == 0)
4276 {
4277 cache_info->type=UndefinedCache;
4278 return(MagickFalse);
4279 }
4280 return(MagickTrue);
4281}
4282
4283/*
4284%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4285% %
4286% %
4287% %
4288+ P e r s i s t P i x e l C a c h e %
4289% %
4290% %
4291% %
4292%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4293%
4294% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4295% persistent pixel cache is one that resides on disk and is not destroyed
4296% when the program exits.
4297%
4298% The format of the PersistPixelCache() method is:
4299%
4300% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4301% const MagickBooleanType attach,MagickOffsetType *offset,
4302% ExceptionInfo *exception)
4303%
4304% A description of each parameter follows:
4305%
4306% o image: the image.
4307%
4308% o filename: the persistent pixel cache filename.
4309%
4310% o attach: A value other than zero initializes the persistent pixel cache.
4311%
4312% o initialize: A value other than zero initializes the persistent pixel
4313% cache.
4314%
4315% o offset: the offset in the persistent cache to store pixels.
4316%
4317% o exception: return any errors or warnings in this structure.
4318%
4319*/
4320MagickExport MagickBooleanType PersistPixelCache(Image *image,
4321 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4322 ExceptionInfo *exception)
4323{
4324 CacheInfo
4325 *magick_restrict cache_info,
4326 *magick_restrict clone_info;
4327
4328 MagickBooleanType
4329 status;
4330
4331 ssize_t
4332 page_size;
4333
4334 assert(image != (Image *) NULL);
4335 assert(image->signature == MagickCoreSignature);
4336 if (IsEventLogging() != MagickFalse)
4337 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4338 assert(image->cache != (void *) NULL);
4339 assert(filename != (const char *) NULL);
4340 assert(offset != (MagickOffsetType *) NULL);
4341 page_size=GetMagickPageSize();
4342 cache_info=(CacheInfo *) image->cache;
4343 assert(cache_info->signature == MagickCoreSignature);
4344#if defined(MAGICKCORE_OPENCL_SUPPORT)
4345 CopyOpenCLBuffer(cache_info);
4346#endif
4347 if (attach != MagickFalse)
4348 {
4349 /*
4350 Attach existing persistent pixel cache.
4351 */
4352 if (cache_info->debug != MagickFalse)
4353 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4354 "attach persistent cache");
4355 (void) CopyMagickString(cache_info->cache_filename,filename,
4356 MaxTextExtent);
4357 cache_info->type=MapCache;
4358 cache_info->offset=(*offset);
4359 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4360 return(MagickFalse);
4361 *offset=(*offset+(MagickOffsetType) cache_info->length+page_size-
4362 ((MagickOffsetType) cache_info->length % page_size));
4363 return(MagickTrue);
4364 }
4365 /*
4366 Clone persistent pixel cache.
4367 */
4368 status=AcquireMagickResource(DiskResource,cache_info->length);
4369 if (status == MagickFalse)
4370 {
4371 cache_info->type=UndefinedCache;
4372 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4373 "CacheResourcesExhausted","`%s'",image->filename);
4374 return(MagickFalse);
4375 }
4376 clone_info=(CacheInfo *) ClonePixelCache(cache_info);
4377 clone_info->type=DiskCache;
4378 (void) CopyMagickString(clone_info->cache_filename,filename,MaxTextExtent);
4379 clone_info->file=(-1);
4380 clone_info->storage_class=cache_info->storage_class;
4381 clone_info->colorspace=cache_info->colorspace;
4382 clone_info->columns=cache_info->columns;
4383 clone_info->rows=cache_info->rows;
4384 clone_info->active_index_channel=cache_info->active_index_channel;
4385 clone_info->mode=PersistMode;
4386 clone_info->length=cache_info->length;
4387 clone_info->channels=cache_info->channels;
4388 clone_info->offset=(*offset);
4389 status=OpenPixelCacheOnDisk(clone_info,WriteMode);
4390 if (status != MagickFalse)
4391 status=ClonePixelCacheRepository(clone_info,cache_info,exception);
4392 *offset=(*offset+(MagickOffsetType) cache_info->length+page_size-
4393 ((MagickOffsetType) cache_info->length % page_size));
4394 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4395 return(status);
4396}
4397
4398/*
4399%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4400% %
4401% %
4402% %
4403+ 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 %
4404% %
4405% %
4406% %
4407%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4408%
4409% QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
4410% defined by the region rectangle and returns a pointer to the region. This
4411% region is subsequently transferred from the pixel cache with
4412% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4413% pixels are transferred, otherwise a NULL is returned.
4414%
4415% The format of the QueueAuthenticPixelCacheNexus() method is:
4416%
4417% PixelPacket *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
4418% const ssize_t y,const size_t columns,const size_t rows,
4419% const MagickBooleanType clone,NexusInfo *nexus_info,
4420% ExceptionInfo *exception)
4421%
4422% A description of each parameter follows:
4423%
4424% o image: the image.
4425%
4426% o x,y,columns,rows: These values define the perimeter of a region of
4427% pixels.
4428%
4429% o nexus_info: the cache nexus to set.
4430%
4431% o clone: clone the pixel cache.
4432%
4433% o exception: return any errors or warnings in this structure.
4434%
4435*/
4436MagickExport PixelPacket *QueueAuthenticPixel(Image *image,const ssize_t x,
4437 const ssize_t y,const size_t columns,const size_t rows,
4438 const MagickBooleanType clone,NexusInfo *nexus_info,
4439 ExceptionInfo *exception)
4440{
4441 return(QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,clone,nexus_info,
4442 exception));
4443}
4444
4445MagickExport PixelPacket *QueueAuthenticPixelCacheNexus(Image *image,
4446 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
4447 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
4448{
4449 CacheInfo
4450 *magick_restrict cache_info;
4451
4452 MagickOffsetType
4453 offset;
4454
4455 MagickSizeType
4456 number_pixels;
4457
4458 PixelPacket
4459 *magick_restrict pixels;
4460
4461 /*
4462 Validate pixel cache geometry.
4463 */
4464 assert(image != (const Image *) NULL);
4465 assert(image->signature == MagickCoreSignature);
4466 assert(image->cache != (Cache) NULL);
4467 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
4468 if (cache_info == (Cache) NULL)
4469 return((PixelPacket *) NULL);
4470 assert(cache_info->signature == MagickCoreSignature);
4471 if ((cache_info->columns == 0) || (cache_info->rows == 0) || (x < 0) ||
4472 (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4473 (y >= (ssize_t) cache_info->rows))
4474 {
4475 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4476 "PixelsAreNotAuthentic","`%s'",image->filename);
4477 return((PixelPacket *) NULL);
4478 }
4479 if (IsValidPixelOffset(y,cache_info->columns) == MagickFalse)
4480 return((PixelPacket *) NULL);
4481 offset=y*(MagickOffsetType) cache_info->columns+x;
4482 if (offset < 0)
4483 return((PixelPacket *) NULL);
4484 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4485 offset+=((MagickOffsetType) rows-1)*(MagickOffsetType) cache_info->columns+
4486 (MagickOffsetType) columns-1;
4487 if ((MagickSizeType) offset >= number_pixels)
4488 return((PixelPacket *) NULL);
4489 /*
4490 Return pixel cache.
4491 */
4492 pixels=SetPixelCacheNexusPixels(cache_info,WriteMode,x,y,columns,rows,
4493 (image->clip_mask != (Image *) NULL) || (image->mask != (Image *) NULL) ?
4494 MagickTrue : MagickFalse,nexus_info,exception);
4495 return(pixels);
4496}
4497
4498/*
4499%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4500% %
4501% %
4502% %
4503+ 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 %
4504% %
4505% %
4506% %
4507%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4508%
4509% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4510% defined by the region rectangle and returns a pointer to the region. This
4511% region is subsequently transferred from the pixel cache with
4512% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4513% pixels are transferred, otherwise a NULL is returned.
4514%
4515% The format of the QueueAuthenticPixelsCache() method is:
4516%
4517% PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4518% const ssize_t y,const size_t columns,const size_t rows,
4519% ExceptionInfo *exception)
4520%
4521% A description of each parameter follows:
4522%
4523% o image: the image.
4524%
4525% o x,y,columns,rows: These values define the perimeter of a region of
4526% pixels.
4527%
4528% o exception: return any errors or warnings in this structure.
4529%
4530*/
4531static PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4532 const ssize_t y,const size_t columns,const size_t rows,
4533 ExceptionInfo *exception)
4534{
4535 CacheInfo
4536 *magick_restrict cache_info;
4537
4538 const int
4539 id = GetOpenMPThreadId();
4540
4541 assert(image != (const Image *) NULL);
4542 assert(image->signature == MagickCoreSignature);
4543 assert(image->cache != (Cache) NULL);
4544 cache_info=(CacheInfo *) image->cache;
4545 assert(cache_info->signature == MagickCoreSignature);
4546 assert(id < (int) cache_info->number_threads);
4547 return(QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4548 cache_info->nexus_info[id],exception));
4549}
4550
4551/*
4552%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4553% %
4554% %
4555% %
4556% Q u e u e A u t h e n t i c P i x e l s %
4557% %
4558% %
4559% %
4560%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4561%
4562% QueueAuthenticPixels() queues a mutable pixel region. If the region is
4563% successfully initialized a pointer to a PixelPacket array representing the
4564% region is returned, otherwise NULL is returned. The returned pointer may
4565% point to a temporary working buffer for the pixels or it may point to the
4566% final location of the pixels in memory.
4567%
4568% Write-only access means that any existing pixel values corresponding to
4569% the region are ignored. This is useful if the initial image is being
4570% created from scratch, or if the existing pixel values are to be
4571% completely replaced without need to refer to their preexisting values.
4572% The application is free to read and write the pixel buffer returned by
4573% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4574% initialize the pixel array values. Initializing pixel array values is the
4575% application's responsibility.
4576%
4577% Performance is maximized if the selected region is part of one row, or
4578% one or more full rows, since then there is opportunity to access the
4579% pixels in-place (without a copy) if the image is in memory, or in a
4580% memory-mapped file. The returned pointer must *never* be deallocated
4581% by the user.
4582%
4583% Pixels accessed via the returned pointer represent a simple array of type
4584% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
4585% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
4586% the black color component or the colormap indexes (of type IndexPacket)
4587% corresponding to the region. Once the PixelPacket (and/or IndexPacket)
4588% array has been updated, the changes must be saved back to the underlying
4589% image using SyncAuthenticPixels() or they may be lost.
4590%
4591% The format of the QueueAuthenticPixels() method is:
4592%
4593% PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4594% const ssize_t y,const size_t columns,const size_t rows,
4595% ExceptionInfo *exception)
4596%
4597% A description of each parameter follows:
4598%
4599% o image: the image.
4600%
4601% o x,y,columns,rows: These values define the perimeter of a region of
4602% pixels.
4603%
4604% o exception: return any errors or warnings in this structure.
4605%
4606*/
4607MagickExport PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4608 const ssize_t y,const size_t columns,const size_t rows,
4609 ExceptionInfo *exception)
4610{
4611 CacheInfo
4612 *magick_restrict cache_info;
4613
4614 const int
4615 id = GetOpenMPThreadId();
4616
4617 assert(image != (Image *) NULL);
4618 assert(image->signature == MagickCoreSignature);
4619 assert(image->cache != (Cache) NULL);
4620 cache_info=(CacheInfo *) image->cache;
4621 assert(cache_info->signature == MagickCoreSignature);
4622 if (cache_info->methods.queue_authentic_pixels_handler !=
4623 (QueueAuthenticPixelsHandler) NULL)
4624 return(cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4625 rows,exception));
4626 assert(id < (int) cache_info->number_threads);
4627 return(QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4628 cache_info->nexus_info[id],exception));
4629}
4630
4631/*
4632%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4633% %
4634% %
4635% %
4636+ R e a d P i x e l C a c h e I n d e x e s %
4637% %
4638% %
4639% %
4640%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4641%
4642% ReadPixelCacheIndexes() reads colormap indexes from the specified region of
4643% the pixel cache.
4644%
4645% The format of the ReadPixelCacheIndexes() method is:
4646%
4647% MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4648% NexusInfo *nexus_info,ExceptionInfo *exception)
4649%
4650% A description of each parameter follows:
4651%
4652% o cache_info: the pixel cache.
4653%
4654% o nexus_info: the cache nexus to read the colormap indexes.
4655%
4656% o exception: return any errors or warnings in this structure.
4657%
4658*/
4659
4660static inline MagickOffsetType ReadPixelCacheRegion(
4661 const CacheInfo *magick_restrict cache_info,const MagickOffsetType offset,
4662 const MagickSizeType length,unsigned char *magick_restrict buffer)
4663{
4664 MagickOffsetType
4665 i;
4666
4667 ssize_t
4668 count = 0;
4669
4670#if !defined(MAGICKCORE_HAVE_PREAD)
4671 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
4672 return((MagickOffsetType) -1);
4673#endif
4674 for (i=0; i < (MagickOffsetType) length; i+=count)
4675 {
4676#if !defined(MAGICKCORE_HAVE_PREAD)
4677 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-
4678 (MagickSizeType) i,(size_t) MagickMaxBufferExtent));
4679#else
4680 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-
4681 (MagickSizeType) i,(size_t) MagickMaxBufferExtent),offset+i);
4682#endif
4683 if (count <= 0)
4684 {
4685 count=0;
4686 if (errno != EINTR)
4687 break;
4688 }
4689 }
4690 return(i);
4691}
4692
4693static MagickBooleanType ReadPixelCacheIndexes(
4694 CacheInfo *magick_restrict cache_info,NexusInfo *magick_restrict nexus_info,
4695 ExceptionInfo *exception)
4696{
4697 IndexPacket
4698 *magick_restrict q;
4699
4700 MagickOffsetType
4701 count,
4702 offset;
4703
4704 MagickSizeType
4705 extent,
4706 length;
4707
4708 ssize_t
4709 y;
4710
4711 size_t
4712 rows;
4713
4714 if (cache_info->active_index_channel == MagickFalse)
4715 return(MagickFalse);
4716 if (nexus_info->authentic_pixel_cache != MagickFalse)
4717 return(MagickTrue);
4718 if (IsValidPixelOffset(nexus_info->region.y,cache_info->columns) == MagickFalse)
4719 return(MagickFalse);
4720 offset=nexus_info->region.y*(MagickOffsetType) cache_info->columns+
4721 nexus_info->region.x;
4722 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
4723 rows=nexus_info->region.height;
4724 extent=length*rows;
4725 q=nexus_info->indexes;
4726 y=0;
4727 switch (cache_info->type)
4728 {
4729 case MemoryCache:
4730 case MapCache:
4731 {
4732 IndexPacket
4733 *magick_restrict p;
4734
4735 /*
4736 Read indexes from memory.
4737 */
4738 if ((cache_info->columns == nexus_info->region.width) &&
4739 (extent == (MagickSizeType) ((size_t) extent)))
4740 {
4741 length=extent;
4742 rows=1UL;
4743 }
4744 p=cache_info->indexes+offset;
4745 for (y=0; y < (ssize_t) rows; y++)
4746 {
4747 (void) memcpy(q,p,(size_t) length);
4748 p+=(ptrdiff_t) cache_info->columns;
4749 q+=(ptrdiff_t) nexus_info->region.width;
4750 }
4751 break;
4752 }
4753 case DiskCache:
4754 {
4755 /*
4756 Read indexes from disk.
4757 */
4758 LockSemaphoreInfo(cache_info->file_semaphore);
4759 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4760 {
4761 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4762 cache_info->cache_filename);
4763 UnlockSemaphoreInfo(cache_info->file_semaphore);
4764 return(MagickFalse);
4765 }
4766 if ((cache_info->columns == nexus_info->region.width) &&
4767 (extent <= MagickMaxBufferExtent))
4768 {
4769 length=extent;
4770 rows=1UL;
4771 }
4772 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4773 for (y=0; y < (ssize_t) rows; y++)
4774 {
4775 count=ReadPixelCacheRegion(cache_info,cache_info->offset+
4776 (MagickOffsetType) extent*(MagickOffsetType) sizeof(PixelPacket)+
4777 offset*(MagickOffsetType) sizeof(*q),length,(unsigned char *) q);
4778 if (count < (MagickOffsetType) length)
4779 break;
4780 offset+=(MagickOffsetType) cache_info->columns;
4781 q+=(ptrdiff_t) nexus_info->region.width;
4782 }
4783 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4784 (void) ClosePixelCacheOnDisk(cache_info);
4785 UnlockSemaphoreInfo(cache_info->file_semaphore);
4786 break;
4787 }
4788 case DistributedCache:
4789 {
4790 RectangleInfo
4791 region;
4792
4793 /*
4794 Read indexes from distributed cache.
4795 */
4796 LockSemaphoreInfo(cache_info->file_semaphore);
4797 region=nexus_info->region;
4798 if ((cache_info->columns != nexus_info->region.width) ||
4799 (extent > MagickMaxBufferExtent))
4800 region.height=1UL;
4801 else
4802 {
4803 length=extent;
4804 rows=1UL;
4805 }
4806 for (y=0; y < (ssize_t) rows; y++)
4807 {
4808 count=ReadDistributePixelCacheIndexes((DistributeCacheInfo *)
4809 cache_info->server_info,&region,length,(unsigned char *) q);
4810 if (count != (MagickOffsetType) length)
4811 break;
4812 q+=(ptrdiff_t) nexus_info->region.width;
4813 region.y++;
4814 }
4815 UnlockSemaphoreInfo(cache_info->file_semaphore);
4816 break;
4817 }
4818 default:
4819 break;
4820 }
4821 if (y < (ssize_t) rows)
4822 {
4823 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4824 cache_info->cache_filename);
4825 return(MagickFalse);
4826 }
4827 if ((cache_info->debug != MagickFalse) &&
4828 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4829 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4830 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4831 nexus_info->region.width,(double) nexus_info->region.height,(double)
4832 nexus_info->region.x,(double) nexus_info->region.y);
4833 return(MagickTrue);
4834}
4835
4836/*
4837%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4838% %
4839% %
4840% %
4841+ R e a d P i x e l C a c h e P i x e l s %
4842% %
4843% %
4844% %
4845%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4846%
4847% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4848% cache.
4849%
4850% The format of the ReadPixelCachePixels() method is:
4851%
4852% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4853% NexusInfo *nexus_info,ExceptionInfo *exception)
4854%
4855% A description of each parameter follows:
4856%
4857% o cache_info: the pixel cache.
4858%
4859% o nexus_info: the cache nexus to read the pixels.
4860%
4861% o exception: return any errors or warnings in this structure.
4862%
4863*/
4864static MagickBooleanType ReadPixelCachePixels(
4865 CacheInfo *magick_restrict cache_info,NexusInfo *magick_restrict nexus_info,
4866 ExceptionInfo *exception)
4867{
4868 MagickOffsetType
4869 count,
4870 offset;
4871
4872 MagickSizeType
4873 extent,
4874 length;
4875
4876 PixelPacket
4877 *magick_restrict q;
4878
4879 size_t
4880 rows;
4881
4882 ssize_t
4883 y;
4884
4885 if (nexus_info->authentic_pixel_cache != MagickFalse)
4886 return(MagickTrue);
4887 if (IsValidPixelOffset(nexus_info->region.y,cache_info->columns) == MagickFalse)
4888 return(MagickFalse);
4889 offset=nexus_info->region.y*(MagickOffsetType) cache_info->columns;
4890 if ((offset/(MagickOffsetType) cache_info->columns) != nexus_info->region.y)
4891 return(MagickFalse);
4892 offset+=nexus_info->region.x;
4893 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
4894 if ((length/sizeof(PixelPacket)) != nexus_info->region.width)
4895 return(MagickFalse);
4896 rows=nexus_info->region.height;
4897 extent=length*rows;
4898 if ((extent == 0) || ((extent/length) != rows))
4899 return(MagickFalse);
4900 q=nexus_info->pixels;
4901 y=0;
4902 switch (cache_info->type)
4903 {
4904 case MemoryCache:
4905 case MapCache:
4906 {
4907 PixelPacket
4908 *magick_restrict p;
4909
4910 /*
4911 Read pixels from memory.
4912 */
4913 if ((cache_info->columns == nexus_info->region.width) &&
4914 (extent == (MagickSizeType) ((size_t) extent)))
4915 {
4916 length=extent;
4917 rows=1UL;
4918 }
4919 p=cache_info->pixels+offset;
4920 for (y=0; y < (ssize_t) rows; y++)
4921 {
4922 (void) memcpy(q,p,(size_t) length);
4923 p+=(ptrdiff_t) cache_info->columns;
4924 q+=(ptrdiff_t) nexus_info->region.width;
4925 }
4926 break;
4927 }
4928 case DiskCache:
4929 {
4930 /*
4931 Read pixels from disk.
4932 */
4933 LockSemaphoreInfo(cache_info->file_semaphore);
4934 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4935 {
4936 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4937 cache_info->cache_filename);
4938 UnlockSemaphoreInfo(cache_info->file_semaphore);
4939 return(MagickFalse);
4940 }
4941 if ((cache_info->columns == nexus_info->region.width) &&
4942 (extent <= MagickMaxBufferExtent))
4943 {
4944 length=extent;
4945 rows=1UL;
4946 }
4947 for (y=0; y < (ssize_t) rows; y++)
4948 {
4949 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4950 (MagickOffsetType) sizeof(*q),length,(unsigned char *) q);
4951 if (count < (MagickOffsetType) length)
4952 break;
4953 offset+=(MagickOffsetType) cache_info->columns;
4954 q+=(ptrdiff_t) nexus_info->region.width;
4955 }
4956 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4957 (void) ClosePixelCacheOnDisk(cache_info);
4958 UnlockSemaphoreInfo(cache_info->file_semaphore);
4959 break;
4960 }
4961 case DistributedCache:
4962 {
4963 RectangleInfo
4964 region;
4965
4966 /*
4967 Read pixels from distributed cache.
4968 */
4969 LockSemaphoreInfo(cache_info->file_semaphore);
4970 region=nexus_info->region;
4971 if ((cache_info->columns != nexus_info->region.width) ||
4972 (extent > MagickMaxBufferExtent))
4973 region.height=1UL;
4974 else
4975 {
4976 length=extent;
4977 rows=1UL;
4978 }
4979 for (y=0; y < (ssize_t) rows; y++)
4980 {
4981 count=ReadDistributePixelCachePixels((DistributeCacheInfo *)
4982 cache_info->server_info,&region,length,(unsigned char *) q);
4983 if (count != (MagickOffsetType) length)
4984 break;
4985 q+=(ptrdiff_t) nexus_info->region.width;
4986 region.y++;
4987 }
4988 UnlockSemaphoreInfo(cache_info->file_semaphore);
4989 break;
4990 }
4991 default:
4992 break;
4993 }
4994 if (y < (ssize_t) rows)
4995 {
4996 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4997 cache_info->cache_filename);
4998 return(MagickFalse);
4999 }
5000 if ((cache_info->debug != MagickFalse) &&
5001 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5002 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5003 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5004 nexus_info->region.width,(double) nexus_info->region.height,(double)
5005 nexus_info->region.x,(double) nexus_info->region.y);
5006 return(MagickTrue);
5007}
5008
5009/*
5010%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5011% %
5012% %
5013% %
5014+ R e f e r e n c e P i x e l C a c h e %
5015% %
5016% %
5017% %
5018%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5019%
5020% ReferencePixelCache() increments the reference count associated with the
5021% pixel cache returning a pointer to the cache.
5022%
5023% The format of the ReferencePixelCache method is:
5024%
5025% Cache ReferencePixelCache(Cache cache_info)
5026%
5027% A description of each parameter follows:
5028%
5029% o cache_info: the pixel cache.
5030%
5031*/
5032MagickExport Cache ReferencePixelCache(Cache cache)
5033{
5034 CacheInfo
5035 *magick_restrict cache_info;
5036
5037 assert(cache != (Cache *) NULL);
5038 cache_info=(CacheInfo *) cache;
5039 assert(cache_info->signature == MagickCoreSignature);
5040 LockSemaphoreInfo(cache_info->semaphore);
5041 cache_info->reference_count++;
5042 UnlockSemaphoreInfo(cache_info->semaphore);
5043 return(cache_info);
5044}
5045
5046/*
5047%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5048% %
5049% %
5050% %
5051+ 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 %
5052% %
5053% %
5054% %
5055%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5056%
5057% ResetCacheAnonymousMemory() resets the anonymous_memory value.
5058%
5059% The format of the ResetCacheAnonymousMemory method is:
5060%
5061% void ResetCacheAnonymousMemory(void)
5062%
5063*/
5064MagickPrivate void ResetCacheAnonymousMemory(void)
5065{
5066 cache_anonymous_memory=0;
5067}
5068
5069/*
5070%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5071% %
5072% %
5073% %
5074+ S e t P i x e l C a c h e M e t h o d s %
5075% %
5076% %
5077% %
5078%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5079%
5080% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
5081%
5082% The format of the SetPixelCacheMethods() method is:
5083%
5084% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
5085%
5086% A description of each parameter follows:
5087%
5088% o cache: the pixel cache.
5089%
5090% o cache_methods: Specifies a pointer to a CacheMethods structure.
5091%
5092*/
5093MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
5094{
5095 CacheInfo
5096 *magick_restrict cache_info;
5097
5098 GetOneAuthenticPixelFromHandler
5099 get_one_authentic_pixel_from_handler;
5100
5101 GetOneVirtualPixelFromHandler
5102 get_one_virtual_pixel_from_handler;
5103
5104 /*
5105 Set cache pixel methods.
5106 */
5107 assert(cache != (Cache) NULL);
5108 assert(cache_methods != (CacheMethods *) NULL);
5109 cache_info=(CacheInfo *) cache;
5110 assert(cache_info->signature == MagickCoreSignature);
5111 if (IsEventLogging() != MagickFalse)
5112 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
5113 cache_info->filename);
5114 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
5115 cache_info->methods.get_virtual_pixel_handler=
5116 cache_methods->get_virtual_pixel_handler;
5117 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
5118 cache_info->methods.destroy_pixel_handler=
5119 cache_methods->destroy_pixel_handler;
5120 if (cache_methods->get_virtual_indexes_from_handler !=
5121 (GetVirtualIndexesFromHandler) NULL)
5122 cache_info->methods.get_virtual_indexes_from_handler=
5123 cache_methods->get_virtual_indexes_from_handler;
5124 if (cache_methods->get_authentic_pixels_handler !=
5125 (GetAuthenticPixelsHandler) NULL)
5126 cache_info->methods.get_authentic_pixels_handler=
5127 cache_methods->get_authentic_pixels_handler;
5128 if (cache_methods->queue_authentic_pixels_handler !=
5129 (QueueAuthenticPixelsHandler) NULL)
5130 cache_info->methods.queue_authentic_pixels_handler=
5131 cache_methods->queue_authentic_pixels_handler;
5132 if (cache_methods->sync_authentic_pixels_handler !=
5133 (SyncAuthenticPixelsHandler) NULL)
5134 cache_info->methods.sync_authentic_pixels_handler=
5135 cache_methods->sync_authentic_pixels_handler;
5136 if (cache_methods->get_authentic_pixels_from_handler !=
5137 (GetAuthenticPixelsFromHandler) NULL)
5138 cache_info->methods.get_authentic_pixels_from_handler=
5139 cache_methods->get_authentic_pixels_from_handler;
5140 if (cache_methods->get_authentic_indexes_from_handler !=
5141 (GetAuthenticIndexesFromHandler) NULL)
5142 cache_info->methods.get_authentic_indexes_from_handler=
5143 cache_methods->get_authentic_indexes_from_handler;
5144 get_one_virtual_pixel_from_handler=
5145 cache_info->methods.get_one_virtual_pixel_from_handler;
5146 if (get_one_virtual_pixel_from_handler !=
5147 (GetOneVirtualPixelFromHandler) NULL)
5148 cache_info->methods.get_one_virtual_pixel_from_handler=
5149 cache_methods->get_one_virtual_pixel_from_handler;
5150 get_one_authentic_pixel_from_handler=
5151 cache_methods->get_one_authentic_pixel_from_handler;
5152 if (get_one_authentic_pixel_from_handler !=
5153 (GetOneAuthenticPixelFromHandler) NULL)
5154 cache_info->methods.get_one_authentic_pixel_from_handler=
5155 cache_methods->get_one_authentic_pixel_from_handler;
5156}
5157
5158/*
5159%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5160% %
5161% %
5162% %
5163+ S e t P i x e l C a c h e N e x u s P i x e l s %
5164% %
5165% %
5166% %
5167%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5168%
5169% SetPixelCacheNexusPixels() defines the region of the cache for the
5170% specified cache nexus.
5171%
5172% The format of the SetPixelCacheNexusPixels() method is:
5173%
5174% PixelPacket SetPixelCacheNexusPixels(
5175% const CacheInfo *magick_restrcit cache_info,const MapMode mode,
5176% const ssize_t y,const size_t width,const size_t height,
5177% const MagickBooleanType buffered,NexusInfo *magick_restrict nexus_info,
5178% ExceptionInfo *exception)
5179%
5180% A description of each parameter follows:
5181%
5182% o cache_info: the pixel cache.
5183%
5184% o mode: ReadMode, WriteMode, or IOMode.
5185%
5186% o x,y,width,height: define the region of this particular cache nexus.
5187%
5188% o buffered: pixels are buffered.
5189%
5190% o nexus_info: the cache nexus to set.
5191%
5192% o exception: return any errors or warnings in this structure.
5193%
5194*/
5195
5196static inline MagickBooleanType AcquireCacheNexusPixels(
5197 const CacheInfo *magick_restrict cache_info,const MagickSizeType length,
5198 NexusInfo *magick_restrict nexus_info,ExceptionInfo *exception)
5199{
5200 if (length != (MagickSizeType) ((size_t) length))
5201 {
5202 (void) ThrowMagickException(exception,GetMagickModule(),
5203 ResourceLimitError,"PixelCacheAllocationFailed","`%s'",
5204 cache_info->filename);
5205 return(MagickFalse);
5206 }
5207 nexus_info->length=0;
5208 nexus_info->mapped=MagickFalse;
5209 if (cache_anonymous_memory <= 0)
5210 {
5211 nexus_info->cache=(PixelPacket *) MagickAssumeAligned(
5212 AcquireAlignedMemory(1,(size_t) length));
5213 if (nexus_info->cache != (PixelPacket *) NULL)
5214 (void) memset(nexus_info->cache,0,(size_t) length);
5215 }
5216 else
5217 {
5218 nexus_info->cache=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t) length);
5219 if (nexus_info->cache != (PixelPacket *) NULL)
5220 nexus_info->mapped=MagickTrue;
5221 }
5222 if (nexus_info->cache == (PixelPacket *) NULL)
5223 {
5224 (void) ThrowMagickException(exception,GetMagickModule(),
5225 ResourceLimitError,"PixelCacheAllocationFailed","`%s'",
5226 cache_info->filename);
5227 return(MagickFalse);
5228 }
5229 nexus_info->length=length;
5230 return(MagickTrue);
5231}
5232
5233static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
5234 const MapMode mode)
5235{
5236 if (nexus_info->length < CACHE_LINE_SIZE)
5237 return;
5238 if (mode == ReadMode)
5239 {
5240 MagickCachePrefetch((unsigned char *) nexus_info->pixels+CACHE_LINE_SIZE,
5241 0,1);
5242 return;
5243 }
5244 MagickCachePrefetch((unsigned char *) nexus_info->pixels+CACHE_LINE_SIZE,1,1);
5245}
5246
5247static inline MagickBooleanType ValidatePixelOffset(const ssize_t x,
5248 const size_t a)
5249{
5250 if ((x >= 0) && (x >= ((ssize_t) (MAGICK_SSIZE_MAX-5*a))))
5251 return(MagickFalse);
5252 if (x <= ((ssize_t) (MAGICK_SSIZE_MIN+5*(MagickOffsetType) a)))
5253 return(MagickFalse);
5254 return(MagickTrue);
5255}
5256
5257static PixelPacket *SetPixelCacheNexusPixels(
5258 const CacheInfo *magick_restrict cache_info,const MapMode mode,
5259 const ssize_t x,const ssize_t y,const size_t width,const size_t height,
5260 const MagickBooleanType buffered,NexusInfo *magick_restrict nexus_info,
5261 ExceptionInfo *exception)
5262{
5263 MagickBooleanType
5264 status;
5265
5266 MagickSizeType
5267 length,
5268 number_pixels;
5269
5270 assert(cache_info != (const CacheInfo *) NULL);
5271 assert(cache_info->signature == MagickCoreSignature);
5272 if (cache_info->type == UndefinedCache)
5273 return((PixelPacket *) NULL);
5274 assert(nexus_info->signature == MagickCoreSignature);
5275 (void) memset(&nexus_info->region,0,sizeof(nexus_info->region));
5276 if ((width == 0) || (height == 0))
5277 {
5278 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
5279 "NoPixelsDefinedInCache","`%s'",cache_info->filename);
5280 return((PixelPacket *) NULL);
5281 }
5282 if (((MagickSizeType) width > cache_info->width_limit) ||
5283 ((MagickSizeType) height > cache_info->height_limit))
5284 {
5285 (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
5286 "WidthOrHeightExceedsLimit","`%s'",cache_info->filename);
5287 return((PixelPacket *) NULL);
5288 }
5289 if ((ValidatePixelOffset(x,width) == MagickFalse) ||
5290 (ValidatePixelOffset(y,height) == MagickFalse))
5291 {
5292 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
5293 "InvalidPixel","`%s'",cache_info->filename);
5294 return((PixelPacket *) NULL);
5295 }
5296 if (((cache_info->type == MemoryCache) || (cache_info->type == MapCache)) &&
5297 (buffered == MagickFalse))
5298 {
5299 if (((x >= 0) && (y >= 0) &&
5300 (((ssize_t) height+y-1) < (ssize_t) cache_info->rows)) &&
5301 (((x == 0) && (width == cache_info->columns)) || ((height == 1) &&
5302 (((ssize_t) width+x-1) < (ssize_t) cache_info->columns))))
5303 {
5304 MagickOffsetType
5305 offset;
5306
5307 /*
5308 Pixels are accessed directly from memory.
5309 */
5310 if (IsValidPixelOffset(y,cache_info->columns) == MagickFalse)
5311 return((PixelPacket *) NULL);
5312 offset=y*(MagickOffsetType) cache_info->columns+x;
5313 nexus_info->pixels=cache_info->pixels+offset;
5314 nexus_info->indexes=(IndexPacket *) NULL;
5315 if (cache_info->active_index_channel != MagickFalse)
5316 nexus_info->indexes=cache_info->indexes+offset;
5317 nexus_info->region.width=width;
5318 nexus_info->region.height=height;
5319 nexus_info->region.x=x;
5320 nexus_info->region.y=y;
5321 nexus_info->authentic_pixel_cache=MagickTrue;
5322 PrefetchPixelCacheNexusPixels(nexus_info,mode);
5323 return(nexus_info->pixels);
5324 }
5325 }
5326 /*
5327 Pixels are stored in a staging region until they are synced to the cache.
5328 */
5329 number_pixels=(MagickSizeType) width*height;
5330 length=MagickMax(number_pixels,MagickMax(cache_info->columns,
5331 cache_info->rows))*sizeof(PixelPacket);
5332 if (cache_info->active_index_channel != MagickFalse)
5333 length+=number_pixels*sizeof(IndexPacket);
5334 status=MagickTrue;
5335 if (nexus_info->cache == (PixelPacket *) NULL)
5336 status=AcquireCacheNexusPixels(cache_info,length,nexus_info,exception);
5337 else
5338 if (nexus_info->length < length)
5339 {
5340 RelinquishCacheNexusPixels(nexus_info);
5341 status=AcquireCacheNexusPixels(cache_info,length,nexus_info,exception);
5342 }
5343 if (status == MagickFalse)
5344 {
5345 (void) memset(&nexus_info->region,0,sizeof(nexus_info->region));
5346 return((PixelPacket *) NULL);
5347 }
5348 nexus_info->pixels=nexus_info->cache;
5349 nexus_info->indexes=(IndexPacket *) NULL;
5350 if (cache_info->active_index_channel != MagickFalse)
5351 nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
5352 nexus_info->region.width=width;
5353 nexus_info->region.height=height;
5354 nexus_info->region.x=x;
5355 nexus_info->region.y=y;
5356 nexus_info->authentic_pixel_cache=cache_info->type == PingCache ?
5357 MagickTrue : MagickFalse;
5358 PrefetchPixelCacheNexusPixels(nexus_info,mode);
5359 return(nexus_info->pixels);
5360}
5361
5362/*
5363%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5364% %
5365% %
5366% %
5367% 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 %
5368% %
5369% %
5370% %
5371%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5372%
5373% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5374% pixel cache and returns the previous setting. A virtual pixel is any pixel
5375% access that is outside the boundaries of the image cache.
5376%
5377% The format of the SetPixelCacheVirtualMethod() method is:
5378%
5379% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5380% const VirtualPixelMethod virtual_pixel_method)
5381%
5382% A description of each parameter follows:
5383%
5384% o image: the image.
5385%
5386% o virtual_pixel_method: choose the type of virtual pixel.
5387%
5388*/
5389
5390static MagickBooleanType SetCacheAlphaChannel(Image *image,
5391 const Quantum opacity)
5392{
5393 CacheView
5394 *magick_restrict image_view;
5395
5396 MagickBooleanType
5397 status;
5398
5399 ssize_t
5400 y;
5401
5402 assert(image != (Image *) NULL);
5403 assert(image->signature == MagickCoreSignature);
5404 if (IsEventLogging() != MagickFalse)
5405 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5406 assert(image->cache != (Cache) NULL);
5407 image->matte=MagickTrue;
5408 status=MagickTrue;
5409 image_view=AcquireVirtualCacheView(image,&image->exception); /* must be virtual */
5410#if defined(MAGICKCORE_OPENMP_SUPPORT)
5411 #pragma omp parallel for schedule(static) shared(status) \
5412 magick_number_threads(image,image,image->rows,2)
5413#endif
5414 for (y=0; y < (ssize_t) image->rows; y++)
5415 {
5416 PixelPacket
5417 *magick_restrict q;
5418
5419 ssize_t
5420 x;
5421
5422 if (status == MagickFalse)
5423 continue;
5424 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
5425 &image->exception);
5426 if (q == (PixelPacket *) NULL)
5427 {
5428 status=MagickFalse;
5429 continue;
5430 }
5431 for (x=0; x < (ssize_t) image->columns; x++)
5432 {
5433 q->opacity=opacity;
5434 q++;
5435 }
5436 status=SyncCacheViewAuthenticPixels(image_view,&image->exception);
5437 }
5438 image_view=DestroyCacheView(image_view);
5439 return(status);
5440}
5441
5442MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5443 const VirtualPixelMethod virtual_pixel_method)
5444{
5445 CacheInfo
5446 *magick_restrict cache_info;
5447
5448 VirtualPixelMethod
5449 method;
5450
5451 assert(image != (Image *) NULL);
5452 assert(image->signature == MagickCoreSignature);
5453 if (IsEventLogging() != MagickFalse)
5454 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5455 assert(image->cache != (Cache) NULL);
5456 cache_info=(CacheInfo *) image->cache;
5457 assert(cache_info->signature == MagickCoreSignature);
5458 method=cache_info->virtual_pixel_method;
5459 cache_info->virtual_pixel_method=virtual_pixel_method;
5460 if ((image->columns != 0) && (image->rows != 0))
5461 switch (virtual_pixel_method)
5462 {
5463 case BackgroundVirtualPixelMethod:
5464 {
5465 if ((image->background_color.opacity != OpaqueOpacity) &&
5466 (image->matte == MagickFalse))
5467 (void) SetCacheAlphaChannel((Image *) image,OpaqueOpacity);
5468 if ((IsPixelGray(&image->background_color) == MagickFalse) &&
5469 (IsGrayColorspace(image->colorspace) != MagickFalse))
5470 (void) SetImageColorspace((Image *) image,sRGBColorspace);
5471 break;
5472 }
5473 case TransparentVirtualPixelMethod:
5474 {
5475 if (image->matte == MagickFalse)
5476 (void) SetCacheAlphaChannel((Image *) image,OpaqueOpacity);
5477 break;
5478 }
5479 default:
5480 break;
5481 }
5482 return(method);
5483}
5484
5485#if defined(MAGICKCORE_OPENCL_SUPPORT)
5486/*
5487%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5488% %
5489% %
5490% %
5491+ 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 %
5492% %
5493% %
5494% %
5495%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5496%
5497% SyncAuthenticOpenCLBuffer() ensures all the OpenCL operations have been
5498% completed and updates the host memory.
5499%
5500% The format of the SyncAuthenticOpenCLBuffer() method is:
5501%
5502% void SyncAuthenticOpenCLBuffer(const Image *image)
5503%
5504% A description of each parameter follows:
5505%
5506% o image: the image.
5507%
5508*/
5509static void CopyOpenCLBuffer(CacheInfo *magick_restrict cache_info)
5510{
5511 MagickCLEnv
5512 clEnv;
5513
5514 assert(cache_info != (CacheInfo *)NULL);
5515 if ((cache_info->type != MemoryCache) ||
5516 (cache_info->opencl == (OpenCLCacheInfo *)NULL))
5517 return;
5518 /*
5519 Ensure single threaded access to OpenCL environment.
5520 */
5521 LockSemaphoreInfo(cache_info->semaphore);
5522 if (cache_info->opencl != (OpenCLCacheInfo *)NULL)
5523 {
5524 cl_event
5525 *events;
5526
5527 cl_uint
5528 event_count;
5529
5530 clEnv=GetDefaultOpenCLEnv();
5531 events=CopyOpenCLEvents(cache_info->opencl,&event_count);
5532 if (events != (cl_event *) NULL)
5533 {
5534 cl_command_queue
5535 queue;
5536
5537 cl_context
5538 context;
5539
5540 cl_int
5541 status;
5542
5543 PixelPacket
5544 *pixels;
5545
5546 context=GetOpenCLContext(clEnv);
5547 queue=AcquireOpenCLCommandQueue(clEnv);
5548 pixels=(PixelPacket *) clEnv->library->clEnqueueMapBuffer(queue,
5549 cache_info->opencl->buffer,CL_TRUE, CL_MAP_READ | CL_MAP_WRITE,0,
5550 cache_info->length,event_count,events,NULL,&status);
5551 assert(pixels == cache_info->pixels);
5552 events=(cl_event *) RelinquishMagickMemory(events);
5553 RelinquishOpenCLCommandQueue(clEnv,queue);
5554 }
5555 cache_info->opencl=RelinquishOpenCLCacheInfo(clEnv,cache_info->opencl);
5556 }
5557 UnlockSemaphoreInfo(cache_info->semaphore);
5558}
5559
5560MagickPrivate void SyncAuthenticOpenCLBuffer(const Image *image)
5561{
5562 CacheInfo
5563 *magick_restrict cache_info;
5564
5565 assert(image != (Image *)NULL);
5566 cache_info = (CacheInfo *)image->cache;
5567 CopyOpenCLBuffer(cache_info);
5568}
5569#endif
5570
5571/*
5572%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5573% %
5574% %
5575% %
5576+ 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 %
5577% %
5578% %
5579% %
5580%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5581%
5582% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5583% in-memory or disk cache. The method returns MagickTrue if the pixel region
5584% is synced, otherwise MagickFalse.
5585%
5586% The format of the SyncAuthenticPixelCacheNexus() method is:
5587%
5588% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5589% NexusInfo *nexus_info,ExceptionInfo *exception)
5590%
5591% A description of each parameter follows:
5592%
5593% o image: the image.
5594%
5595% o nexus_info: the cache nexus to sync.
5596%
5597% o exception: return any errors or warnings in this structure.
5598%
5599*/
5600MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5601 NexusInfo *magick_restrict nexus_info,ExceptionInfo *exception)
5602{
5603 CacheInfo
5604 *magick_restrict cache_info;
5605
5606 MagickBooleanType
5607 status;
5608
5609 /*
5610 Transfer pixels to the cache.
5611 */
5612 assert(image != (Image *) NULL);
5613 assert(image->signature == MagickCoreSignature);
5614 if (image->cache == (Cache) NULL)
5615 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5616 cache_info=(CacheInfo *) image->cache;
5617 assert(cache_info->signature == MagickCoreSignature);
5618 if (cache_info->type == UndefinedCache)
5619 return(MagickFalse);
5620 if ((image->storage_class == DirectClass) &&
5621 (image->clip_mask != (Image *) NULL) &&
5622 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5623 return(MagickFalse);
5624 if ((image->storage_class == DirectClass) &&
5625 (image->mask != (Image *) NULL) &&
5626 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5627 return(MagickFalse);
5628 if (nexus_info->authentic_pixel_cache != MagickFalse)
5629 {
5630 if (image->taint == MagickFalse)
5631 image->taint=MagickTrue;
5632 return(MagickTrue);
5633 }
5634 assert(cache_info->signature == MagickCoreSignature);
5635 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5636 if ((cache_info->active_index_channel != MagickFalse) &&
5637 (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
5638 return(MagickFalse);
5639 if ((status != MagickFalse) && (image->taint == MagickFalse))
5640 image->taint=MagickTrue;
5641 return(status);
5642}
5643
5644/*
5645%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5646% %
5647% %
5648% %
5649+ S y n c A u t h e n t i c P i x e l C a c h e %
5650% %
5651% %
5652% %
5653%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5654%
5655% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5656% or disk cache. The method returns MagickTrue if the pixel region is synced,
5657% otherwise MagickFalse.
5658%
5659% The format of the SyncAuthenticPixelsCache() method is:
5660%
5661% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5662% ExceptionInfo *exception)
5663%
5664% A description of each parameter follows:
5665%
5666% o image: the image.
5667%
5668% o exception: return any errors or warnings in this structure.
5669%
5670*/
5671static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5672 ExceptionInfo *exception)
5673{
5674 CacheInfo
5675 *magick_restrict cache_info;
5676
5677 const int
5678 id = GetOpenMPThreadId();
5679
5680 MagickBooleanType
5681 status;
5682
5683 assert(image != (Image *) NULL);
5684 assert(image->signature == MagickCoreSignature);
5685 assert(image->cache != (Cache) NULL);
5686 cache_info=(CacheInfo *) image->cache;
5687 assert(cache_info->signature == MagickCoreSignature);
5688 assert(id < (int) cache_info->number_threads);
5689 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5690 exception);
5691 return(status);
5692}
5693
5694/*
5695%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5696% %
5697% %
5698% %
5699% S y n c A u t h e n t i c P i x e l s %
5700% %
5701% %
5702% %
5703%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5704%
5705% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5706% The method returns MagickTrue if the pixel region is flushed, otherwise
5707% MagickFalse.
5708%
5709% The format of the SyncAuthenticPixels() method is:
5710%
5711% MagickBooleanType SyncAuthenticPixels(Image *image,
5712% ExceptionInfo *exception)
5713%
5714% A description of each parameter follows:
5715%
5716% o image: the image.
5717%
5718% o exception: return any errors or warnings in this structure.
5719%
5720*/
5721MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5722 ExceptionInfo *exception)
5723{
5724 CacheInfo
5725 *magick_restrict cache_info;
5726
5727 const int
5728 id = GetOpenMPThreadId();
5729
5730 MagickBooleanType
5731 status;
5732
5733 assert(image != (Image *) NULL);
5734 assert(image->signature == MagickCoreSignature);
5735 assert(image->cache != (Cache) NULL);
5736 cache_info=(CacheInfo *) image->cache;
5737 assert(cache_info->signature == MagickCoreSignature);
5738 if (cache_info->methods.sync_authentic_pixels_handler !=
5739 (SyncAuthenticPixelsHandler) NULL)
5740 return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
5741 assert(id < (int) cache_info->number_threads);
5742 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5743 exception);
5744 return(status);
5745}
5746
5747/*
5748%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5749% %
5750% %
5751% %
5752+ S y n c I m a g e P i x e l C a c h e %
5753% %
5754% %
5755% %
5756%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5757%
5758% SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5759% The method returns MagickTrue if the pixel region is flushed, otherwise
5760% MagickFalse.
5761%
5762% The format of the SyncImagePixelCache() method is:
5763%
5764% MagickBooleanType SyncImagePixelCache(Image *image,
5765% ExceptionInfo *exception)
5766%
5767% A description of each parameter follows:
5768%
5769% o image: the image.
5770%
5771% o exception: return any errors or warnings in this structure.
5772%
5773*/
5774MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5775 ExceptionInfo *exception)
5776{
5777 CacheInfo
5778 *magick_restrict cache_info;
5779
5780 assert(image != (Image *) NULL);
5781 assert(exception != (ExceptionInfo *) NULL);
5782 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5783 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5784}
5785
5786/*
5787%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5788% %
5789% %
5790% %
5791+ W r i t e P i x e l C a c h e I n d e x e s %
5792% %
5793% %
5794% %
5795%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5796%
5797% WritePixelCacheIndexes() writes the colormap indexes to the specified
5798% region of the pixel cache.
5799%
5800% The format of the WritePixelCacheIndexes() method is:
5801%
5802% MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5803% NexusInfo *nexus_info,ExceptionInfo *exception)
5804%
5805% A description of each parameter follows:
5806%
5807% o cache_info: the pixel cache.
5808%
5809% o nexus_info: the cache nexus to write the colormap indexes.
5810%
5811% o exception: return any errors or warnings in this structure.
5812%
5813*/
5814static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5815 NexusInfo *magick_restrict nexus_info,ExceptionInfo *exception)
5816{
5817 MagickOffsetType
5818 count,
5819 offset;
5820
5821 MagickSizeType
5822 extent,
5823 length;
5824
5825 const IndexPacket
5826 *magick_restrict p;
5827
5828 ssize_t
5829 y;
5830
5831 size_t
5832 rows;
5833
5834 if (cache_info->active_index_channel == MagickFalse)
5835 return(MagickFalse);
5836 if (nexus_info->authentic_pixel_cache != MagickFalse)
5837 return(MagickTrue);
5838 if (nexus_info->indexes == (IndexPacket *) NULL)
5839 return(MagickFalse);
5840 if (IsValidPixelOffset(nexus_info->region.y,cache_info->columns) == MagickFalse)
5841 return(MagickFalse);
5842 offset=nexus_info->region.y*(MagickOffsetType) cache_info->columns+
5843 nexus_info->region.x;
5844 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
5845 rows=nexus_info->region.height;
5846 extent=(MagickSizeType) length*rows;
5847 p=nexus_info->indexes;
5848 y=0;
5849 switch (cache_info->type)
5850 {
5851 case MemoryCache:
5852 case MapCache:
5853 {
5854 IndexPacket
5855 *magick_restrict q;
5856
5857 /*
5858 Write indexes to memory.
5859 */
5860 if ((cache_info->columns == nexus_info->region.width) &&
5861 (extent == (MagickSizeType) ((size_t) extent)))
5862 {
5863 length=extent;
5864 rows=1UL;
5865 }
5866 q=cache_info->indexes+offset;
5867 for (y=0; y < (ssize_t) rows; y++)
5868 {
5869 (void) memcpy(q,p,(size_t) length);
5870 p+=(ptrdiff_t) nexus_info->region.width;
5871 q+=(ptrdiff_t) cache_info->columns;
5872 }
5873 break;
5874 }
5875 case DiskCache:
5876 {
5877 /*
5878 Write indexes to disk.
5879 */
5880 LockSemaphoreInfo(cache_info->file_semaphore);
5881 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5882 {
5883 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5884 cache_info->cache_filename);
5885 UnlockSemaphoreInfo(cache_info->file_semaphore);
5886 return(MagickFalse);
5887 }
5888 if ((cache_info->columns == nexus_info->region.width) &&
5889 (extent <= MagickMaxBufferExtent))
5890 {
5891 length=extent;
5892 rows=1UL;
5893 }
5894 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5895 for (y=0; y < (ssize_t) rows; y++)
5896 {
5897 count=WritePixelCacheRegion(cache_info,cache_info->offset+
5898 (MagickOffsetType) extent*(MagickOffsetType) sizeof(PixelPacket)+
5899 offset*(MagickOffsetType) sizeof(*p),length,(const unsigned char *)
5900 p);
5901 if (count < (MagickOffsetType) length)
5902 break;
5903 p+=(ptrdiff_t) nexus_info->region.width;
5904 offset+=(MagickOffsetType) cache_info->columns;
5905 }
5906 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5907 (void) ClosePixelCacheOnDisk(cache_info);
5908 UnlockSemaphoreInfo(cache_info->file_semaphore);
5909 break;
5910 }
5911 case DistributedCache:
5912 {
5913 RectangleInfo
5914 region;
5915
5916 /*
5917 Write indexes to distributed cache.
5918 */
5919 LockSemaphoreInfo(cache_info->file_semaphore);
5920 region=nexus_info->region;
5921 if ((cache_info->columns != nexus_info->region.width) ||
5922 (extent > MagickMaxBufferExtent))
5923 region.height=1UL;
5924 else
5925 {
5926 length=extent;
5927 rows=1UL;
5928 }
5929 for (y=0; y < (ssize_t) rows; y++)
5930 {
5931 count=WriteDistributePixelCacheIndexes((DistributeCacheInfo *)
5932 cache_info->server_info,&region,length,(const unsigned char *) p);
5933 if (count != (MagickOffsetType) length)
5934 break;
5935 p+=(ptrdiff_t) nexus_info->region.width;
5936 region.y++;
5937 }
5938 UnlockSemaphoreInfo(cache_info->file_semaphore);
5939 break;
5940 }
5941 default:
5942 break;
5943 }
5944 if (y < (ssize_t) rows)
5945 {
5946 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5947 cache_info->cache_filename);
5948 return(MagickFalse);
5949 }
5950 if ((cache_info->debug != MagickFalse) &&
5951 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5952 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5953 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5954 nexus_info->region.width,(double) nexus_info->region.height,(double)
5955 nexus_info->region.x,(double) nexus_info->region.y);
5956 return(MagickTrue);
5957}
5958
5959/*
5960%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5961% %
5962% %
5963% %
5964+ W r i t e P i x e l C a c h e P i x e l s %
5965% %
5966% %
5967% %
5968%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5969%
5970% WritePixelCachePixels() writes image pixels to the specified region of the
5971% pixel cache.
5972%
5973% The format of the WritePixelCachePixels() method is:
5974%
5975% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5976% NexusInfo *nexus_info,ExceptionInfo *exception)
5977%
5978% A description of each parameter follows:
5979%
5980% o cache_info: the pixel cache.
5981%
5982% o nexus_info: the cache nexus to write the pixels.
5983%
5984% o exception: return any errors or warnings in this structure.
5985%
5986*/
5987static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5988 NexusInfo *magick_restrict nexus_info,ExceptionInfo *exception)
5989{
5990 MagickOffsetType
5991 count,
5992 offset;
5993
5994 MagickSizeType
5995 extent,
5996 length;
5997
5998 const PixelPacket
5999 *magick_restrict p;
6000
6001 ssize_t
6002 y;
6003
6004 size_t
6005 rows;
6006
6007 if (nexus_info->authentic_pixel_cache != MagickFalse)
6008 return(MagickTrue);
6009 if (IsValidPixelOffset(nexus_info->region.y,cache_info->columns) == MagickFalse)
6010 return(MagickFalse);
6011 offset=nexus_info->region.y*(MagickOffsetType) cache_info->columns+
6012 nexus_info->region.x;
6013 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
6014 rows=nexus_info->region.height;
6015 extent=length*rows;
6016 p=nexus_info->pixels;
6017 y=0;
6018 switch (cache_info->type)
6019 {
6020 case MemoryCache:
6021 case MapCache:
6022 {
6023 PixelPacket
6024 *magick_restrict q;
6025
6026 /*
6027 Write pixels to memory.
6028 */
6029 if ((cache_info->columns == nexus_info->region.width) &&
6030 (extent == (MagickSizeType) ((size_t) extent)))
6031 {
6032 length=extent;
6033 rows=1UL;
6034 }
6035 q=cache_info->pixels+offset;
6036 for (y=0; y < (ssize_t) rows; y++)
6037 {
6038 (void) memcpy(q,p,(size_t) length);
6039 p+=(ptrdiff_t) nexus_info->region.width;
6040 q+=(ptrdiff_t) cache_info->columns;
6041 }
6042 break;
6043 }
6044 case DiskCache:
6045 {
6046 /*
6047 Write pixels to disk.
6048 */
6049 LockSemaphoreInfo(cache_info->file_semaphore);
6050 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
6051 {
6052 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
6053 cache_info->cache_filename);
6054 UnlockSemaphoreInfo(cache_info->file_semaphore);
6055 return(MagickFalse);
6056 }
6057 if ((cache_info->columns == nexus_info->region.width) &&
6058 (extent <= MagickMaxBufferExtent))
6059 {
6060 length=extent;
6061 rows=1UL;
6062 }
6063 for (y=0; y < (ssize_t) rows; y++)
6064 {
6065 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
6066 (MagickOffsetType) sizeof(*p),length,(const unsigned char *) p);
6067 if (count < (MagickOffsetType) length)
6068 break;
6069 p+=(ptrdiff_t) nexus_info->region.width;
6070 offset+=(MagickOffsetType) cache_info->columns;
6071 }
6072 if (IsFileDescriptorLimitExceeded() != MagickFalse)
6073 (void) ClosePixelCacheOnDisk(cache_info);
6074 UnlockSemaphoreInfo(cache_info->file_semaphore);
6075 break;
6076 }
6077 case DistributedCache:
6078 {
6079 RectangleInfo
6080 region;
6081
6082 /*
6083 Write pixels to distributed cache.
6084 */
6085 LockSemaphoreInfo(cache_info->file_semaphore);
6086 region=nexus_info->region;
6087 if ((cache_info->columns != nexus_info->region.width) ||
6088 (extent > MagickMaxBufferExtent))
6089 region.height=1UL;
6090 else
6091 {
6092 length=extent;
6093 rows=1UL;
6094 }
6095 for (y=0; y < (ssize_t) rows; y++)
6096 {
6097 count=WriteDistributePixelCachePixels((DistributeCacheInfo *)
6098 cache_info->server_info,&region,length,(const unsigned char *) p);
6099 if (count != (MagickOffsetType) length)
6100 break;
6101 p+=(ptrdiff_t) nexus_info->region.width;
6102 region.y++;
6103 }
6104 UnlockSemaphoreInfo(cache_info->file_semaphore);
6105 break;
6106 }
6107 default:
6108 break;
6109 }
6110 if (y < (ssize_t) rows)
6111 {
6112 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
6113 cache_info->cache_filename);
6114 return(MagickFalse);
6115 }
6116 if ((cache_info->debug != MagickFalse) &&
6117 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
6118 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
6119 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
6120 nexus_info->region.width,(double) nexus_info->region.height,(double)
6121 nexus_info->region.x,(double) nexus_info->region.y);
6122 return(MagickTrue);
6123}