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