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