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