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