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