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