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