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