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 % G e t A u t h e n t i c M e t a c o n t e n t %
1143 % %
1144 % %
1145 % %
1146 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1147 %
1148 % GetAuthenticMetacontent() returns the authentic metacontent corresponding
1149 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1150 % returned if the associated pixels are not available.
1151 %
1152 % The format of the GetAuthenticMetacontent() method is:
1153 %
1154 % void *GetAuthenticMetacontent(const Image *image)
1155 %
1156 % A description of each parameter follows:
1157 %
1158 % o image: the image.
1159 %
1160 */
GetAuthenticMetacontent(const Image * image)1161 MagickExport void *GetAuthenticMetacontent(const Image *image)
1162 {
1163 CacheInfo
1164 *magick_restrict cache_info;
1165
1166 const int
1167 id = GetOpenMPThreadId();
1168
1169 assert(image != (const Image *) NULL);
1170 assert(image->signature == MagickCoreSignature);
1171 assert(image->cache != (Cache) NULL);
1172 cache_info=(CacheInfo *) image->cache;
1173 assert(cache_info->signature == MagickCoreSignature);
1174 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1175 (GetAuthenticMetacontentFromHandler) NULL)
1176 {
1177 void
1178 *metacontent;
1179
1180 metacontent=cache_info->methods.
1181 get_authentic_metacontent_from_handler(image);
1182 return(metacontent);
1183 }
1184 assert(id < (int) cache_info->number_threads);
1185 return(cache_info->nexus_info[id]->metacontent);
1186 }
1187
1188 /*
1189 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1190 % %
1191 % %
1192 % %
1193 + 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 %
1194 % %
1195 % %
1196 % %
1197 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1198 %
1199 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1200 % with the last call to QueueAuthenticPixelsCache() or
1201 % GetAuthenticPixelsCache().
1202 %
1203 % The format of the GetAuthenticMetacontentFromCache() method is:
1204 %
1205 % void *GetAuthenticMetacontentFromCache(const Image *image)
1206 %
1207 % A description of each parameter follows:
1208 %
1209 % o image: the image.
1210 %
1211 */
GetAuthenticMetacontentFromCache(const Image * image)1212 static void *GetAuthenticMetacontentFromCache(const Image *image)
1213 {
1214 CacheInfo
1215 *magick_restrict cache_info;
1216
1217 const int
1218 id = GetOpenMPThreadId();
1219
1220 assert(image != (const Image *) NULL);
1221 assert(image->signature == MagickCoreSignature);
1222 assert(image->cache != (Cache) NULL);
1223 cache_info=(CacheInfo *) image->cache;
1224 assert(cache_info->signature == MagickCoreSignature);
1225 assert(id < (int) cache_info->number_threads);
1226 return(cache_info->nexus_info[id]->metacontent);
1227 }
1228
1229 #if defined(MAGICKCORE_OPENCL_SUPPORT)
1230 /*
1231 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1232 % %
1233 % %
1234 % %
1235 + G e t A u t h e n t i c O p e n C L B u f f e r %
1236 % %
1237 % %
1238 % %
1239 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1240 %
1241 % GetAuthenticOpenCLBuffer() returns an OpenCL buffer used to execute OpenCL
1242 % operations.
1243 %
1244 % The format of the GetAuthenticOpenCLBuffer() method is:
1245 %
1246 % cl_mem GetAuthenticOpenCLBuffer(const Image *image,
1247 % MagickCLDevice device,ExceptionInfo *exception)
1248 %
1249 % A description of each parameter follows:
1250 %
1251 % o image: the image.
1252 %
1253 % o device: the device to use.
1254 %
1255 % o exception: return any errors or warnings in this structure.
1256 %
1257 */
GetAuthenticOpenCLBuffer(const Image * image,MagickCLDevice device,ExceptionInfo * exception)1258 MagickPrivate cl_mem GetAuthenticOpenCLBuffer(const Image *image,
1259 MagickCLDevice device,ExceptionInfo *exception)
1260 {
1261 CacheInfo
1262 *magick_restrict cache_info;
1263
1264 assert(image != (const Image *) NULL);
1265 assert(device != (const MagickCLDevice) NULL);
1266 cache_info=(CacheInfo *) image->cache;
1267 if ((cache_info->type == UndefinedCache) || (cache_info->reference_count > 1))
1268 {
1269 SyncImagePixelCache((Image *) image,exception);
1270 cache_info=(CacheInfo *) image->cache;
1271 }
1272 if ((cache_info->type != MemoryCache) || (cache_info->mapped != MagickFalse))
1273 return((cl_mem) NULL);
1274 LockSemaphoreInfo(cache_info->semaphore);
1275 if ((cache_info->opencl != (MagickCLCacheInfo) NULL) &&
1276 (cache_info->opencl->device->context != device->context))
1277 cache_info->opencl=CopyMagickCLCacheInfo(cache_info->opencl);
1278 if (cache_info->opencl == (MagickCLCacheInfo) NULL)
1279 {
1280 assert(cache_info->pixels != (Quantum *) NULL);
1281 cache_info->opencl=AcquireMagickCLCacheInfo(device,cache_info->pixels,
1282 cache_info->length);
1283 }
1284 if (cache_info->opencl != (MagickCLCacheInfo) NULL)
1285 RetainOpenCLMemObject(cache_info->opencl->buffer);
1286 UnlockSemaphoreInfo(cache_info->semaphore);
1287 if (cache_info->opencl == (MagickCLCacheInfo) NULL)
1288 return((cl_mem) NULL);
1289 assert(cache_info->opencl->pixels == cache_info->pixels);
1290 return(cache_info->opencl->buffer);
1291 }
1292 #endif
1293
1294 /*
1295 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1296 % %
1297 % %
1298 % %
1299 + 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 %
1300 % %
1301 % %
1302 % %
1303 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1304 %
1305 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1306 % disk pixel cache as defined by the geometry parameters. A pointer to the
1307 % pixels is returned if the pixels are transferred, otherwise a NULL is
1308 % returned.
1309 %
1310 % The format of the GetAuthenticPixelCacheNexus() method is:
1311 %
1312 % Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1313 % const ssize_t y,const size_t columns,const size_t rows,
1314 % NexusInfo *nexus_info,ExceptionInfo *exception)
1315 %
1316 % A description of each parameter follows:
1317 %
1318 % o image: the image.
1319 %
1320 % o x,y,columns,rows: These values define the perimeter of a region of
1321 % pixels.
1322 %
1323 % o nexus_info: the cache nexus to return.
1324 %
1325 % o exception: return any errors or warnings in this structure.
1326 %
1327 */
1328
GetAuthenticPixelCacheNexus(Image * image,const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,NexusInfo * nexus_info,ExceptionInfo * exception)1329 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1330 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
1331 ExceptionInfo *exception)
1332 {
1333 CacheInfo
1334 *magick_restrict cache_info;
1335
1336 Quantum
1337 *magick_restrict pixels;
1338
1339 /*
1340 Transfer pixels from the cache.
1341 */
1342 assert(image != (Image *) NULL);
1343 assert(image->signature == MagickCoreSignature);
1344 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,
1345 nexus_info,exception);
1346 if (pixels == (Quantum *) NULL)
1347 return((Quantum *) NULL);
1348 cache_info=(CacheInfo *) image->cache;
1349 assert(cache_info->signature == MagickCoreSignature);
1350 if (nexus_info->authentic_pixel_cache != MagickFalse)
1351 return(pixels);
1352 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1353 return((Quantum *) NULL);
1354 if (cache_info->metacontent_extent != 0)
1355 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1356 return((Quantum *) NULL);
1357 return(pixels);
1358 }
1359
1360 /*
1361 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1362 % %
1363 % %
1364 % %
1365 + 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 %
1366 % %
1367 % %
1368 % %
1369 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1370 %
1371 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1372 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1373 %
1374 % The format of the GetAuthenticPixelsFromCache() method is:
1375 %
1376 % Quantum *GetAuthenticPixelsFromCache(const Image image)
1377 %
1378 % A description of each parameter follows:
1379 %
1380 % o image: the image.
1381 %
1382 */
GetAuthenticPixelsFromCache(const Image * image)1383 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1384 {
1385 CacheInfo
1386 *magick_restrict cache_info;
1387
1388 const int
1389 id = GetOpenMPThreadId();
1390
1391 assert(image != (const Image *) NULL);
1392 assert(image->signature == MagickCoreSignature);
1393 assert(image->cache != (Cache) NULL);
1394 cache_info=(CacheInfo *) image->cache;
1395 assert(cache_info->signature == MagickCoreSignature);
1396 assert(id < (int) cache_info->number_threads);
1397 return(cache_info->nexus_info[id]->pixels);
1398 }
1399
1400 /*
1401 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1402 % %
1403 % %
1404 % %
1405 % G e t A u t h e n t i c P i x e l Q u e u e %
1406 % %
1407 % %
1408 % %
1409 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1410 %
1411 % GetAuthenticPixelQueue() returns the authentic pixels associated
1412 % corresponding with the last call to QueueAuthenticPixels() or
1413 % GetAuthenticPixels().
1414 %
1415 % The format of the GetAuthenticPixelQueue() method is:
1416 %
1417 % Quantum *GetAuthenticPixelQueue(const Image image)
1418 %
1419 % A description of each parameter follows:
1420 %
1421 % o image: the image.
1422 %
1423 */
GetAuthenticPixelQueue(const Image * image)1424 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1425 {
1426 CacheInfo
1427 *magick_restrict cache_info;
1428
1429 const int
1430 id = GetOpenMPThreadId();
1431
1432 assert(image != (const Image *) NULL);
1433 assert(image->signature == MagickCoreSignature);
1434 assert(image->cache != (Cache) NULL);
1435 cache_info=(CacheInfo *) image->cache;
1436 assert(cache_info->signature == MagickCoreSignature);
1437 if (cache_info->methods.get_authentic_pixels_from_handler !=
1438 (GetAuthenticPixelsFromHandler) NULL)
1439 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1440 assert(id < (int) cache_info->number_threads);
1441 return(cache_info->nexus_info[id]->pixels);
1442 }
1443
1444 /*
1445 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1446 % %
1447 % %
1448 % %
1449 % G e t A u t h e n t i c P i x e l s %
1450 % %
1451 % %
1452 % %
1453 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1454 %
1455 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1456 % region is successfully accessed, a pointer to a Quantum array
1457 % representing the region is returned, otherwise NULL is returned.
1458 %
1459 % The returned pointer may point to a temporary working copy of the pixels
1460 % or it may point to the original pixels in memory. Performance is maximized
1461 % if the selected region is part of one row, or one or more full rows, since
1462 % then there is opportunity to access the pixels in-place (without a copy)
1463 % if the image is in memory, or in a memory-mapped file. The returned pointer
1464 % must *never* be deallocated by the user.
1465 %
1466 % Pixels accessed via the returned pointer represent a simple array of type
1467 % Quantum. If the image has corresponding metacontent,call
1468 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1469 % meta-content corresponding to the region. Once the Quantum array has
1470 % been updated, the changes must be saved back to the underlying image using
1471 % SyncAuthenticPixels() or they may be lost.
1472 %
1473 % The format of the GetAuthenticPixels() method is:
1474 %
1475 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1476 % const ssize_t y,const size_t columns,const size_t rows,
1477 % ExceptionInfo *exception)
1478 %
1479 % A description of each parameter follows:
1480 %
1481 % o image: the image.
1482 %
1483 % o x,y,columns,rows: These values define the perimeter of a region of
1484 % pixels.
1485 %
1486 % o exception: return any errors or warnings in this structure.
1487 %
1488 */
GetAuthenticPixels(Image * image,const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,ExceptionInfo * exception)1489 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1490 const ssize_t y,const size_t columns,const size_t rows,
1491 ExceptionInfo *exception)
1492 {
1493 CacheInfo
1494 *magick_restrict cache_info;
1495
1496 const int
1497 id = GetOpenMPThreadId();
1498
1499 Quantum
1500 *pixels;
1501
1502 assert(image != (Image *) NULL);
1503 assert(image->signature == MagickCoreSignature);
1504 assert(image->cache != (Cache) NULL);
1505 cache_info=(CacheInfo *) image->cache;
1506 assert(cache_info->signature == MagickCoreSignature);
1507 if (cache_info->methods.get_authentic_pixels_handler !=
1508 (GetAuthenticPixelsHandler) NULL)
1509 {
1510 pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1511 rows,exception);
1512 return(pixels);
1513 }
1514 assert(id < (int) cache_info->number_threads);
1515 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1516 cache_info->nexus_info[id],exception);
1517 return(pixels);
1518 }
1519
1520 /*
1521 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1522 % %
1523 % %
1524 % %
1525 + G e t A u t h e n t i c P i x e l s C a c h e %
1526 % %
1527 % %
1528 % %
1529 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1530 %
1531 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1532 % as defined by the geometry parameters. A pointer to the pixels is returned
1533 % if the pixels are transferred, otherwise a NULL is returned.
1534 %
1535 % The format of the GetAuthenticPixelsCache() method is:
1536 %
1537 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1538 % const ssize_t y,const size_t columns,const size_t rows,
1539 % ExceptionInfo *exception)
1540 %
1541 % A description of each parameter follows:
1542 %
1543 % o image: the image.
1544 %
1545 % o x,y,columns,rows: These values define the perimeter of a region of
1546 % pixels.
1547 %
1548 % o exception: return any errors or warnings in this structure.
1549 %
1550 */
GetAuthenticPixelsCache(Image * image,const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,ExceptionInfo * exception)1551 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1552 const ssize_t y,const size_t columns,const size_t rows,
1553 ExceptionInfo *exception)
1554 {
1555 CacheInfo
1556 *magick_restrict cache_info;
1557
1558 const int
1559 id = GetOpenMPThreadId();
1560
1561 Quantum
1562 *magick_restrict pixels;
1563
1564 assert(image != (const Image *) NULL);
1565 assert(image->signature == MagickCoreSignature);
1566 assert(image->cache != (Cache) NULL);
1567 cache_info=(CacheInfo *) image->cache;
1568 if (cache_info == (Cache) NULL)
1569 return((Quantum *) NULL);
1570 assert(cache_info->signature == MagickCoreSignature);
1571 assert(id < (int) cache_info->number_threads);
1572 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1573 cache_info->nexus_info[id],exception);
1574 return(pixels);
1575 }
1576
1577 /*
1578 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1579 % %
1580 % %
1581 % %
1582 + G e t I m a g e E x t e n t %
1583 % %
1584 % %
1585 % %
1586 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1587 %
1588 % GetImageExtent() returns the extent of the pixels associated corresponding
1589 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1590 %
1591 % The format of the GetImageExtent() method is:
1592 %
1593 % MagickSizeType GetImageExtent(const Image *image)
1594 %
1595 % A description of each parameter follows:
1596 %
1597 % o image: the image.
1598 %
1599 */
GetImageExtent(const Image * image)1600 MagickExport MagickSizeType GetImageExtent(const Image *image)
1601 {
1602 CacheInfo
1603 *magick_restrict cache_info;
1604
1605 const int
1606 id = GetOpenMPThreadId();
1607
1608 assert(image != (Image *) NULL);
1609 assert(image->signature == MagickCoreSignature);
1610 if (image->debug != MagickFalse)
1611 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1612 assert(image->cache != (Cache) NULL);
1613 cache_info=(CacheInfo *) image->cache;
1614 assert(cache_info->signature == MagickCoreSignature);
1615 assert(id < (int) cache_info->number_threads);
1616 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1617 }
1618
1619 /*
1620 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1621 % %
1622 % %
1623 % %
1624 + G e t I m a g e P i x e l C a c h e %
1625 % %
1626 % %
1627 % %
1628 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1629 %
1630 % GetImagePixelCache() ensures that there is only a single reference to the
1631 % pixel cache to be modified, updating the provided cache pointer to point to
1632 % a clone of the original pixel cache if necessary.
1633 %
1634 % The format of the GetImagePixelCache method is:
1635 %
1636 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1637 % ExceptionInfo *exception)
1638 %
1639 % A description of each parameter follows:
1640 %
1641 % o image: the image.
1642 %
1643 % o clone: any value other than MagickFalse clones the cache pixels.
1644 %
1645 % o exception: return any errors or warnings in this structure.
1646 %
1647 */
1648
ValidatePixelCacheMorphology(const Image * magick_restrict image)1649 static inline MagickBooleanType ValidatePixelCacheMorphology(
1650 const Image *magick_restrict image)
1651 {
1652 const CacheInfo
1653 *magick_restrict cache_info;
1654
1655 const PixelChannelMap
1656 *magick_restrict p,
1657 *magick_restrict q;
1658
1659 /*
1660 Does the image match the pixel cache morphology?
1661 */
1662 cache_info=(CacheInfo *) image->cache;
1663 p=image->channel_map;
1664 q=cache_info->channel_map;
1665 if ((image->storage_class != cache_info->storage_class) ||
1666 (image->colorspace != cache_info->colorspace) ||
1667 (image->alpha_trait != cache_info->alpha_trait) ||
1668 (image->channels != cache_info->channels) ||
1669 (image->columns != cache_info->columns) ||
1670 (image->rows != cache_info->rows) ||
1671 (image->number_channels != cache_info->number_channels) ||
1672 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
1673 (image->metacontent_extent != cache_info->metacontent_extent) ||
1674 (cache_info->nexus_info == (NexusInfo **) NULL))
1675 return(MagickFalse);
1676 return(MagickTrue);
1677 }
1678
GetImagePixelCache(Image * image,const MagickBooleanType clone,ExceptionInfo * exception)1679 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1680 ExceptionInfo *exception)
1681 {
1682 CacheInfo
1683 *magick_restrict cache_info;
1684
1685 MagickBooleanType
1686 destroy,
1687 status;
1688
1689 static MagickSizeType
1690 cache_timelimit = MagickResourceInfinity,
1691 cpu_throttle = MagickResourceInfinity,
1692 cycles = 0;
1693
1694 status=MagickTrue;
1695 if (cpu_throttle == MagickResourceInfinity)
1696 cpu_throttle=GetMagickResourceLimit(ThrottleResource);
1697 if ((cpu_throttle != 0) && ((cycles++ % 32) == 0))
1698 MagickDelay(cpu_throttle);
1699 if (cache_epoch == 0)
1700 {
1701 /*
1702 Set the expire time in seconds.
1703 */
1704 cache_timelimit=GetMagickResourceLimit(TimeResource);
1705 cache_epoch=GetMagickTime();
1706 }
1707 if ((cache_timelimit != MagickResourceInfinity) &&
1708 ((MagickSizeType) (GetMagickTime()-cache_epoch) >= cache_timelimit))
1709 {
1710 #if defined(ECANCELED)
1711 errno=ECANCELED;
1712 #endif
1713 cache_info=(CacheInfo *) image->cache;
1714 if (cache_info->file != -1)
1715 (void) ClosePixelCacheOnDisk(cache_info);
1716 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
1717 }
1718 LockSemaphoreInfo(image->semaphore);
1719 assert(image->cache != (Cache) NULL);
1720 cache_info=(CacheInfo *) image->cache;
1721 #if defined(MAGICKCORE_OPENCL_SUPPORT)
1722 CopyOpenCLBuffer(cache_info);
1723 #endif
1724 destroy=MagickFalse;
1725 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1726 {
1727 LockSemaphoreInfo(cache_info->semaphore);
1728 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1729 {
1730 CacheInfo
1731 *clone_info;
1732
1733 Image
1734 clone_image;
1735
1736 /*
1737 Clone pixel cache.
1738 */
1739 clone_image=(*image);
1740 clone_image.semaphore=AcquireSemaphoreInfo();
1741 clone_image.reference_count=1;
1742 clone_image.cache=ClonePixelCache(cache_info);
1743 clone_info=(CacheInfo *) clone_image.cache;
1744 status=OpenPixelCache(&clone_image,IOMode,exception);
1745 if (status == MagickFalse)
1746 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
1747 else
1748 {
1749 if (clone != MagickFalse)
1750 status=ClonePixelCacheRepository(clone_info,cache_info,
1751 exception);
1752 if (status == MagickFalse)
1753 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
1754 else
1755 {
1756 destroy=MagickTrue;
1757 image->cache=clone_info;
1758 }
1759 }
1760 RelinquishSemaphoreInfo(&clone_image.semaphore);
1761 }
1762 UnlockSemaphoreInfo(cache_info->semaphore);
1763 }
1764 if (destroy != MagickFalse)
1765 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
1766 if (status != MagickFalse)
1767 {
1768 /*
1769 Ensure the image matches the pixel cache morphology.
1770 */
1771 if (image->type != UndefinedType)
1772 image->type=UndefinedType;
1773 if (ValidatePixelCacheMorphology(image) == MagickFalse)
1774 {
1775 status=OpenPixelCache(image,IOMode,exception);
1776 cache_info=(CacheInfo *) image->cache;
1777 if (cache_info->file != -1)
1778 (void) ClosePixelCacheOnDisk(cache_info);
1779 }
1780 }
1781 UnlockSemaphoreInfo(image->semaphore);
1782 if (status == MagickFalse)
1783 return((Cache) NULL);
1784 return(image->cache);
1785 }
1786
1787 /*
1788 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1789 % %
1790 % %
1791 % %
1792 + G e t I m a g e P i x e l C a c h e T y p e %
1793 % %
1794 % %
1795 % %
1796 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1797 %
1798 % GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1799 % DiskCache, MemoryCache, MapCache, or PingCache.
1800 %
1801 % The format of the GetImagePixelCacheType() method is:
1802 %
1803 % CacheType GetImagePixelCacheType(const Image *image)
1804 %
1805 % A description of each parameter follows:
1806 %
1807 % o image: the image.
1808 %
1809 */
GetImagePixelCacheType(const Image * image)1810 MagickExport CacheType GetImagePixelCacheType(const Image *image)
1811 {
1812 CacheInfo
1813 *magick_restrict cache_info;
1814
1815 assert(image != (Image *) NULL);
1816 assert(image->signature == MagickCoreSignature);
1817 assert(image->cache != (Cache) NULL);
1818 cache_info=(CacheInfo *) image->cache;
1819 assert(cache_info->signature == MagickCoreSignature);
1820 return(cache_info->type);
1821 }
1822
1823 /*
1824 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1825 % %
1826 % %
1827 % %
1828 % G e t O n e A u t h e n t i c P i x e l %
1829 % %
1830 % %
1831 % %
1832 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1833 %
1834 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1835 % location. The image background color is returned if an error occurs.
1836 %
1837 % The format of the GetOneAuthenticPixel() method is:
1838 %
1839 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
1840 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1841 %
1842 % A description of each parameter follows:
1843 %
1844 % o image: the image.
1845 %
1846 % o x,y: These values define the location of the pixel to return.
1847 %
1848 % o pixel: return a pixel at the specified (x,y) location.
1849 %
1850 % o exception: return any errors or warnings in this structure.
1851 %
1852 */
1853
CopyPixel(const Image * image,const Quantum * source,Quantum * destination)1854 static inline MagickBooleanType CopyPixel(const Image *image,
1855 const Quantum *source,Quantum *destination)
1856 {
1857 ssize_t
1858 i;
1859
1860 if (source == (const Quantum *) NULL)
1861 {
1862 destination[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1863 destination[GreenPixelChannel]=ClampToQuantum(
1864 image->background_color.green);
1865 destination[BluePixelChannel]=ClampToQuantum(
1866 image->background_color.blue);
1867 destination[BlackPixelChannel]=ClampToQuantum(
1868 image->background_color.black);
1869 destination[AlphaPixelChannel]=ClampToQuantum(
1870 image->background_color.alpha);
1871 return(MagickFalse);
1872 }
1873 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1874 {
1875 PixelChannel channel = GetPixelChannelChannel(image,i);
1876 destination[channel]=source[i];
1877 }
1878 return(MagickTrue);
1879 }
1880
GetOneAuthenticPixel(Image * image,const ssize_t x,const ssize_t y,Quantum * pixel,ExceptionInfo * exception)1881 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
1882 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1883 {
1884 CacheInfo
1885 *magick_restrict cache_info;
1886
1887 Quantum
1888 *magick_restrict q;
1889
1890 assert(image != (Image *) NULL);
1891 assert(image->signature == MagickCoreSignature);
1892 assert(image->cache != (Cache) NULL);
1893 cache_info=(CacheInfo *) image->cache;
1894 assert(cache_info->signature == MagickCoreSignature);
1895 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1896 if (cache_info->methods.get_one_authentic_pixel_from_handler != (GetOneAuthenticPixelFromHandler) NULL)
1897 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,pixel,exception));
1898 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
1899 return(CopyPixel(image,q,pixel));
1900 }
1901
1902 /*
1903 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1904 % %
1905 % %
1906 % %
1907 + 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 %
1908 % %
1909 % %
1910 % %
1911 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1912 %
1913 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
1914 % location. The image background color is returned if an error occurs.
1915 %
1916 % The format of the GetOneAuthenticPixelFromCache() method is:
1917 %
1918 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
1919 % const ssize_t x,const ssize_t y,Quantum *pixel,
1920 % ExceptionInfo *exception)
1921 %
1922 % A description of each parameter follows:
1923 %
1924 % o image: the image.
1925 %
1926 % o x,y: These values define the location of the pixel to return.
1927 %
1928 % o pixel: return a pixel at the specified (x,y) location.
1929 %
1930 % o exception: return any errors or warnings in this structure.
1931 %
1932 */
GetOneAuthenticPixelFromCache(Image * image,const ssize_t x,const ssize_t y,Quantum * pixel,ExceptionInfo * exception)1933 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
1934 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1935 {
1936 CacheInfo
1937 *magick_restrict cache_info;
1938
1939 const int
1940 id = GetOpenMPThreadId();
1941
1942 Quantum
1943 *magick_restrict q;
1944
1945 assert(image != (const Image *) NULL);
1946 assert(image->signature == MagickCoreSignature);
1947 assert(image->cache != (Cache) NULL);
1948 cache_info=(CacheInfo *) image->cache;
1949 assert(cache_info->signature == MagickCoreSignature);
1950 assert(id < (int) cache_info->number_threads);
1951 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1952 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
1953 exception);
1954 return(CopyPixel(image,q,pixel));
1955 }
1956
1957 /*
1958 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1959 % %
1960 % %
1961 % %
1962 % G e t O n e V i r t u a l P i x e l %
1963 % %
1964 % %
1965 % %
1966 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1967 %
1968 % GetOneVirtualPixel() returns a single virtual pixel at the specified
1969 % (x,y) location. The image background color is returned if an error occurs.
1970 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1971 %
1972 % The format of the GetOneVirtualPixel() method is:
1973 %
1974 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
1975 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
1976 %
1977 % A description of each parameter follows:
1978 %
1979 % o image: the image.
1980 %
1981 % o x,y: These values define the location of the pixel to return.
1982 %
1983 % o pixel: return a pixel at the specified (x,y) location.
1984 %
1985 % o exception: return any errors or warnings in this structure.
1986 %
1987 */
GetOneVirtualPixel(const Image * image,const ssize_t x,const ssize_t y,Quantum * pixel,ExceptionInfo * exception)1988 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
1989 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1990 {
1991 CacheInfo
1992 *magick_restrict cache_info;
1993
1994 const int
1995 id = GetOpenMPThreadId();
1996
1997 const Quantum
1998 *p;
1999
2000 assert(image != (const Image *) NULL);
2001 assert(image->signature == MagickCoreSignature);
2002 assert(image->cache != (Cache) NULL);
2003 cache_info=(CacheInfo *) image->cache;
2004 assert(cache_info->signature == MagickCoreSignature);
2005 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2006 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2007 (GetOneVirtualPixelFromHandler) NULL)
2008 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2009 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
2010 assert(id < (int) cache_info->number_threads);
2011 p=GetVirtualPixelCacheNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2012 1UL,1UL,cache_info->nexus_info[id],exception);
2013 return(CopyPixel(image,p,pixel));
2014 }
2015
2016 /*
2017 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2018 % %
2019 % %
2020 % %
2021 + 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 %
2022 % %
2023 % %
2024 % %
2025 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2026 %
2027 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2028 % specified (x,y) location. The image background color is returned if an
2029 % error occurs.
2030 %
2031 % The format of the GetOneVirtualPixelFromCache() method is:
2032 %
2033 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
2034 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2035 % Quantum *pixel,ExceptionInfo *exception)
2036 %
2037 % A description of each parameter follows:
2038 %
2039 % o image: the image.
2040 %
2041 % o virtual_pixel_method: the virtual pixel method.
2042 %
2043 % o x,y: These values define the location of the pixel to return.
2044 %
2045 % o pixel: return a pixel at the specified (x,y) location.
2046 %
2047 % o exception: return any errors or warnings in this structure.
2048 %
2049 */
GetOneVirtualPixelFromCache(const Image * image,const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,Quantum * pixel,ExceptionInfo * exception)2050 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
2051 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2052 Quantum *pixel,ExceptionInfo *exception)
2053 {
2054 CacheInfo
2055 *magick_restrict cache_info;
2056
2057 const int
2058 id = GetOpenMPThreadId();
2059
2060 const Quantum
2061 *p;
2062
2063 assert(image != (const Image *) NULL);
2064 assert(image->signature == MagickCoreSignature);
2065 assert(image->cache != (Cache) NULL);
2066 cache_info=(CacheInfo *) image->cache;
2067 assert(cache_info->signature == MagickCoreSignature);
2068 assert(id < (int) cache_info->number_threads);
2069 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2070 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2071 cache_info->nexus_info[id],exception);
2072 return(CopyPixel(image,p,pixel));
2073 }
2074
2075 /*
2076 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2077 % %
2078 % %
2079 % %
2080 % G e t O n e V i r t u a l P i x e l I n f o %
2081 % %
2082 % %
2083 % %
2084 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2085 %
2086 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2087 % location. The image background color is returned if an error occurs. If
2088 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2089 %
2090 % The format of the GetOneVirtualPixelInfo() method is:
2091 %
2092 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2093 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2094 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2095 %
2096 % A description of each parameter follows:
2097 %
2098 % o image: the image.
2099 %
2100 % o virtual_pixel_method: the virtual pixel method.
2101 %
2102 % o x,y: these values define the location of the pixel to return.
2103 %
2104 % o pixel: return a pixel at the specified (x,y) location.
2105 %
2106 % o exception: return any errors or warnings in this structure.
2107 %
2108 */
GetOneVirtualPixelInfo(const Image * image,const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,PixelInfo * pixel,ExceptionInfo * exception)2109 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2110 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2111 PixelInfo *pixel,ExceptionInfo *exception)
2112 {
2113 CacheInfo
2114 *magick_restrict cache_info;
2115
2116 const int
2117 id = GetOpenMPThreadId();
2118
2119 const Quantum
2120 *magick_restrict p;
2121
2122 assert(image != (const Image *) NULL);
2123 assert(image->signature == MagickCoreSignature);
2124 assert(image->cache != (Cache) NULL);
2125 cache_info=(CacheInfo *) image->cache;
2126 assert(cache_info->signature == MagickCoreSignature);
2127 assert(id < (int) cache_info->number_threads);
2128 GetPixelInfo(image,pixel);
2129 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2130 cache_info->nexus_info[id],exception);
2131 if (p == (const Quantum *) NULL)
2132 return(MagickFalse);
2133 GetPixelInfoPixel(image,p,pixel);
2134 return(MagickTrue);
2135 }
2136
2137 /*
2138 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2139 % %
2140 % %
2141 % %
2142 + G e t P i x e l C a c h e C o l o r s p a c e %
2143 % %
2144 % %
2145 % %
2146 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2147 %
2148 % GetPixelCacheColorspace() returns the colorspace of the pixel cache.
2149 %
2150 % The format of the GetPixelCacheColorspace() method is:
2151 %
2152 % Colorspace GetPixelCacheColorspace(const Cache cache)
2153 %
2154 % A description of each parameter follows:
2155 %
2156 % o cache: the pixel cache.
2157 %
2158 */
GetPixelCacheColorspace(const Cache cache)2159 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
2160 {
2161 CacheInfo
2162 *magick_restrict cache_info;
2163
2164 assert(cache != (Cache) NULL);
2165 cache_info=(CacheInfo *) cache;
2166 assert(cache_info->signature == MagickCoreSignature);
2167 if (cache_info->debug != MagickFalse)
2168 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2169 cache_info->filename);
2170 return(cache_info->colorspace);
2171 }
2172
2173 /*
2174 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2175 % %
2176 % %
2177 % %
2178 + G e t P i x e l C a c h e F i l e n a m e %
2179 % %
2180 % %
2181 % %
2182 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2183 %
2184 % GetPixelCacheFilename() returns the filename associated with the pixel
2185 % cache.
2186 %
2187 % The format of the GetPixelCacheFilename() method is:
2188 %
2189 % const char *GetPixelCacheFilename(const Image *image)
2190 %
2191 % A description of each parameter follows:
2192 %
2193 % o image: the image.
2194 %
2195 */
GetPixelCacheFilename(const Image * image)2196 MagickExport const char *GetPixelCacheFilename(const Image *image)
2197 {
2198 CacheInfo
2199 *magick_restrict cache_info;
2200
2201 assert(image != (const Image *) NULL);
2202 assert(image->signature == MagickCoreSignature);
2203 assert(image->cache != (Cache) NULL);
2204 cache_info=(CacheInfo *) image->cache;
2205 assert(cache_info->signature == MagickCoreSignature);
2206 return(cache_info->cache_filename);
2207 }
2208
2209 /*
2210 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2211 % %
2212 % %
2213 % %
2214 + G e t P i x e l C a c h e M e t h o d s %
2215 % %
2216 % %
2217 % %
2218 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2219 %
2220 % GetPixelCacheMethods() initializes the CacheMethods structure.
2221 %
2222 % The format of the GetPixelCacheMethods() method is:
2223 %
2224 % void GetPixelCacheMethods(CacheMethods *cache_methods)
2225 %
2226 % A description of each parameter follows:
2227 %
2228 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2229 %
2230 */
GetPixelCacheMethods(CacheMethods * cache_methods)2231 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
2232 {
2233 assert(cache_methods != (CacheMethods *) NULL);
2234 (void) memset(cache_methods,0,sizeof(*cache_methods));
2235 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2236 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2237 cache_methods->get_virtual_metacontent_from_handler=
2238 GetVirtualMetacontentFromCache;
2239 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2240 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2241 cache_methods->get_authentic_metacontent_from_handler=
2242 GetAuthenticMetacontentFromCache;
2243 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2244 cache_methods->get_one_authentic_pixel_from_handler=
2245 GetOneAuthenticPixelFromCache;
2246 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2247 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2248 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2249 }
2250
2251 /*
2252 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2253 % %
2254 % %
2255 % %
2256 + G e t P i x e l C a c h e N e x u s E x t e n t %
2257 % %
2258 % %
2259 % %
2260 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2261 %
2262 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2263 % corresponding with the last call to SetPixelCacheNexusPixels() or
2264 % GetPixelCacheNexusPixels().
2265 %
2266 % The format of the GetPixelCacheNexusExtent() method is:
2267 %
2268 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2269 % NexusInfo *nexus_info)
2270 %
2271 % A description of each parameter follows:
2272 %
2273 % o nexus_info: the nexus info.
2274 %
2275 */
GetPixelCacheNexusExtent(const Cache cache,NexusInfo * magick_restrict nexus_info)2276 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2277 NexusInfo *magick_restrict nexus_info)
2278 {
2279 CacheInfo
2280 *magick_restrict cache_info;
2281
2282 MagickSizeType
2283 extent;
2284
2285 assert(cache != NULL);
2286 cache_info=(CacheInfo *) cache;
2287 assert(cache_info->signature == MagickCoreSignature);
2288 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2289 if (extent == 0)
2290 return((MagickSizeType) cache_info->columns*cache_info->rows);
2291 return(extent);
2292 }
2293
2294 /*
2295 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2296 % %
2297 % %
2298 % %
2299 + G e t P i x e l C a c h e P i x e l s %
2300 % %
2301 % %
2302 % %
2303 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2304 %
2305 % GetPixelCachePixels() returns the pixels associated with the specified image.
2306 %
2307 % The format of the GetPixelCachePixels() method is:
2308 %
2309 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2310 % ExceptionInfo *exception)
2311 %
2312 % A description of each parameter follows:
2313 %
2314 % o image: the image.
2315 %
2316 % o length: the pixel cache length.
2317 %
2318 % o exception: return any errors or warnings in this structure.
2319 %
2320 */
GetPixelCachePixels(Image * image,MagickSizeType * length,ExceptionInfo * exception)2321 MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2322 ExceptionInfo *exception)
2323 {
2324 CacheInfo
2325 *magick_restrict cache_info;
2326
2327 assert(image != (const Image *) NULL);
2328 assert(image->signature == MagickCoreSignature);
2329 assert(image->cache != (Cache) NULL);
2330 assert(length != (MagickSizeType *) NULL);
2331 assert(exception != (ExceptionInfo *) NULL);
2332 assert(exception->signature == MagickCoreSignature);
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/((ssize_t) extent);
2706 modulo.remainder=offset % ((ssize_t) extent);
2707 if ((modulo.remainder != 0) && ((offset ^ ((ssize_t) extent)) < 0))
2708 {
2709 modulo.quotient-=1;
2710 modulo.remainder+=((ssize_t) extent);
2711 }
2712 return(modulo);
2713 }
2714
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)2715 MagickPrivate const Quantum *GetVirtualPixelCacheNexus(const Image *image,
2716 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2717 const size_t columns,const size_t rows,NexusInfo *nexus_info,
2718 ExceptionInfo *exception)
2719 {
2720 CacheInfo
2721 *magick_restrict cache_info;
2722
2723 MagickOffsetType
2724 offset;
2725
2726 MagickSizeType
2727 length,
2728 number_pixels;
2729
2730 NexusInfo
2731 *magick_restrict virtual_nexus;
2732
2733 Quantum
2734 *magick_restrict pixels,
2735 virtual_pixel[MaxPixelChannels];
2736
2737 const Quantum
2738 *magick_restrict p;
2739
2740 const void
2741 *magick_restrict r;
2742
2743 Quantum
2744 *magick_restrict q;
2745
2746 ssize_t
2747 i,
2748 u;
2749
2750 unsigned char
2751 *magick_restrict s;
2752
2753 ssize_t
2754 v;
2755
2756 void
2757 *magick_restrict virtual_metacontent;
2758
2759 /*
2760 Acquire pixels.
2761 */
2762 assert(image != (const Image *) NULL);
2763 assert(image->signature == MagickCoreSignature);
2764 assert(image->cache != (Cache) NULL);
2765 cache_info=(CacheInfo *) image->cache;
2766 assert(cache_info->signature == MagickCoreSignature);
2767 if (cache_info->type == UndefinedCache)
2768 return((const Quantum *) NULL);
2769 #if defined(MAGICKCORE_OPENCL_SUPPORT)
2770 CopyOpenCLBuffer(cache_info);
2771 #endif
2772 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,x,y,columns,rows,
2773 ((image->channels & WriteMaskChannel) != 0) ||
2774 ((image->channels & CompositeMaskChannel) != 0) ? MagickTrue : MagickFalse,
2775 nexus_info,exception);
2776 if (pixels == (Quantum *) NULL)
2777 return((const Quantum *) NULL);
2778 q=pixels;
2779 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
2780 nexus_info->region.x;
2781 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
2782 nexus_info->region.width-1L;
2783 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
2784 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
2785 if ((x >= 0) && ((ssize_t) (x+columns-1) < (ssize_t) cache_info->columns) &&
2786 (y >= 0) && ((ssize_t) (y+rows-1) < (ssize_t) cache_info->rows))
2787 {
2788 MagickBooleanType
2789 status;
2790
2791 /*
2792 Pixel request is inside cache extents.
2793 */
2794 if (nexus_info->authentic_pixel_cache != MagickFalse)
2795 return(q);
2796 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
2797 if (status == MagickFalse)
2798 return((const Quantum *) NULL);
2799 if (cache_info->metacontent_extent != 0)
2800 {
2801 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
2802 if (status == MagickFalse)
2803 return((const Quantum *) NULL);
2804 }
2805 return(q);
2806 }
2807 /*
2808 Pixel request is outside cache extents.
2809 */
2810 virtual_nexus=nexus_info->virtual_nexus;
2811 s=(unsigned char *) nexus_info->metacontent;
2812 (void) memset(virtual_pixel,0,cache_info->number_channels*
2813 sizeof(*virtual_pixel));
2814 virtual_metacontent=(void *) NULL;
2815 switch (virtual_pixel_method)
2816 {
2817 case BackgroundVirtualPixelMethod:
2818 case BlackVirtualPixelMethod:
2819 case GrayVirtualPixelMethod:
2820 case TransparentVirtualPixelMethod:
2821 case MaskVirtualPixelMethod:
2822 case WhiteVirtualPixelMethod:
2823 case EdgeVirtualPixelMethod:
2824 case CheckerTileVirtualPixelMethod:
2825 case HorizontalTileVirtualPixelMethod:
2826 case VerticalTileVirtualPixelMethod:
2827 {
2828 if (cache_info->metacontent_extent != 0)
2829 {
2830 /*
2831 Acquire a metacontent buffer.
2832 */
2833 virtual_metacontent=(void *) AcquireQuantumMemory(1,
2834 cache_info->metacontent_extent);
2835 if (virtual_metacontent == (void *) NULL)
2836 {
2837 (void) ThrowMagickException(exception,GetMagickModule(),
2838 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
2839 return((const Quantum *) NULL);
2840 }
2841 (void) memset(virtual_metacontent,0,cache_info->metacontent_extent);
2842 }
2843 switch (virtual_pixel_method)
2844 {
2845 case BlackVirtualPixelMethod:
2846 {
2847 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2848 SetPixelChannel(image,(PixelChannel) i,(Quantum) 0,virtual_pixel);
2849 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2850 break;
2851 }
2852 case GrayVirtualPixelMethod:
2853 {
2854 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2855 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
2856 virtual_pixel);
2857 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2858 break;
2859 }
2860 case TransparentVirtualPixelMethod:
2861 {
2862 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2863 SetPixelChannel(image,(PixelChannel) i,(Quantum) 0,virtual_pixel);
2864 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
2865 break;
2866 }
2867 case MaskVirtualPixelMethod:
2868 case WhiteVirtualPixelMethod:
2869 {
2870 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2871 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
2872 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2873 break;
2874 }
2875 default:
2876 {
2877 SetPixelRed(image,ClampToQuantum(image->background_color.red),
2878 virtual_pixel);
2879 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
2880 virtual_pixel);
2881 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
2882 virtual_pixel);
2883 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
2884 virtual_pixel);
2885 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
2886 virtual_pixel);
2887 break;
2888 }
2889 }
2890 break;
2891 }
2892 default:
2893 break;
2894 }
2895 for (v=0; v < (ssize_t) rows; v++)
2896 {
2897 ssize_t
2898 y_offset;
2899
2900 y_offset=y+v;
2901 if ((virtual_pixel_method == EdgeVirtualPixelMethod) ||
2902 (virtual_pixel_method == UndefinedVirtualPixelMethod))
2903 y_offset=EdgeY(y_offset,cache_info->rows);
2904 for (u=0; u < (ssize_t) columns; u+=length)
2905 {
2906 ssize_t
2907 x_offset;
2908
2909 x_offset=x+u;
2910 length=(MagickSizeType) MagickMin(cache_info->columns-x_offset,columns-u);
2911 if (((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns)) ||
2912 ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows)) ||
2913 (length == 0))
2914 {
2915 MagickModulo
2916 x_modulo,
2917 y_modulo;
2918
2919 /*
2920 Transfer a single pixel.
2921 */
2922 length=(MagickSizeType) 1;
2923 switch (virtual_pixel_method)
2924 {
2925 case EdgeVirtualPixelMethod:
2926 default:
2927 {
2928 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
2929 EdgeX(x_offset,cache_info->columns),
2930 EdgeY(y_offset,cache_info->rows),1UL,1UL,virtual_nexus,
2931 exception);
2932 r=GetVirtualMetacontentFromNexus(cache_info,
2933 nexus_info->virtual_nexus);
2934 break;
2935 }
2936 case RandomVirtualPixelMethod:
2937 {
2938 if (cache_info->random_info == (RandomInfo *) NULL)
2939 cache_info->random_info=AcquireRandomInfo();
2940 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
2941 RandomX(cache_info->random_info,cache_info->columns),
2942 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
2943 virtual_nexus,exception);
2944 r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
2945 break;
2946 }
2947 case DitherVirtualPixelMethod:
2948 {
2949 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
2950 DitherX(x_offset,cache_info->columns),
2951 DitherY(y_offset,cache_info->rows),1UL,1UL,virtual_nexus,
2952 exception);
2953 r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
2954 break;
2955 }
2956 case TileVirtualPixelMethod:
2957 {
2958 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2959 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2960 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
2961 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus,
2962 exception);
2963 r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
2964 break;
2965 }
2966 case MirrorVirtualPixelMethod:
2967 {
2968 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2969 if ((x_modulo.quotient & 0x01) == 1L)
2970 x_modulo.remainder=(ssize_t) cache_info->columns-
2971 x_modulo.remainder-1L;
2972 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2973 if ((y_modulo.quotient & 0x01) == 1L)
2974 y_modulo.remainder=(ssize_t) cache_info->rows-
2975 y_modulo.remainder-1L;
2976 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
2977 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus,
2978 exception);
2979 r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
2980 break;
2981 }
2982 case HorizontalTileEdgeVirtualPixelMethod:
2983 {
2984 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2985 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
2986 x_modulo.remainder,EdgeY(y_offset,cache_info->rows),1UL,1UL,
2987 virtual_nexus,exception);
2988 r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
2989 break;
2990 }
2991 case VerticalTileEdgeVirtualPixelMethod:
2992 {
2993 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2994 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
2995 EdgeX(x_offset,cache_info->columns),y_modulo.remainder,1UL,1UL,
2996 virtual_nexus,exception);
2997 r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
2998 break;
2999 }
3000 case BackgroundVirtualPixelMethod:
3001 case BlackVirtualPixelMethod:
3002 case GrayVirtualPixelMethod:
3003 case TransparentVirtualPixelMethod:
3004 case MaskVirtualPixelMethod:
3005 case WhiteVirtualPixelMethod:
3006 {
3007 p=virtual_pixel;
3008 r=virtual_metacontent;
3009 break;
3010 }
3011 case CheckerTileVirtualPixelMethod:
3012 {
3013 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
3014 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
3015 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3016 {
3017 p=virtual_pixel;
3018 r=virtual_metacontent;
3019 break;
3020 }
3021 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3022 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus,
3023 exception);
3024 r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
3025 break;
3026 }
3027 case HorizontalTileVirtualPixelMethod:
3028 {
3029 if ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows))
3030 {
3031 p=virtual_pixel;
3032 r=virtual_metacontent;
3033 break;
3034 }
3035 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
3036 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
3037 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3038 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus,
3039 exception);
3040 r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
3041 break;
3042 }
3043 case VerticalTileVirtualPixelMethod:
3044 {
3045 if ((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns))
3046 {
3047 p=virtual_pixel;
3048 r=virtual_metacontent;
3049 break;
3050 }
3051 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
3052 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
3053 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3054 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus,
3055 exception);
3056 r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
3057 break;
3058 }
3059 }
3060 if (p == (const Quantum *) NULL)
3061 break;
3062 (void) memcpy(q,p,(size_t) (cache_info->number_channels*length*
3063 sizeof(*p)));
3064 q+=cache_info->number_channels;
3065 if ((s != (void *) NULL) && (r != (const void *) NULL))
3066 {
3067 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3068 s+=cache_info->metacontent_extent;
3069 }
3070 continue;
3071 }
3072 /*
3073 Transfer a run of pixels.
3074 */
3075 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,x_offset,y_offset,
3076 (size_t) length,1UL,virtual_nexus,exception);
3077 if (p == (const Quantum *) NULL)
3078 break;
3079 r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
3080 (void) memcpy(q,p,(size_t) (cache_info->number_channels*length*
3081 sizeof(*p)));
3082 q+=cache_info->number_channels*length;
3083 if ((r != (void *) NULL) && (s != (const void *) NULL))
3084 {
3085 (void) memcpy(s,r,(size_t) length);
3086 s+=length*cache_info->metacontent_extent;
3087 }
3088 }
3089 if (u < (ssize_t) columns)
3090 break;
3091 }
3092 /*
3093 Free resources.
3094 */
3095 if (virtual_metacontent != (void *) NULL)
3096 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
3097 if (v < (ssize_t) rows)
3098 return((const Quantum *) NULL);
3099 return(pixels);
3100 }
3101
3102 /*
3103 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3104 % %
3105 % %
3106 % %
3107 + G e t V i r t u a l P i x e l C a c h e %
3108 % %
3109 % %
3110 % %
3111 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3112 %
3113 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3114 % cache as defined by the geometry parameters. A pointer to the pixels
3115 % is returned if the pixels are transferred, otherwise a NULL is returned.
3116 %
3117 % The format of the GetVirtualPixelCache() method is:
3118 %
3119 % const Quantum *GetVirtualPixelCache(const Image *image,
3120 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3121 % const ssize_t y,const size_t columns,const size_t rows,
3122 % ExceptionInfo *exception)
3123 %
3124 % A description of each parameter follows:
3125 %
3126 % o image: the image.
3127 %
3128 % o virtual_pixel_method: the virtual pixel method.
3129 %
3130 % o x,y,columns,rows: These values define the perimeter of a region of
3131 % pixels.
3132 %
3133 % o exception: return any errors or warnings in this structure.
3134 %
3135 */
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)3136 static const Quantum *GetVirtualPixelCache(const Image *image,
3137 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3138 const size_t columns,const size_t rows,ExceptionInfo *exception)
3139 {
3140 CacheInfo
3141 *magick_restrict cache_info;
3142
3143 const int
3144 id = GetOpenMPThreadId();
3145
3146 const Quantum
3147 *magick_restrict p;
3148
3149 assert(image != (const Image *) NULL);
3150 assert(image->signature == MagickCoreSignature);
3151 assert(image->cache != (Cache) NULL);
3152 cache_info=(CacheInfo *) image->cache;
3153 assert(cache_info->signature == MagickCoreSignature);
3154 assert(id < (int) cache_info->number_threads);
3155 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,x,y,columns,rows,
3156 cache_info->nexus_info[id],exception);
3157 return(p);
3158 }
3159
3160 /*
3161 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3162 % %
3163 % %
3164 % %
3165 % G e t V i r t u a l P i x e l Q u e u e %
3166 % %
3167 % %
3168 % %
3169 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3170 %
3171 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3172 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
3173 %
3174 % The format of the GetVirtualPixelQueue() method is:
3175 %
3176 % const Quantum *GetVirtualPixelQueue(const Image image)
3177 %
3178 % A description of each parameter follows:
3179 %
3180 % o image: the image.
3181 %
3182 */
GetVirtualPixelQueue(const Image * image)3183 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
3184 {
3185 CacheInfo
3186 *magick_restrict cache_info;
3187
3188 const int
3189 id = GetOpenMPThreadId();
3190
3191 assert(image != (const Image *) NULL);
3192 assert(image->signature == MagickCoreSignature);
3193 assert(image->cache != (Cache) NULL);
3194 cache_info=(CacheInfo *) image->cache;
3195 assert(cache_info->signature == MagickCoreSignature);
3196 if (cache_info->methods.get_virtual_pixels_handler !=
3197 (GetVirtualPixelsHandler) NULL)
3198 return(cache_info->methods.get_virtual_pixels_handler(image));
3199 assert(id < (int) cache_info->number_threads);
3200 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3201 }
3202
3203 /*
3204 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3205 % %
3206 % %
3207 % %
3208 % G e t V i r t u a l P i x e l s %
3209 % %
3210 % %
3211 % %
3212 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3213 %
3214 % GetVirtualPixels() returns an immutable pixel region. If the
3215 % region is successfully accessed, a pointer to it is returned, otherwise
3216 % NULL is returned. The returned pointer may point to a temporary working
3217 % copy of the pixels or it may point to the original pixels in memory.
3218 % Performance is maximized if the selected region is part of one row, or one
3219 % or more full rows, since there is opportunity to access the pixels in-place
3220 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3221 % returned pointer must *never* be deallocated by the user.
3222 %
3223 % Pixels accessed via the returned pointer represent a simple array of type
3224 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3225 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3226 % access the meta-content (of type void) corresponding to the
3227 % region.
3228 %
3229 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3230 %
3231 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3232 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3233 % GetCacheViewAuthenticPixels() instead.
3234 %
3235 % The format of the GetVirtualPixels() method is:
3236 %
3237 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3238 % const ssize_t y,const size_t columns,const size_t rows,
3239 % ExceptionInfo *exception)
3240 %
3241 % A description of each parameter follows:
3242 %
3243 % o image: the image.
3244 %
3245 % o x,y,columns,rows: These values define the perimeter of a region of
3246 % pixels.
3247 %
3248 % o exception: return any errors or warnings in this structure.
3249 %
3250 */
GetVirtualPixels(const Image * image,const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,ExceptionInfo * exception)3251 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3252 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3253 ExceptionInfo *exception)
3254 {
3255 CacheInfo
3256 *magick_restrict cache_info;
3257
3258 const int
3259 id = GetOpenMPThreadId();
3260
3261 const Quantum
3262 *magick_restrict p;
3263
3264 assert(image != (const Image *) NULL);
3265 assert(image->signature == MagickCoreSignature);
3266 assert(image->cache != (Cache) NULL);
3267 cache_info=(CacheInfo *) image->cache;
3268 assert(cache_info->signature == MagickCoreSignature);
3269 if (cache_info->methods.get_virtual_pixel_handler !=
3270 (GetVirtualPixelHandler) NULL)
3271 return(cache_info->methods.get_virtual_pixel_handler(image,
3272 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3273 assert(id < (int) cache_info->number_threads);
3274 p=GetVirtualPixelCacheNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3275 columns,rows,cache_info->nexus_info[id],exception);
3276 return(p);
3277 }
3278
3279 /*
3280 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3281 % %
3282 % %
3283 % %
3284 + 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 %
3285 % %
3286 % %
3287 % %
3288 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3289 %
3290 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3291 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3292 %
3293 % The format of the GetVirtualPixelsCache() method is:
3294 %
3295 % Quantum *GetVirtualPixelsCache(const Image *image)
3296 %
3297 % A description of each parameter follows:
3298 %
3299 % o image: the image.
3300 %
3301 */
GetVirtualPixelsCache(const Image * image)3302 static const Quantum *GetVirtualPixelsCache(const Image *image)
3303 {
3304 CacheInfo
3305 *magick_restrict cache_info;
3306
3307 const int
3308 id = GetOpenMPThreadId();
3309
3310 assert(image != (const Image *) NULL);
3311 assert(image->signature == MagickCoreSignature);
3312 assert(image->cache != (Cache) NULL);
3313 cache_info=(CacheInfo *) image->cache;
3314 assert(cache_info->signature == MagickCoreSignature);
3315 assert(id < (int) cache_info->number_threads);
3316 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3317 }
3318
3319 /*
3320 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3321 % %
3322 % %
3323 % %
3324 + G e t V i r t u a l P i x e l s N e x u s %
3325 % %
3326 % %
3327 % %
3328 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3329 %
3330 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3331 % cache nexus.
3332 %
3333 % The format of the GetVirtualPixelsNexus() method is:
3334 %
3335 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3336 % NexusInfo *nexus_info)
3337 %
3338 % A description of each parameter follows:
3339 %
3340 % o cache: the pixel cache.
3341 %
3342 % o nexus_info: the cache nexus to return the colormap pixels.
3343 %
3344 */
GetVirtualPixelsNexus(const Cache cache,NexusInfo * magick_restrict nexus_info)3345 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3346 NexusInfo *magick_restrict nexus_info)
3347 {
3348 CacheInfo
3349 *magick_restrict cache_info;
3350
3351 assert(cache != (Cache) NULL);
3352 cache_info=(CacheInfo *) cache;
3353 assert(cache_info->signature == MagickCoreSignature);
3354 if (cache_info->storage_class == UndefinedClass)
3355 return((Quantum *) NULL);
3356 return((const Quantum *) nexus_info->pixels);
3357 }
3358
3359 /*
3360 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3361 % %
3362 % %
3363 % %
3364 + M a s k P i x e l C a c h e N e x u s %
3365 % %
3366 % %
3367 % %
3368 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3369 %
3370 % MaskPixelCacheNexus() masks the cache nexus as defined by the composite mask.
3371 % The method returns MagickTrue if the pixel region is masked, otherwise
3372 % MagickFalse.
3373 %
3374 % The format of the MaskPixelCacheNexus() method is:
3375 %
3376 % MagickBooleanType MaskPixelCacheNexus(Image *image,
3377 % NexusInfo *nexus_info,ExceptionInfo *exception)
3378 %
3379 % A description of each parameter follows:
3380 %
3381 % o image: the image.
3382 %
3383 % o nexus_info: the cache nexus to clip.
3384 %
3385 % o exception: return any errors or warnings in this structure.
3386 %
3387 */
3388
ApplyPixelCompositeMask(const Quantum p,const MagickRealType alpha,const Quantum q,const MagickRealType beta)3389 static inline Quantum ApplyPixelCompositeMask(const Quantum p,
3390 const MagickRealType alpha,const Quantum q,const MagickRealType beta)
3391 {
3392 double
3393 mask_alpha;
3394
3395 Quantum
3396 pixel;
3397
3398 if (fabs((double) (alpha-OpaqueAlpha)) < MagickEpsilon)
3399 return(p);
3400 mask_alpha=1.0-QuantumScale*QuantumScale*alpha*beta;
3401 mask_alpha=PerceptibleReciprocal(mask_alpha);
3402 pixel=ClampToQuantum(mask_alpha*MagickOver_((double) p,alpha,(double) q,
3403 beta));
3404 return(pixel);
3405 }
3406
MaskPixelCacheNexus(Image * image,NexusInfo * nexus_info,ExceptionInfo * exception)3407 static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3408 ExceptionInfo *exception)
3409 {
3410 CacheInfo
3411 *magick_restrict cache_info;
3412
3413 Quantum
3414 *magick_restrict p,
3415 *magick_restrict q;
3416
3417 ssize_t
3418 y;
3419
3420 /*
3421 Apply composite mask.
3422 */
3423 if (image->debug != MagickFalse)
3424 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3425 if ((image->channels & CompositeMaskChannel) == 0)
3426 return(MagickTrue);
3427 if ((nexus_info->region.width == 0) || (nexus_info->region.height == 0))
3428 return(MagickTrue);
3429 cache_info=(CacheInfo *) image->cache;
3430 if (cache_info == (Cache) NULL)
3431 return(MagickFalse);
3432 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,nexus_info->region.y,
3433 nexus_info->region.width,nexus_info->region.height,
3434 nexus_info->virtual_nexus,exception);
3435 q=nexus_info->pixels;
3436 if ((p == (Quantum *) NULL) || (q == (Quantum *) NULL))
3437 return(MagickFalse);
3438 for (y=0; y < (ssize_t) nexus_info->region.height; y++)
3439 {
3440 ssize_t
3441 x;
3442
3443 for (x=0; x < (ssize_t) nexus_info->region.width; x++)
3444 {
3445 double
3446 mask_alpha;
3447
3448 ssize_t
3449 i;
3450
3451 mask_alpha=(double) GetPixelCompositeMask(image,p);
3452 for (i=0; i < (ssize_t) image->number_channels; i++)
3453 {
3454 PixelChannel channel = GetPixelChannelChannel(image,i);
3455 PixelTrait traits = GetPixelChannelTraits(image,channel);
3456 if ((traits & UpdatePixelTrait) == 0)
3457 continue;
3458 q[i]=ApplyPixelCompositeMask(p[i],mask_alpha,q[i],(MagickRealType)
3459 GetPixelAlpha(image,q));
3460 }
3461 p+=GetPixelChannels(image);
3462 q+=GetPixelChannels(image);
3463 }
3464 }
3465 return(MagickTrue);
3466 }
3467
3468 /*
3469 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3470 % %
3471 % %
3472 % %
3473 + O p e n P i x e l C a c h e %
3474 % %
3475 % %
3476 % %
3477 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3478 %
3479 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3480 % dimensions, allocating space for the image pixels and optionally the
3481 % metacontent, and memory mapping the cache if it is disk based. The cache
3482 % nexus array is initialized as well.
3483 %
3484 % The format of the OpenPixelCache() method is:
3485 %
3486 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3487 % ExceptionInfo *exception)
3488 %
3489 % A description of each parameter follows:
3490 %
3491 % o image: the image.
3492 %
3493 % o mode: ReadMode, WriteMode, or IOMode.
3494 %
3495 % o exception: return any errors or warnings in this structure.
3496 %
3497 */
3498
OpenPixelCacheOnDisk(CacheInfo * cache_info,const MapMode mode)3499 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
3500 const MapMode mode)
3501 {
3502 int
3503 file;
3504
3505 /*
3506 Open pixel cache on disk.
3507 */
3508 if ((cache_info->file != -1) && (cache_info->disk_mode == mode))
3509 return(MagickTrue); /* cache already open and in the proper mode */
3510 if (*cache_info->cache_filename == '\0')
3511 file=AcquireUniqueFileResource(cache_info->cache_filename);
3512 else
3513 switch (mode)
3514 {
3515 case ReadMode:
3516 {
3517 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
3518 break;
3519 }
3520 case WriteMode:
3521 {
3522 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
3523 O_BINARY | O_EXCL,S_MODE);
3524 if (file == -1)
3525 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
3526 break;
3527 }
3528 case IOMode:
3529 default:
3530 {
3531 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
3532 O_EXCL,S_MODE);
3533 if (file == -1)
3534 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
3535 break;
3536 }
3537 }
3538 if (file == -1)
3539 return(MagickFalse);
3540 (void) AcquireMagickResource(FileResource,1);
3541 if (cache_info->file != -1)
3542 (void) ClosePixelCacheOnDisk(cache_info);
3543 cache_info->file=file;
3544 cache_info->disk_mode=mode;
3545 return(MagickTrue);
3546 }
3547
WritePixelCacheRegion(const CacheInfo * magick_restrict cache_info,const MagickOffsetType offset,const MagickSizeType length,const unsigned char * magick_restrict buffer)3548 static inline MagickOffsetType WritePixelCacheRegion(
3549 const CacheInfo *magick_restrict cache_info,const MagickOffsetType offset,
3550 const MagickSizeType length,const unsigned char *magick_restrict buffer)
3551 {
3552 MagickOffsetType
3553 i;
3554
3555 ssize_t
3556 count;
3557
3558 #if !defined(MAGICKCORE_HAVE_PWRITE)
3559 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
3560 return((MagickOffsetType) -1);
3561 #endif
3562 count=0;
3563 for (i=0; i < (MagickOffsetType) length; i+=count)
3564 {
3565 #if !defined(MAGICKCORE_HAVE_PWRITE)
3566 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,(size_t)
3567 MAGICK_SSIZE_MAX));
3568 #else
3569 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,(size_t)
3570 MAGICK_SSIZE_MAX),offset+i);
3571 #endif
3572 if (count <= 0)
3573 {
3574 count=0;
3575 if (errno != EINTR)
3576 break;
3577 }
3578 }
3579 return(i);
3580 }
3581
SetPixelCacheExtent(Image * image,MagickSizeType length)3582 static MagickBooleanType SetPixelCacheExtent(Image *image,MagickSizeType length)
3583 {
3584 CacheInfo
3585 *magick_restrict cache_info;
3586
3587 MagickOffsetType
3588 count,
3589 extent,
3590 offset;
3591
3592 cache_info=(CacheInfo *) image->cache;
3593 if (image->debug != MagickFalse)
3594 {
3595 char
3596 format[MagickPathExtent],
3597 message[MagickPathExtent];
3598
3599 (void) FormatMagickSize(length,MagickFalse,"B",MagickPathExtent,format);
3600 (void) FormatLocaleString(message,MagickPathExtent,
3601 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3602 cache_info->cache_filename,cache_info->file,format);
3603 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3604 }
3605 if (length != (MagickSizeType) ((MagickOffsetType) length))
3606 return(MagickFalse);
3607 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3608 if (offset < 0)
3609 return(MagickFalse);
3610 if ((MagickSizeType) offset >= length)
3611 count=(MagickOffsetType) 1;
3612 else
3613 {
3614 extent=(MagickOffsetType) length-1;
3615 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *)
3616 "");
3617 if (count != 1)
3618 return(MagickFalse);
3619 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3620 if (cache_info->synchronize != MagickFalse)
3621 if (posix_fallocate(cache_info->file,offset+1,extent-offset) != 0)
3622 return(MagickFalse);
3623 #endif
3624 }
3625 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_SET);
3626 if (offset < 0)
3627 return(MagickFalse);
3628 return(MagickTrue);
3629 }
3630
OpenPixelCache(Image * image,const MapMode mode,ExceptionInfo * exception)3631 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3632 ExceptionInfo *exception)
3633 {
3634 CacheInfo
3635 *magick_restrict cache_info,
3636 source_info;
3637
3638 char
3639 format[MagickPathExtent],
3640 message[MagickPathExtent];
3641
3642 const char
3643 *hosts,
3644 *type;
3645
3646 MagickBooleanType
3647 status;
3648
3649 MagickSizeType
3650 length,
3651 number_pixels;
3652
3653 size_t
3654 columns,
3655 packet_size;
3656
3657 assert(image != (const Image *) NULL);
3658 assert(image->signature == MagickCoreSignature);
3659 assert(image->cache != (Cache) NULL);
3660 if (image->debug != MagickFalse)
3661 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3662 if (cache_anonymous_memory < 0)
3663 {
3664 char
3665 *value;
3666
3667 /*
3668 Does the security policy require anonymous mapping for pixel cache?
3669 */
3670 cache_anonymous_memory=0;
3671 value=GetPolicyValue("pixel-cache-memory");
3672 if (value == (char *) NULL)
3673 value=GetPolicyValue("cache:memory-map");
3674 if (LocaleCompare(value,"anonymous") == 0)
3675 {
3676 #if defined(MAGICKCORE_HAVE_MMAP) && defined(MAP_ANONYMOUS)
3677 cache_anonymous_memory=1;
3678 #else
3679 (void) ThrowMagickException(exception,GetMagickModule(),
3680 MissingDelegateError,"DelegateLibrarySupportNotBuiltIn",
3681 "'%s' (policy requires anonymous memory mapping)",image->filename);
3682 #endif
3683 }
3684 value=DestroyString(value);
3685 }
3686 if ((image->columns == 0) || (image->rows == 0))
3687 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3688 cache_info=(CacheInfo *) image->cache;
3689 assert(cache_info->signature == MagickCoreSignature);
3690 if (((MagickSizeType) image->columns > cache_info->width_limit) ||
3691 ((MagickSizeType) image->rows > cache_info->height_limit))
3692 ThrowBinaryException(ImageError,"WidthOrHeightExceedsLimit",
3693 image->filename);
3694 if (GetMagickResourceLimit(ListLengthResource) != MagickResourceInfinity)
3695 {
3696 length=GetImageListLength(image);
3697 if (AcquireMagickResource(ListLengthResource,length) == MagickFalse)
3698 ThrowBinaryException(ResourceLimitError,"ListLengthExceedsLimit",
3699 image->filename);
3700 }
3701 source_info=(*cache_info);
3702 source_info.file=(-1);
3703 (void) FormatLocaleString(cache_info->filename,MagickPathExtent,"%s[%.20g]",
3704 image->filename,(double) image->scene);
3705 cache_info->storage_class=image->storage_class;
3706 cache_info->colorspace=image->colorspace;
3707 cache_info->alpha_trait=image->alpha_trait;
3708 cache_info->channels=image->channels;
3709 cache_info->rows=image->rows;
3710 cache_info->columns=image->columns;
3711 InitializePixelChannelMap(image);
3712 cache_info->number_channels=GetPixelChannels(image);
3713 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3714 sizeof(*image->channel_map));
3715 cache_info->metacontent_extent=image->metacontent_extent;
3716 cache_info->mode=mode;
3717 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3718 packet_size=cache_info->number_channels*sizeof(Quantum);
3719 if (image->metacontent_extent != 0)
3720 packet_size+=cache_info->metacontent_extent;
3721 length=number_pixels*packet_size;
3722 columns=(size_t) (length/cache_info->rows/packet_size);
3723 if ((cache_info->columns != columns) || ((ssize_t) cache_info->columns < 0) ||
3724 ((ssize_t) cache_info->rows < 0))
3725 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3726 image->filename);
3727 cache_info->length=length;
3728 if (image->ping != MagickFalse)
3729 {
3730 cache_info->type=PingCache;
3731 return(MagickTrue);
3732 }
3733 status=AcquireMagickResource(AreaResource,(MagickSizeType)
3734 cache_info->columns*cache_info->rows);
3735 if (cache_info->mode == PersistMode)
3736 status=MagickFalse;
3737 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3738 cache_info->metacontent_extent);
3739 if ((status != MagickFalse) &&
3740 (length == (MagickSizeType) ((size_t) length)) &&
3741 ((cache_info->type == UndefinedCache) ||
3742 (cache_info->type == MemoryCache)))
3743 {
3744 status=AcquireMagickResource(MemoryResource,cache_info->length);
3745 if (status != MagickFalse)
3746 {
3747 status=MagickTrue;
3748 if (cache_anonymous_memory <= 0)
3749 {
3750 cache_info->mapped=MagickFalse;
3751 cache_info->pixels=(Quantum *) MagickAssumeAligned(
3752 AcquireAlignedMemory(1,(size_t) cache_info->length));
3753 }
3754 else
3755 {
3756 cache_info->mapped=MagickTrue;
3757 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3758 cache_info->length);
3759 }
3760 if (cache_info->pixels == (Quantum *) NULL)
3761 {
3762 cache_info->mapped=source_info.mapped;
3763 cache_info->pixels=source_info.pixels;
3764 }
3765 else
3766 {
3767 /*
3768 Create memory pixel cache.
3769 */
3770 cache_info->type=MemoryCache;
3771 cache_info->metacontent=(void *) NULL;
3772 if (cache_info->metacontent_extent != 0)
3773 cache_info->metacontent=(void *) (cache_info->pixels+
3774 cache_info->number_channels*number_pixels);
3775 if ((source_info.storage_class != UndefinedClass) &&
3776 (mode != ReadMode))
3777 {
3778 status=ClonePixelCacheRepository(cache_info,&source_info,
3779 exception);
3780 RelinquishPixelCachePixels(&source_info);
3781 }
3782 if (image->debug != MagickFalse)
3783 {
3784 (void) FormatMagickSize(cache_info->length,MagickTrue,"B",
3785 MagickPathExtent,format);
3786 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3787 cache_info->type);
3788 (void) FormatLocaleString(message,MagickPathExtent,
3789 "open %s (%s %s, %.20gx%.20gx%.20g %s)",
3790 cache_info->filename,cache_info->mapped != MagickFalse ?
3791 "Anonymous" : "Heap",type,(double) cache_info->columns,
3792 (double) cache_info->rows,(double)
3793 cache_info->number_channels,format);
3794 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3795 message);
3796 }
3797 cache_info->storage_class=image->storage_class;
3798 if (status == 0)
3799 {
3800 cache_info->type=UndefinedCache;
3801 return(MagickFalse);
3802 }
3803 return(MagickTrue);
3804 }
3805 }
3806 }
3807 status=AcquireMagickResource(DiskResource,cache_info->length);
3808 hosts=(const char *) GetImageRegistry(StringRegistryType,"cache:hosts",
3809 exception);
3810 if ((status == MagickFalse) && (hosts != (const char *) NULL))
3811 {
3812 DistributeCacheInfo
3813 *server_info;
3814
3815 /*
3816 Distribute the pixel cache to a remote server.
3817 */
3818 server_info=AcquireDistributeCacheInfo(exception);
3819 if (server_info != (DistributeCacheInfo *) NULL)
3820 {
3821 status=OpenDistributePixelCache(server_info,image);
3822 if (status == MagickFalse)
3823 {
3824 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3825 GetDistributeCacheHostname(server_info));
3826 server_info=DestroyDistributeCacheInfo(server_info);
3827 }
3828 else
3829 {
3830 /*
3831 Create a distributed pixel cache.
3832 */
3833 status=MagickTrue;
3834 cache_info->type=DistributedCache;
3835 cache_info->server_info=server_info;
3836 (void) FormatLocaleString(cache_info->cache_filename,
3837 MagickPathExtent,"%s:%d",GetDistributeCacheHostname(
3838 (DistributeCacheInfo *) cache_info->server_info),
3839 GetDistributeCachePort((DistributeCacheInfo *)
3840 cache_info->server_info));
3841 if ((source_info.storage_class != UndefinedClass) &&
3842 (mode != ReadMode))
3843 {
3844 status=ClonePixelCacheRepository(cache_info,&source_info,
3845 exception);
3846 RelinquishPixelCachePixels(&source_info);
3847 }
3848 if (image->debug != MagickFalse)
3849 {
3850 (void) FormatMagickSize(cache_info->length,MagickFalse,"B",
3851 MagickPathExtent,format);
3852 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3853 cache_info->type);
3854 (void) FormatLocaleString(message,MagickPathExtent,
3855 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3856 cache_info->filename,cache_info->cache_filename,
3857 GetDistributeCacheFile((DistributeCacheInfo *)
3858 cache_info->server_info),type,(double) cache_info->columns,
3859 (double) cache_info->rows,(double)
3860 cache_info->number_channels,format);
3861 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3862 message);
3863 }
3864 if (status == 0)
3865 {
3866 cache_info->type=UndefinedCache;
3867 return(MagickFalse);
3868 }
3869 return(MagickTrue);
3870 }
3871 }
3872 cache_info->type=UndefinedCache;
3873 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3874 "CacheResourcesExhausted","`%s'",image->filename);
3875 return(MagickFalse);
3876 }
3877 /*
3878 Create pixel cache on disk.
3879 */
3880 if (status == MagickFalse)
3881 {
3882 cache_info->type=UndefinedCache;
3883 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3884 "CacheResourcesExhausted","`%s'",image->filename);
3885 return(MagickFalse);
3886 }
3887 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode) &&
3888 (cache_info->mode != PersistMode))
3889 {
3890 (void) ClosePixelCacheOnDisk(cache_info);
3891 *cache_info->cache_filename='\0';
3892 }
3893 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3894 {
3895 cache_info->type=UndefinedCache;
3896 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3897 image->filename);
3898 return(MagickFalse);
3899 }
3900 status=SetPixelCacheExtent(image,(MagickSizeType) cache_info->offset+
3901 cache_info->length);
3902 if (status == MagickFalse)
3903 {
3904 cache_info->type=UndefinedCache;
3905 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3906 image->filename);
3907 return(MagickFalse);
3908 }
3909 cache_info->type=DiskCache;
3910 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3911 cache_info->metacontent_extent);
3912 if (length == (MagickSizeType) ((size_t) length))
3913 {
3914 status=AcquireMagickResource(MapResource,cache_info->length);
3915 if (status != MagickFalse)
3916 {
3917 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3918 cache_info->offset,(size_t) cache_info->length);
3919 if (cache_info->pixels == (Quantum *) NULL)
3920 {
3921 cache_info->mapped=source_info.mapped;
3922 cache_info->pixels=source_info.pixels;
3923 RelinquishMagickResource(MapResource,cache_info->length);
3924 }
3925 else
3926 {
3927 /*
3928 Create file-backed memory-mapped pixel cache.
3929 */
3930 (void) ClosePixelCacheOnDisk(cache_info);
3931 cache_info->type=MapCache;
3932 cache_info->mapped=MagickTrue;
3933 cache_info->metacontent=(void *) NULL;
3934 if (cache_info->metacontent_extent != 0)
3935 cache_info->metacontent=(void *) (cache_info->pixels+
3936 cache_info->number_channels*number_pixels);
3937 if ((source_info.storage_class != UndefinedClass) &&
3938 (mode != ReadMode))
3939 {
3940 status=ClonePixelCacheRepository(cache_info,&source_info,
3941 exception);
3942 RelinquishPixelCachePixels(&source_info);
3943 }
3944 if (image->debug != MagickFalse)
3945 {
3946 (void) FormatMagickSize(cache_info->length,MagickTrue,"B",
3947 MagickPathExtent,format);
3948 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3949 cache_info->type);
3950 (void) FormatLocaleString(message,MagickPathExtent,
3951 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3952 cache_info->filename,cache_info->cache_filename,
3953 cache_info->file,type,(double) cache_info->columns,
3954 (double) cache_info->rows,(double)
3955 cache_info->number_channels,format);
3956 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3957 message);
3958 }
3959 if (status == 0)
3960 {
3961 cache_info->type=UndefinedCache;
3962 return(MagickFalse);
3963 }
3964 return(MagickTrue);
3965 }
3966 }
3967 }
3968 status=MagickTrue;
3969 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3970 {
3971 status=ClonePixelCacheRepository(cache_info,&source_info,exception);
3972 RelinquishPixelCachePixels(&source_info);
3973 }
3974 if (image->debug != MagickFalse)
3975 {
3976 (void) FormatMagickSize(cache_info->length,MagickFalse,"B",
3977 MagickPathExtent,format);
3978 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3979 cache_info->type);
3980 (void) FormatLocaleString(message,MagickPathExtent,
3981 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",cache_info->filename,
3982 cache_info->cache_filename,cache_info->file,type,(double)
3983 cache_info->columns,(double) cache_info->rows,(double)
3984 cache_info->number_channels,format);
3985 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3986 }
3987 if (status == 0)
3988 {
3989 cache_info->type=UndefinedCache;
3990 return(MagickFalse);
3991 }
3992 return(MagickTrue);
3993 }
3994
3995 /*
3996 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3997 % %
3998 % %
3999 % %
4000 + P e r s i s t P i x e l C a c h e %
4001 % %
4002 % %
4003 % %
4004 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4005 %
4006 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4007 % persistent pixel cache is one that resides on disk and is not destroyed
4008 % when the program exits.
4009 %
4010 % The format of the PersistPixelCache() method is:
4011 %
4012 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4013 % const MagickBooleanType attach,MagickOffsetType *offset,
4014 % ExceptionInfo *exception)
4015 %
4016 % A description of each parameter follows:
4017 %
4018 % o image: the image.
4019 %
4020 % o filename: the persistent pixel cache filename.
4021 %
4022 % o attach: A value other than zero initializes the persistent pixel cache.
4023 %
4024 % o initialize: A value other than zero initializes the persistent pixel
4025 % cache.
4026 %
4027 % o offset: the offset in the persistent cache to store pixels.
4028 %
4029 % o exception: return any errors or warnings in this structure.
4030 %
4031 */
PersistPixelCache(Image * image,const char * filename,const MagickBooleanType attach,MagickOffsetType * offset,ExceptionInfo * exception)4032 MagickExport MagickBooleanType PersistPixelCache(Image *image,
4033 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4034 ExceptionInfo *exception)
4035 {
4036 CacheInfo
4037 *magick_restrict cache_info,
4038 *magick_restrict clone_info;
4039
4040 MagickBooleanType
4041 status;
4042
4043 ssize_t
4044 page_size;
4045
4046 assert(image != (Image *) NULL);
4047 assert(image->signature == MagickCoreSignature);
4048 if (image->debug != MagickFalse)
4049 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4050 assert(image->cache != (void *) NULL);
4051 assert(filename != (const char *) NULL);
4052 assert(offset != (MagickOffsetType *) NULL);
4053 page_size=GetMagickPageSize();
4054 cache_info=(CacheInfo *) image->cache;
4055 assert(cache_info->signature == MagickCoreSignature);
4056 #if defined(MAGICKCORE_OPENCL_SUPPORT)
4057 CopyOpenCLBuffer(cache_info);
4058 #endif
4059 if (attach != MagickFalse)
4060 {
4061 /*
4062 Attach existing persistent pixel cache.
4063 */
4064 if (image->debug != MagickFalse)
4065 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4066 "attach persistent cache");
4067 (void) CopyMagickString(cache_info->cache_filename,filename,
4068 MagickPathExtent);
4069 cache_info->type=MapCache;
4070 cache_info->offset=(*offset);
4071 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4072 return(MagickFalse);
4073 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4074 return(MagickTrue);
4075 }
4076 /*
4077 Clone persistent pixel cache.
4078 */
4079 status=AcquireMagickResource(DiskResource,cache_info->length);
4080 if (status == MagickFalse)
4081 {
4082 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4083 "CacheResourcesExhausted","`%s'",image->filename);
4084 return(MagickFalse);
4085 }
4086 clone_info=(CacheInfo *) ClonePixelCache(cache_info);
4087 clone_info->type=DiskCache;
4088 (void) CopyMagickString(clone_info->cache_filename,filename,MagickPathExtent);
4089 clone_info->file=(-1);
4090 clone_info->storage_class=cache_info->storage_class;
4091 clone_info->colorspace=cache_info->colorspace;
4092 clone_info->alpha_trait=cache_info->alpha_trait;
4093 clone_info->channels=cache_info->channels;
4094 clone_info->columns=cache_info->columns;
4095 clone_info->rows=cache_info->rows;
4096 clone_info->number_channels=cache_info->number_channels;
4097 clone_info->metacontent_extent=cache_info->metacontent_extent;
4098 clone_info->mode=PersistMode;
4099 clone_info->length=cache_info->length;
4100 (void) memcpy(clone_info->channel_map,cache_info->channel_map,
4101 MaxPixelChannels*sizeof(*cache_info->channel_map));
4102 clone_info->offset=(*offset);
4103 status=ClonePixelCacheRepository(clone_info,cache_info,exception);
4104 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4105 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4106 return(status);
4107 }
4108
4109 /*
4110 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4111 % %
4112 % %
4113 % %
4114 + 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 %
4115 % %
4116 % %
4117 % %
4118 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4119 %
4120 % QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
4121 % defined by the region rectangle and returns a pointer to the region. This
4122 % region is subsequently transferred from the pixel cache with
4123 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4124 % pixels are transferred, otherwise a NULL is returned.
4125 %
4126 % The format of the QueueAuthenticPixelCacheNexus() method is:
4127 %
4128 % Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
4129 % const ssize_t y,const size_t columns,const size_t rows,
4130 % const MagickBooleanType clone,NexusInfo *nexus_info,
4131 % ExceptionInfo *exception)
4132 %
4133 % A description of each parameter follows:
4134 %
4135 % o image: the image.
4136 %
4137 % o x,y,columns,rows: These values define the perimeter of a region of
4138 % pixels.
4139 %
4140 % o nexus_info: the cache nexus to set.
4141 %
4142 % o clone: clone the pixel cache.
4143 %
4144 % o exception: return any errors or warnings in this structure.
4145 %
4146 */
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)4147 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
4148 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
4149 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
4150 {
4151 CacheInfo
4152 *magick_restrict cache_info;
4153
4154 MagickOffsetType
4155 offset;
4156
4157 MagickSizeType
4158 number_pixels;
4159
4160 Quantum
4161 *magick_restrict pixels;
4162
4163 /*
4164 Validate pixel cache geometry.
4165 */
4166 assert(image != (const Image *) NULL);
4167 assert(image->signature == MagickCoreSignature);
4168 assert(image->cache != (Cache) NULL);
4169 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
4170 if (cache_info == (Cache) NULL)
4171 return((Quantum *) NULL);
4172 assert(cache_info->signature == MagickCoreSignature);
4173 if ((cache_info->columns == 0) || (cache_info->rows == 0) || (x < 0) ||
4174 (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4175 (y >= (ssize_t) cache_info->rows))
4176 {
4177 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4178 "PixelsAreNotAuthentic","`%s'",image->filename);
4179 return((Quantum *) NULL);
4180 }
4181 offset=(MagickOffsetType) y*cache_info->columns+x;
4182 if (offset < 0)
4183 return((Quantum *) NULL);
4184 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4185 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4186 if ((MagickSizeType) offset >= number_pixels)
4187 return((Quantum *) NULL);
4188 /*
4189 Return pixel cache.
4190 */
4191 pixels=SetPixelCacheNexusPixels(cache_info,WriteMode,x,y,columns,rows,
4192 ((image->channels & WriteMaskChannel) != 0) ||
4193 ((image->channels & CompositeMaskChannel) != 0) ? MagickTrue : MagickFalse,
4194 nexus_info,exception);
4195 return(pixels);
4196 }
4197
4198 /*
4199 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4200 % %
4201 % %
4202 % %
4203 + 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 %
4204 % %
4205 % %
4206 % %
4207 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4208 %
4209 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
4210 % defined by the region rectangle and returns a pointer to the region. This
4211 % region is subsequently transferred from the pixel cache with
4212 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4213 % pixels are transferred, otherwise a NULL is returned.
4214 %
4215 % The format of the QueueAuthenticPixelsCache() method is:
4216 %
4217 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4218 % const ssize_t y,const size_t columns,const size_t rows,
4219 % ExceptionInfo *exception)
4220 %
4221 % A description of each parameter follows:
4222 %
4223 % o image: the image.
4224 %
4225 % o x,y,columns,rows: These values define the perimeter of a region of
4226 % pixels.
4227 %
4228 % o exception: return any errors or warnings in this structure.
4229 %
4230 */
QueueAuthenticPixelsCache(Image * image,const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,ExceptionInfo * exception)4231 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4232 const ssize_t y,const size_t columns,const size_t rows,
4233 ExceptionInfo *exception)
4234 {
4235 CacheInfo
4236 *magick_restrict cache_info;
4237
4238 const int
4239 id = GetOpenMPThreadId();
4240
4241 Quantum
4242 *magick_restrict pixels;
4243
4244 assert(image != (const Image *) NULL);
4245 assert(image->signature == MagickCoreSignature);
4246 assert(image->cache != (Cache) NULL);
4247 cache_info=(CacheInfo *) image->cache;
4248 assert(cache_info->signature == MagickCoreSignature);
4249 assert(id < (int) cache_info->number_threads);
4250 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4251 cache_info->nexus_info[id],exception);
4252 return(pixels);
4253 }
4254
4255 /*
4256 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4257 % %
4258 % %
4259 % %
4260 % Q u e u e A u t h e n t i c P i x e l s %
4261 % %
4262 % %
4263 % %
4264 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4265 %
4266 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
4267 % successfully initialized a pointer to a Quantum array representing the
4268 % region is returned, otherwise NULL is returned. The returned pointer may
4269 % point to a temporary working buffer for the pixels or it may point to the
4270 % final location of the pixels in memory.
4271 %
4272 % Write-only access means that any existing pixel values corresponding to
4273 % the region are ignored. This is useful if the initial image is being
4274 % created from scratch, or if the existing pixel values are to be
4275 % completely replaced without need to refer to their pre-existing values.
4276 % The application is free to read and write the pixel buffer returned by
4277 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4278 % initialize the pixel array values. Initializing pixel array values is the
4279 % application's responsibility.
4280 %
4281 % Performance is maximized if the selected region is part of one row, or
4282 % one or more full rows, since then there is opportunity to access the
4283 % pixels in-place (without a copy) if the image is in memory, or in a
4284 % memory-mapped file. The returned pointer must *never* be deallocated
4285 % by the user.
4286 %
4287 % Pixels accessed via the returned pointer represent a simple array of type
4288 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
4289 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4290 % obtain the meta-content (of type void) corresponding to the region.
4291 % Once the Quantum (and/or Quantum) array has been updated, the
4292 % changes must be saved back to the underlying image using
4293 % SyncAuthenticPixels() or they may be lost.
4294 %
4295 % The format of the QueueAuthenticPixels() method is:
4296 %
4297 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4298 % const ssize_t y,const size_t columns,const size_t rows,
4299 % ExceptionInfo *exception)
4300 %
4301 % A description of each parameter follows:
4302 %
4303 % o image: the image.
4304 %
4305 % o x,y,columns,rows: These values define the perimeter of a region of
4306 % pixels.
4307 %
4308 % o exception: return any errors or warnings in this structure.
4309 %
4310 */
QueueAuthenticPixels(Image * image,const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,ExceptionInfo * exception)4311 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4312 const ssize_t y,const size_t columns,const size_t rows,
4313 ExceptionInfo *exception)
4314 {
4315 CacheInfo
4316 *magick_restrict cache_info;
4317
4318 const int
4319 id = GetOpenMPThreadId();
4320
4321 Quantum
4322 *magick_restrict pixels;
4323
4324 assert(image != (Image *) NULL);
4325 assert(image->signature == MagickCoreSignature);
4326 assert(image->cache != (Cache) NULL);
4327 cache_info=(CacheInfo *) image->cache;
4328 assert(cache_info->signature == MagickCoreSignature);
4329 if (cache_info->methods.queue_authentic_pixels_handler !=
4330 (QueueAuthenticPixelsHandler) NULL)
4331 {
4332 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
4333 columns,rows,exception);
4334 return(pixels);
4335 }
4336 assert(id < (int) cache_info->number_threads);
4337 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4338 cache_info->nexus_info[id],exception);
4339 return(pixels);
4340 }
4341
4342 /*
4343 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4344 % %
4345 % %
4346 % %
4347 + 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 %
4348 % %
4349 % %
4350 % %
4351 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4352 %
4353 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
4354 % the pixel cache.
4355 %
4356 % The format of the ReadPixelCacheMetacontent() method is:
4357 %
4358 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4359 % NexusInfo *nexus_info,ExceptionInfo *exception)
4360 %
4361 % A description of each parameter follows:
4362 %
4363 % o cache_info: the pixel cache.
4364 %
4365 % o nexus_info: the cache nexus to read the metacontent.
4366 %
4367 % o exception: return any errors or warnings in this structure.
4368 %
4369 */
4370
ReadPixelCacheRegion(const CacheInfo * magick_restrict cache_info,const MagickOffsetType offset,const MagickSizeType length,unsigned char * magick_restrict buffer)4371 static inline MagickOffsetType ReadPixelCacheRegion(
4372 const CacheInfo *magick_restrict cache_info,const MagickOffsetType offset,
4373 const MagickSizeType length,unsigned char *magick_restrict buffer)
4374 {
4375 MagickOffsetType
4376 i;
4377
4378 ssize_t
4379 count;
4380
4381 #if !defined(MAGICKCORE_HAVE_PREAD)
4382 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
4383 return((MagickOffsetType) -1);
4384 #endif
4385 count=0;
4386 for (i=0; i < (MagickOffsetType) length; i+=count)
4387 {
4388 #if !defined(MAGICKCORE_HAVE_PREAD)
4389 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,(size_t)
4390 MAGICK_SSIZE_MAX));
4391 #else
4392 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,(size_t)
4393 MAGICK_SSIZE_MAX),offset+i);
4394 #endif
4395 if (count <= 0)
4396 {
4397 count=0;
4398 if (errno != EINTR)
4399 break;
4400 }
4401 }
4402 return(i);
4403 }
4404
ReadPixelCacheMetacontent(CacheInfo * magick_restrict cache_info,NexusInfo * magick_restrict nexus_info,ExceptionInfo * exception)4405 static MagickBooleanType ReadPixelCacheMetacontent(
4406 CacheInfo *magick_restrict cache_info,NexusInfo *magick_restrict nexus_info,
4407 ExceptionInfo *exception)
4408 {
4409 MagickOffsetType
4410 count,
4411 offset;
4412
4413 MagickSizeType
4414 extent,
4415 length;
4416
4417 ssize_t
4418 y;
4419
4420 unsigned char
4421 *magick_restrict q;
4422
4423 size_t
4424 rows;
4425
4426 if (cache_info->metacontent_extent == 0)
4427 return(MagickFalse);
4428 if (nexus_info->authentic_pixel_cache != MagickFalse)
4429 return(MagickTrue);
4430 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4431 nexus_info->region.x;
4432 length=(MagickSizeType) nexus_info->region.width*
4433 cache_info->metacontent_extent;
4434 extent=length*nexus_info->region.height;
4435 rows=nexus_info->region.height;
4436 y=0;
4437 q=(unsigned char *) nexus_info->metacontent;
4438 switch (cache_info->type)
4439 {
4440 case MemoryCache:
4441 case MapCache:
4442 {
4443 unsigned char
4444 *magick_restrict p;
4445
4446 /*
4447 Read meta-content from memory.
4448 */
4449 if ((cache_info->columns == nexus_info->region.width) &&
4450 (extent == (MagickSizeType) ((size_t) extent)))
4451 {
4452 length=extent;
4453 rows=1UL;
4454 }
4455 p=(unsigned char *) cache_info->metacontent+offset*
4456 cache_info->metacontent_extent;
4457 for (y=0; y < (ssize_t) rows; y++)
4458 {
4459 (void) memcpy(q,p,(size_t) length);
4460 p+=cache_info->metacontent_extent*cache_info->columns;
4461 q+=cache_info->metacontent_extent*nexus_info->region.width;
4462 }
4463 break;
4464 }
4465 case DiskCache:
4466 {
4467 /*
4468 Read meta content from disk.
4469 */
4470 LockSemaphoreInfo(cache_info->file_semaphore);
4471 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4472 {
4473 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4474 cache_info->cache_filename);
4475 UnlockSemaphoreInfo(cache_info->file_semaphore);
4476 return(MagickFalse);
4477 }
4478 if ((cache_info->columns == nexus_info->region.width) &&
4479 (extent <= MagickMaxBufferExtent))
4480 {
4481 length=extent;
4482 rows=1UL;
4483 }
4484 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4485 for (y=0; y < (ssize_t) rows; y++)
4486 {
4487 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4488 cache_info->number_channels*sizeof(Quantum)+offset*
4489 cache_info->metacontent_extent,length,(unsigned char *) q);
4490 if (count != (MagickOffsetType) length)
4491 break;
4492 offset+=cache_info->columns;
4493 q+=cache_info->metacontent_extent*nexus_info->region.width;
4494 }
4495 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4496 (void) ClosePixelCacheOnDisk(cache_info);
4497 UnlockSemaphoreInfo(cache_info->file_semaphore);
4498 break;
4499 }
4500 case DistributedCache:
4501 {
4502 RectangleInfo
4503 region;
4504
4505 /*
4506 Read metacontent from distributed cache.
4507 */
4508 LockSemaphoreInfo(cache_info->file_semaphore);
4509 region=nexus_info->region;
4510 if ((cache_info->columns != nexus_info->region.width) ||
4511 (extent > MagickMaxBufferExtent))
4512 region.height=1UL;
4513 else
4514 {
4515 length=extent;
4516 rows=1UL;
4517 }
4518 for (y=0; y < (ssize_t) rows; y++)
4519 {
4520 count=ReadDistributePixelCacheMetacontent((DistributeCacheInfo *)
4521 cache_info->server_info,®ion,length,(unsigned char *) q);
4522 if (count != (MagickOffsetType) length)
4523 break;
4524 q+=cache_info->metacontent_extent*nexus_info->region.width;
4525 region.y++;
4526 }
4527 UnlockSemaphoreInfo(cache_info->file_semaphore);
4528 break;
4529 }
4530 default:
4531 break;
4532 }
4533 if (y < (ssize_t) rows)
4534 {
4535 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4536 cache_info->cache_filename);
4537 return(MagickFalse);
4538 }
4539 if ((cache_info->debug != MagickFalse) &&
4540 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4541 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4542 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4543 nexus_info->region.width,(double) nexus_info->region.height,(double)
4544 nexus_info->region.x,(double) nexus_info->region.y);
4545 return(MagickTrue);
4546 }
4547
4548 /*
4549 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4550 % %
4551 % %
4552 % %
4553 + R e a d P i x e l C a c h e P i x e l s %
4554 % %
4555 % %
4556 % %
4557 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4558 %
4559 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4560 % cache.
4561 %
4562 % The format of the ReadPixelCachePixels() method is:
4563 %
4564 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4565 % NexusInfo *nexus_info,ExceptionInfo *exception)
4566 %
4567 % A description of each parameter follows:
4568 %
4569 % o cache_info: the pixel cache.
4570 %
4571 % o nexus_info: the cache nexus to read the pixels.
4572 %
4573 % o exception: return any errors or warnings in this structure.
4574 %
4575 */
ReadPixelCachePixels(CacheInfo * magick_restrict cache_info,NexusInfo * magick_restrict nexus_info,ExceptionInfo * exception)4576 static MagickBooleanType ReadPixelCachePixels(
4577 CacheInfo *magick_restrict cache_info,NexusInfo *magick_restrict nexus_info,
4578 ExceptionInfo *exception)
4579 {
4580 MagickOffsetType
4581 count,
4582 offset;
4583
4584 MagickSizeType
4585 extent,
4586 length;
4587
4588 Quantum
4589 *magick_restrict q;
4590
4591 ssize_t
4592 y;
4593
4594 size_t
4595 number_channels,
4596 rows;
4597
4598 if (nexus_info->authentic_pixel_cache != MagickFalse)
4599 return(MagickTrue);
4600 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns;
4601 if ((ssize_t) (offset/cache_info->columns) != nexus_info->region.y)
4602 return(MagickFalse);
4603 offset+=nexus_info->region.x;
4604 number_channels=cache_info->number_channels;
4605 length=(MagickSizeType) number_channels*nexus_info->region.width*
4606 sizeof(Quantum);
4607 if ((length/number_channels/sizeof(Quantum)) != nexus_info->region.width)
4608 return(MagickFalse);
4609 rows=nexus_info->region.height;
4610 extent=length*rows;
4611 if ((extent == 0) || ((extent/length) != rows))
4612 return(MagickFalse);
4613 y=0;
4614 q=nexus_info->pixels;
4615 switch (cache_info->type)
4616 {
4617 case MemoryCache:
4618 case MapCache:
4619 {
4620 Quantum
4621 *magick_restrict p;
4622
4623 /*
4624 Read pixels from memory.
4625 */
4626 if ((cache_info->columns == nexus_info->region.width) &&
4627 (extent == (MagickSizeType) ((size_t) extent)))
4628 {
4629 length=extent;
4630 rows=1UL;
4631 }
4632 p=cache_info->pixels+cache_info->number_channels*offset;
4633 for (y=0; y < (ssize_t) rows; y++)
4634 {
4635 (void) memcpy(q,p,(size_t) length);
4636 p+=cache_info->number_channels*cache_info->columns;
4637 q+=cache_info->number_channels*nexus_info->region.width;
4638 }
4639 break;
4640 }
4641 case DiskCache:
4642 {
4643 /*
4644 Read pixels from disk.
4645 */
4646 LockSemaphoreInfo(cache_info->file_semaphore);
4647 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4648 {
4649 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4650 cache_info->cache_filename);
4651 UnlockSemaphoreInfo(cache_info->file_semaphore);
4652 return(MagickFalse);
4653 }
4654 if ((cache_info->columns == nexus_info->region.width) &&
4655 (extent <= MagickMaxBufferExtent))
4656 {
4657 length=extent;
4658 rows=1UL;
4659 }
4660 for (y=0; y < (ssize_t) rows; y++)
4661 {
4662 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4663 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4664 if (count != (MagickOffsetType) length)
4665 break;
4666 offset+=cache_info->columns;
4667 q+=cache_info->number_channels*nexus_info->region.width;
4668 }
4669 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4670 (void) ClosePixelCacheOnDisk(cache_info);
4671 UnlockSemaphoreInfo(cache_info->file_semaphore);
4672 break;
4673 }
4674 case DistributedCache:
4675 {
4676 RectangleInfo
4677 region;
4678
4679 /*
4680 Read pixels from distributed cache.
4681 */
4682 LockSemaphoreInfo(cache_info->file_semaphore);
4683 region=nexus_info->region;
4684 if ((cache_info->columns != nexus_info->region.width) ||
4685 (extent > MagickMaxBufferExtent))
4686 region.height=1UL;
4687 else
4688 {
4689 length=extent;
4690 rows=1UL;
4691 }
4692 for (y=0; y < (ssize_t) rows; y++)
4693 {
4694 count=ReadDistributePixelCachePixels((DistributeCacheInfo *)
4695 cache_info->server_info,®ion,length,(unsigned char *) q);
4696 if (count != (MagickOffsetType) length)
4697 break;
4698 q+=cache_info->number_channels*nexus_info->region.width;
4699 region.y++;
4700 }
4701 UnlockSemaphoreInfo(cache_info->file_semaphore);
4702 break;
4703 }
4704 default:
4705 break;
4706 }
4707 if (y < (ssize_t) rows)
4708 {
4709 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4710 cache_info->cache_filename);
4711 return(MagickFalse);
4712 }
4713 if ((cache_info->debug != MagickFalse) &&
4714 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4715 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4716 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4717 nexus_info->region.width,(double) nexus_info->region.height,(double)
4718 nexus_info->region.x,(double) nexus_info->region.y);
4719 return(MagickTrue);
4720 }
4721
4722 /*
4723 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4724 % %
4725 % %
4726 % %
4727 + R e f e r e n c e P i x e l C a c h e %
4728 % %
4729 % %
4730 % %
4731 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4732 %
4733 % ReferencePixelCache() increments the reference count associated with the
4734 % pixel cache returning a pointer to the cache.
4735 %
4736 % The format of the ReferencePixelCache method is:
4737 %
4738 % Cache ReferencePixelCache(Cache cache_info)
4739 %
4740 % A description of each parameter follows:
4741 %
4742 % o cache_info: the pixel cache.
4743 %
4744 */
ReferencePixelCache(Cache cache)4745 MagickPrivate Cache ReferencePixelCache(Cache cache)
4746 {
4747 CacheInfo
4748 *magick_restrict cache_info;
4749
4750 assert(cache != (Cache *) NULL);
4751 cache_info=(CacheInfo *) cache;
4752 assert(cache_info->signature == MagickCoreSignature);
4753 LockSemaphoreInfo(cache_info->semaphore);
4754 cache_info->reference_count++;
4755 UnlockSemaphoreInfo(cache_info->semaphore);
4756 return(cache_info);
4757 }
4758
4759 /*
4760 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4761 % %
4762 % %
4763 % %
4764 + R e s e t P i x e l C a c h e C h a n n e l s %
4765 % %
4766 % %
4767 % %
4768 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4769 %
4770 % ResetPixelCacheChannels() resets the pixel cache channels.
4771 %
4772 % The format of the ResetPixelCacheChannels method is:
4773 %
4774 % void ResetPixelCacheChannels(Image *)
4775 %
4776 % A description of each parameter follows:
4777 %
4778 % o image: the image.
4779 %
4780 */
ResetPixelCacheChannels(Image * image)4781 MagickPrivate void ResetPixelCacheChannels(Image *image)
4782 {
4783 CacheInfo
4784 *magick_restrict cache_info;
4785
4786 assert(image != (const Image *) NULL);
4787 assert(image->signature == MagickCoreSignature);
4788 assert(image->cache != (Cache) NULL);
4789 cache_info=(CacheInfo *) image->cache;
4790 assert(cache_info->signature == MagickCoreSignature);
4791 cache_info->number_channels=GetPixelChannels(image);
4792 }
4793
4794 /*
4795 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4796 % %
4797 % %
4798 % %
4799 + 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 %
4800 % %
4801 % %
4802 % %
4803 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4804 %
4805 % ResetCacheAnonymousMemory() resets the anonymous_memory value.
4806 %
4807 % The format of the ResetCacheAnonymousMemory method is:
4808 %
4809 % void ResetCacheAnonymousMemory(void)
4810 %
4811 */
ResetCacheAnonymousMemory(void)4812 MagickPrivate void ResetCacheAnonymousMemory(void)
4813 {
4814 cache_anonymous_memory=0;
4815 }
4816
4817 /*
4818 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4819 % %
4820 % %
4821 % %
4822 + R e s e t P i x e l C a c h e E p o c h %
4823 % %
4824 % %
4825 % %
4826 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4827 %
4828 % ResetPixelCacheEpoch() resets the pixel cache epoch.
4829 %
4830 % The format of the ResetPixelCacheEpoch method is:
4831 %
4832 % void ResetPixelCacheEpoch(void)
4833 %
4834 */
ResetPixelCacheEpoch(void)4835 MagickPrivate void ResetPixelCacheEpoch(void)
4836 {
4837 cache_epoch=0;
4838 }
4839
4840 /*
4841 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4842 % %
4843 % %
4844 % %
4845 + S e t P i x e l C a c h e M e t h o d s %
4846 % %
4847 % %
4848 % %
4849 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4850 %
4851 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4852 %
4853 % The format of the SetPixelCacheMethods() method is:
4854 %
4855 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4856 %
4857 % A description of each parameter follows:
4858 %
4859 % o cache: the pixel cache.
4860 %
4861 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4862 %
4863 */
SetPixelCacheMethods(Cache cache,CacheMethods * cache_methods)4864 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4865 {
4866 CacheInfo
4867 *magick_restrict cache_info;
4868
4869 GetOneAuthenticPixelFromHandler
4870 get_one_authentic_pixel_from_handler;
4871
4872 GetOneVirtualPixelFromHandler
4873 get_one_virtual_pixel_from_handler;
4874
4875 /*
4876 Set cache pixel methods.
4877 */
4878 assert(cache != (Cache) NULL);
4879 assert(cache_methods != (CacheMethods *) NULL);
4880 cache_info=(CacheInfo *) cache;
4881 assert(cache_info->signature == MagickCoreSignature);
4882 if (cache_info->debug != MagickFalse)
4883 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4884 cache_info->filename);
4885 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4886 cache_info->methods.get_virtual_pixel_handler=
4887 cache_methods->get_virtual_pixel_handler;
4888 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4889 cache_info->methods.destroy_pixel_handler=
4890 cache_methods->destroy_pixel_handler;
4891 if (cache_methods->get_virtual_metacontent_from_handler !=
4892 (GetVirtualMetacontentFromHandler) NULL)
4893 cache_info->methods.get_virtual_metacontent_from_handler=
4894 cache_methods->get_virtual_metacontent_from_handler;
4895 if (cache_methods->get_authentic_pixels_handler !=
4896 (GetAuthenticPixelsHandler) NULL)
4897 cache_info->methods.get_authentic_pixels_handler=
4898 cache_methods->get_authentic_pixels_handler;
4899 if (cache_methods->queue_authentic_pixels_handler !=
4900 (QueueAuthenticPixelsHandler) NULL)
4901 cache_info->methods.queue_authentic_pixels_handler=
4902 cache_methods->queue_authentic_pixels_handler;
4903 if (cache_methods->sync_authentic_pixels_handler !=
4904 (SyncAuthenticPixelsHandler) NULL)
4905 cache_info->methods.sync_authentic_pixels_handler=
4906 cache_methods->sync_authentic_pixels_handler;
4907 if (cache_methods->get_authentic_pixels_from_handler !=
4908 (GetAuthenticPixelsFromHandler) NULL)
4909 cache_info->methods.get_authentic_pixels_from_handler=
4910 cache_methods->get_authentic_pixels_from_handler;
4911 if (cache_methods->get_authentic_metacontent_from_handler !=
4912 (GetAuthenticMetacontentFromHandler) NULL)
4913 cache_info->methods.get_authentic_metacontent_from_handler=
4914 cache_methods->get_authentic_metacontent_from_handler;
4915 get_one_virtual_pixel_from_handler=
4916 cache_info->methods.get_one_virtual_pixel_from_handler;
4917 if (get_one_virtual_pixel_from_handler !=
4918 (GetOneVirtualPixelFromHandler) NULL)
4919 cache_info->methods.get_one_virtual_pixel_from_handler=
4920 cache_methods->get_one_virtual_pixel_from_handler;
4921 get_one_authentic_pixel_from_handler=
4922 cache_methods->get_one_authentic_pixel_from_handler;
4923 if (get_one_authentic_pixel_from_handler !=
4924 (GetOneAuthenticPixelFromHandler) NULL)
4925 cache_info->methods.get_one_authentic_pixel_from_handler=
4926 cache_methods->get_one_authentic_pixel_from_handler;
4927 }
4928
4929 /*
4930 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4931 % %
4932 % %
4933 % %
4934 + S e t P i x e l C a c h e N e x u s P i x e l s %
4935 % %
4936 % %
4937 % %
4938 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4939 %
4940 % SetPixelCacheNexusPixels() defines the region of the cache for the
4941 % specified cache nexus.
4942 %
4943 % The format of the SetPixelCacheNexusPixels() method is:
4944 %
4945 % Quantum SetPixelCacheNexusPixels(
4946 % const CacheInfo *magick_restrict cache_info,const MapMode mode,
4947 % const ssize_t x,const ssize_t y,const size_t width,const size_t height,
4948 % const MagickBooleanType buffered,NexusInfo *magick_restrict nexus_info,
4949 % ExceptionInfo *exception)
4950 %
4951 % A description of each parameter follows:
4952 %
4953 % o cache_info: the pixel cache.
4954 %
4955 % o mode: ReadMode, WriteMode, or IOMode.
4956 %
4957 % o x,y,width,height: define the region of this particular cache nexus.
4958 %
4959 % o buffered: if true, nexus pixels are buffered.
4960 %
4961 % o nexus_info: the cache nexus to set.
4962 %
4963 % o exception: return any errors or warnings in this structure.
4964 %
4965 */
4966
AcquireCacheNexusPixels(const CacheInfo * magick_restrict cache_info,const MagickSizeType length,NexusInfo * magick_restrict nexus_info,ExceptionInfo * exception)4967 static inline MagickBooleanType AcquireCacheNexusPixels(
4968 const CacheInfo *magick_restrict cache_info,const MagickSizeType length,
4969 NexusInfo *magick_restrict nexus_info,ExceptionInfo *exception)
4970 {
4971 if (length != (MagickSizeType) ((size_t) length))
4972 {
4973 (void) ThrowMagickException(exception,GetMagickModule(),
4974 ResourceLimitError,"PixelCacheAllocationFailed","`%s'",
4975 cache_info->filename);
4976 return(MagickFalse);
4977 }
4978 nexus_info->length=0;
4979 nexus_info->mapped=MagickFalse;
4980 if (cache_anonymous_memory <= 0)
4981 {
4982 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
4983 (size_t) length));
4984 if (nexus_info->cache != (Quantum *) NULL)
4985 (void) memset(nexus_info->cache,0,(size_t) length);
4986 }
4987 else
4988 {
4989 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t) length);
4990 if (nexus_info->cache != (Quantum *) NULL)
4991 nexus_info->mapped=MagickTrue;
4992 }
4993 if (nexus_info->cache == (Quantum *) NULL)
4994 {
4995 (void) ThrowMagickException(exception,GetMagickModule(),
4996 ResourceLimitError,"PixelCacheAllocationFailed","`%s'",
4997 cache_info->filename);
4998 return(MagickFalse);
4999 }
5000 nexus_info->length=length;
5001 return(MagickTrue);
5002 }
5003
PrefetchPixelCacheNexusPixels(const NexusInfo * nexus_info,const MapMode mode)5004 static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
5005 const MapMode mode)
5006 {
5007 if (nexus_info->length < CACHE_LINE_SIZE)
5008 return;
5009 if (mode == ReadMode)
5010 {
5011 MagickCachePrefetch((unsigned char *) nexus_info->pixels+CACHE_LINE_SIZE,
5012 0,1);
5013 return;
5014 }
5015 MagickCachePrefetch((unsigned char *) nexus_info->pixels+CACHE_LINE_SIZE,1,1);
5016 }
5017
ValidatePixelOffset(const ssize_t x,const size_t a)5018 static inline MagickBooleanType ValidatePixelOffset(const ssize_t x,
5019 const size_t a)
5020 {
5021 if ((x >= 0) && (x >= ((ssize_t) MAGICK_SSIZE_MAX-(ssize_t) a)))
5022 return(MagickFalse);
5023 if (x <= ((ssize_t) MAGICK_SSIZE_MIN+(ssize_t) a))
5024 return(MagickFalse);
5025 return(MagickTrue);
5026 }
5027
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)5028 static Quantum *SetPixelCacheNexusPixels(
5029 const CacheInfo *magick_restrict cache_info,const MapMode mode,
5030 const ssize_t x,const ssize_t y,const size_t width,const size_t height,
5031 const MagickBooleanType buffered,NexusInfo *magick_restrict nexus_info,
5032 ExceptionInfo *exception)
5033 {
5034 MagickBooleanType
5035 status;
5036
5037 MagickSizeType
5038 length,
5039 number_pixels;
5040
5041 assert(cache_info != (const CacheInfo *) NULL);
5042 assert(cache_info->signature == MagickCoreSignature);
5043 if (cache_info->type == UndefinedCache)
5044 return((Quantum *) NULL);
5045 assert(nexus_info->signature == MagickCoreSignature);
5046 (void) memset(&nexus_info->region,0,sizeof(nexus_info->region));
5047 if ((width == 0) || (height == 0))
5048 {
5049 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
5050 "NoPixelsDefinedInCache","`%s'",cache_info->filename);
5051 return((Quantum *) NULL);
5052 }
5053 if (((MagickSizeType) width > cache_info->width_limit) ||
5054 ((MagickSizeType) height > cache_info->height_limit) ||
5055 (ValidatePixelOffset(x,width) == MagickFalse) ||
5056 (ValidatePixelOffset(y,height) == MagickFalse))
5057 {
5058 (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
5059 "WidthOrHeightExceedsLimit","`%s'",cache_info->filename);
5060 return((Quantum *) NULL);
5061 }
5062 if (((cache_info->type == MemoryCache) || (cache_info->type == MapCache)) &&
5063 (buffered == MagickFalse))
5064 {
5065 if (((x >= 0) && (y >= 0) &&
5066 (((ssize_t) height+y-1) < (ssize_t) cache_info->rows)) &&
5067 (((x == 0) && (width == cache_info->columns)) || ((height == 1) &&
5068 (((ssize_t) width+x-1) < (ssize_t) cache_info->columns))))
5069 {
5070 MagickOffsetType
5071 offset;
5072
5073 /*
5074 Pixels are accessed directly from memory.
5075 */
5076 offset=(MagickOffsetType) y*cache_info->columns+x;
5077 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
5078 offset;
5079 nexus_info->metacontent=(void *) NULL;
5080 if (cache_info->metacontent_extent != 0)
5081 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
5082 offset*cache_info->metacontent_extent;
5083 nexus_info->region.width=width;
5084 nexus_info->region.height=height;
5085 nexus_info->region.x=x;
5086 nexus_info->region.y=y;
5087 nexus_info->authentic_pixel_cache=MagickTrue;
5088 PrefetchPixelCacheNexusPixels(nexus_info,mode);
5089 return(nexus_info->pixels);
5090 }
5091 }
5092 /*
5093 Pixels are stored in a staging region until they are synced to the cache.
5094 */
5095 number_pixels=(MagickSizeType) width*height;
5096 length=MagickMax(number_pixels,MagickMax(cache_info->columns,
5097 cache_info->rows))*cache_info->number_channels*sizeof(*nexus_info->pixels);
5098 if (cache_info->metacontent_extent != 0)
5099 length+=number_pixels*cache_info->metacontent_extent;
5100 status=MagickTrue;
5101 if (nexus_info->cache == (Quantum *) NULL)
5102 status=AcquireCacheNexusPixels(cache_info,length,nexus_info,exception);
5103 else
5104 if (nexus_info->length < length)
5105 {
5106 RelinquishCacheNexusPixels(nexus_info);
5107 status=AcquireCacheNexusPixels(cache_info,length,nexus_info,exception);
5108 }
5109 if (status == MagickFalse)
5110 return((Quantum *) NULL);
5111 nexus_info->pixels=nexus_info->cache;
5112 nexus_info->metacontent=(void *) NULL;
5113 if (cache_info->metacontent_extent != 0)
5114 nexus_info->metacontent=(void *) (nexus_info->pixels+
5115 cache_info->number_channels*number_pixels);
5116 nexus_info->region.width=width;
5117 nexus_info->region.height=height;
5118 nexus_info->region.x=x;
5119 nexus_info->region.y=y;
5120 nexus_info->authentic_pixel_cache=cache_info->type == PingCache ?
5121 MagickTrue : MagickFalse;
5122 PrefetchPixelCacheNexusPixels(nexus_info,mode);
5123 return(nexus_info->pixels);
5124 }
5125
5126 /*
5127 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5128 % %
5129 % %
5130 % %
5131 % 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 %
5132 % %
5133 % %
5134 % %
5135 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5136 %
5137 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5138 % pixel cache and returns the previous setting. A virtual pixel is any pixel
5139 % access that is outside the boundaries of the image cache.
5140 %
5141 % The format of the SetPixelCacheVirtualMethod() method is:
5142 %
5143 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
5144 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
5145 %
5146 % A description of each parameter follows:
5147 %
5148 % o image: the image.
5149 %
5150 % o virtual_pixel_method: choose the type of virtual pixel.
5151 %
5152 % o exception: return any errors or warnings in this structure.
5153 %
5154 */
5155
SetCacheAlphaChannel(Image * image,const Quantum alpha,ExceptionInfo * exception)5156 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
5157 ExceptionInfo *exception)
5158 {
5159 CacheInfo
5160 *magick_restrict cache_info;
5161
5162 CacheView
5163 *magick_restrict image_view;
5164
5165 MagickBooleanType
5166 status;
5167
5168 ssize_t
5169 y;
5170
5171 assert(image != (Image *) NULL);
5172 assert(image->signature == MagickCoreSignature);
5173 if (image->debug != MagickFalse)
5174 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5175 assert(image->cache != (Cache) NULL);
5176 cache_info=(CacheInfo *) image->cache;
5177 assert(cache_info->signature == MagickCoreSignature);
5178 image->alpha_trait=BlendPixelTrait;
5179 status=MagickTrue;
5180 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
5181 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5182 #pragma omp parallel for schedule(static) shared(status) \
5183 magick_number_threads(image,image,image->rows,1)
5184 #endif
5185 for (y=0; y < (ssize_t) image->rows; y++)
5186 {
5187 Quantum
5188 *magick_restrict q;
5189
5190 ssize_t
5191 x;
5192
5193 if (status == MagickFalse)
5194 continue;
5195 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
5196 if (q == (Quantum *) NULL)
5197 {
5198 status=MagickFalse;
5199 continue;
5200 }
5201 for (x=0; x < (ssize_t) image->columns; x++)
5202 {
5203 SetPixelAlpha(image,alpha,q);
5204 q+=GetPixelChannels(image);
5205 }
5206 status=SyncCacheViewAuthenticPixels(image_view,exception);
5207 }
5208 image_view=DestroyCacheView(image_view);
5209 return(status);
5210 }
5211
SetPixelCacheVirtualMethod(Image * image,const VirtualPixelMethod virtual_pixel_method,ExceptionInfo * exception)5212 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
5213 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
5214 {
5215 CacheInfo
5216 *magick_restrict cache_info;
5217
5218 VirtualPixelMethod
5219 method;
5220
5221 assert(image != (Image *) NULL);
5222 assert(image->signature == MagickCoreSignature);
5223 if (image->debug != MagickFalse)
5224 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5225 assert(image->cache != (Cache) NULL);
5226 cache_info=(CacheInfo *) image->cache;
5227 assert(cache_info->signature == MagickCoreSignature);
5228 method=cache_info->virtual_pixel_method;
5229 cache_info->virtual_pixel_method=virtual_pixel_method;
5230 if ((image->columns != 0) && (image->rows != 0))
5231 switch (virtual_pixel_method)
5232 {
5233 case BackgroundVirtualPixelMethod:
5234 {
5235 if ((image->background_color.alpha_trait != UndefinedPixelTrait) &&
5236 (image->alpha_trait == UndefinedPixelTrait))
5237 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
5238 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
5239 (IsGrayColorspace(image->colorspace) != MagickFalse))
5240 (void) SetImageColorspace(image,sRGBColorspace,exception);
5241 break;
5242 }
5243 case TransparentVirtualPixelMethod:
5244 {
5245 if (image->alpha_trait == UndefinedPixelTrait)
5246 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
5247 break;
5248 }
5249 default:
5250 break;
5251 }
5252 return(method);
5253 }
5254
5255 #if defined(MAGICKCORE_OPENCL_SUPPORT)
5256 /*
5257 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5258 % %
5259 % %
5260 % %
5261 + 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 %
5262 % %
5263 % %
5264 % %
5265 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5266 %
5267 % SyncAuthenticOpenCLBuffer() makes sure that all the OpenCL operations have
5268 % been completed and updates the host memory.
5269 %
5270 % The format of the SyncAuthenticOpenCLBuffer() method is:
5271 %
5272 % void SyncAuthenticOpenCLBuffer(const Image *image)
5273 %
5274 % A description of each parameter follows:
5275 %
5276 % o image: the image.
5277 %
5278 */
5279
CopyOpenCLBuffer(CacheInfo * magick_restrict cache_info)5280 static void CopyOpenCLBuffer(CacheInfo *magick_restrict cache_info)
5281 {
5282 assert(cache_info != (CacheInfo *) NULL);
5283 assert(cache_info->signature == MagickCoreSignature);
5284 if ((cache_info->type != MemoryCache) ||
5285 (cache_info->opencl == (MagickCLCacheInfo) NULL))
5286 return;
5287 /*
5288 Ensure single threaded access to OpenCL environment.
5289 */
5290 LockSemaphoreInfo(cache_info->semaphore);
5291 cache_info->opencl=CopyMagickCLCacheInfo(cache_info->opencl);
5292 UnlockSemaphoreInfo(cache_info->semaphore);
5293 }
5294
SyncAuthenticOpenCLBuffer(const Image * image)5295 MagickPrivate void SyncAuthenticOpenCLBuffer(const Image *image)
5296 {
5297 CacheInfo
5298 *magick_restrict cache_info;
5299
5300 assert(image != (const Image *) NULL);
5301 cache_info=(CacheInfo *) image->cache;
5302 CopyOpenCLBuffer(cache_info);
5303 }
5304 #endif
5305
5306 /*
5307 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5308 % %
5309 % %
5310 % %
5311 + 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 %
5312 % %
5313 % %
5314 % %
5315 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5316 %
5317 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5318 % in-memory or disk cache. The method returns MagickTrue if the pixel region
5319 % is synced, otherwise MagickFalse.
5320 %
5321 % The format of the SyncAuthenticPixelCacheNexus() method is:
5322 %
5323 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5324 % NexusInfo *nexus_info,ExceptionInfo *exception)
5325 %
5326 % A description of each parameter follows:
5327 %
5328 % o image: the image.
5329 %
5330 % o nexus_info: the cache nexus to sync.
5331 %
5332 % o exception: return any errors or warnings in this structure.
5333 %
5334 */
SyncAuthenticPixelCacheNexus(Image * image,NexusInfo * magick_restrict nexus_info,ExceptionInfo * exception)5335 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5336 NexusInfo *magick_restrict nexus_info,ExceptionInfo *exception)
5337 {
5338 CacheInfo
5339 *magick_restrict cache_info;
5340
5341 MagickBooleanType
5342 status;
5343
5344 /*
5345 Transfer pixels to the cache.
5346 */
5347 assert(image != (Image *) NULL);
5348 assert(image->signature == MagickCoreSignature);
5349 if (image->cache == (Cache) NULL)
5350 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5351 cache_info=(CacheInfo *) image->cache;
5352 assert(cache_info->signature == MagickCoreSignature);
5353 if (cache_info->type == UndefinedCache)
5354 return(MagickFalse);
5355 if (image->mask_trait != UpdatePixelTrait)
5356 {
5357 if (((image->channels & WriteMaskChannel) != 0) &&
5358 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5359 return(MagickFalse);
5360 if (((image->channels & CompositeMaskChannel) != 0) &&
5361 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5362 return(MagickFalse);
5363 }
5364 if (nexus_info->authentic_pixel_cache != MagickFalse)
5365 {
5366 if (image->taint == MagickFalse)
5367 image->taint=MagickTrue;
5368 return(MagickTrue);
5369 }
5370 assert(cache_info->signature == MagickCoreSignature);
5371 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5372 if ((cache_info->metacontent_extent != 0) &&
5373 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
5374 return(MagickFalse);
5375 if ((status != MagickFalse) && (image->taint == MagickFalse))
5376 image->taint=MagickTrue;
5377 return(status);
5378 }
5379
5380 /*
5381 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5382 % %
5383 % %
5384 % %
5385 + S y n c A u t h e n t i c P i x e l C a c h e %
5386 % %
5387 % %
5388 % %
5389 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5390 %
5391 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5392 % or disk cache. The method returns MagickTrue if the pixel region is synced,
5393 % otherwise MagickFalse.
5394 %
5395 % The format of the SyncAuthenticPixelsCache() method is:
5396 %
5397 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5398 % ExceptionInfo *exception)
5399 %
5400 % A description of each parameter follows:
5401 %
5402 % o image: the image.
5403 %
5404 % o exception: return any errors or warnings in this structure.
5405 %
5406 */
SyncAuthenticPixelsCache(Image * image,ExceptionInfo * exception)5407 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5408 ExceptionInfo *exception)
5409 {
5410 CacheInfo
5411 *magick_restrict cache_info;
5412
5413 const int
5414 id = GetOpenMPThreadId();
5415
5416 MagickBooleanType
5417 status;
5418
5419 assert(image != (Image *) NULL);
5420 assert(image->signature == MagickCoreSignature);
5421 assert(image->cache != (Cache) NULL);
5422 cache_info=(CacheInfo *) image->cache;
5423 assert(cache_info->signature == MagickCoreSignature);
5424 assert(id < (int) cache_info->number_threads);
5425 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5426 exception);
5427 return(status);
5428 }
5429
5430 /*
5431 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5432 % %
5433 % %
5434 % %
5435 % S y n c A u t h e n t i c P i x e l s %
5436 % %
5437 % %
5438 % %
5439 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5440 %
5441 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5442 % The method returns MagickTrue if the pixel region is flushed, otherwise
5443 % MagickFalse.
5444 %
5445 % The format of the SyncAuthenticPixels() method is:
5446 %
5447 % MagickBooleanType SyncAuthenticPixels(Image *image,
5448 % ExceptionInfo *exception)
5449 %
5450 % A description of each parameter follows:
5451 %
5452 % o image: the image.
5453 %
5454 % o exception: return any errors or warnings in this structure.
5455 %
5456 */
SyncAuthenticPixels(Image * image,ExceptionInfo * exception)5457 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5458 ExceptionInfo *exception)
5459 {
5460 CacheInfo
5461 *magick_restrict cache_info;
5462
5463 const int
5464 id = GetOpenMPThreadId();
5465
5466 MagickBooleanType
5467 status;
5468
5469 assert(image != (Image *) NULL);
5470 assert(image->signature == MagickCoreSignature);
5471 assert(image->cache != (Cache) NULL);
5472 cache_info=(CacheInfo *) image->cache;
5473 assert(cache_info->signature == MagickCoreSignature);
5474 if (cache_info->methods.sync_authentic_pixels_handler != (SyncAuthenticPixelsHandler) NULL)
5475 {
5476 status=cache_info->methods.sync_authentic_pixels_handler(image,
5477 exception);
5478 return(status);
5479 }
5480 assert(id < (int) cache_info->number_threads);
5481 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5482 exception);
5483 return(status);
5484 }
5485
5486 /*
5487 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5488 % %
5489 % %
5490 % %
5491 + S y n c I m a g e P i x e l C a c h e %
5492 % %
5493 % %
5494 % %
5495 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5496 %
5497 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5498 % The method returns MagickTrue if the pixel region is flushed, otherwise
5499 % MagickFalse.
5500 %
5501 % The format of the SyncImagePixelCache() method is:
5502 %
5503 % MagickBooleanType SyncImagePixelCache(Image *image,
5504 % ExceptionInfo *exception)
5505 %
5506 % A description of each parameter follows:
5507 %
5508 % o image: the image.
5509 %
5510 % o exception: return any errors or warnings in this structure.
5511 %
5512 */
SyncImagePixelCache(Image * image,ExceptionInfo * exception)5513 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5514 ExceptionInfo *exception)
5515 {
5516 CacheInfo
5517 *magick_restrict cache_info;
5518
5519 assert(image != (Image *) NULL);
5520 assert(exception != (ExceptionInfo *) NULL);
5521 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5522 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5523 }
5524
5525 /*
5526 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5527 % %
5528 % %
5529 % %
5530 + 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 %
5531 % %
5532 % %
5533 % %
5534 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5535 %
5536 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5537 % of the pixel cache.
5538 %
5539 % The format of the WritePixelCacheMetacontent() method is:
5540 %
5541 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5542 % NexusInfo *nexus_info,ExceptionInfo *exception)
5543 %
5544 % A description of each parameter follows:
5545 %
5546 % o cache_info: the pixel cache.
5547 %
5548 % o nexus_info: the cache nexus to write the meta-content.
5549 %
5550 % o exception: return any errors or warnings in this structure.
5551 %
5552 */
WritePixelCacheMetacontent(CacheInfo * cache_info,NexusInfo * magick_restrict nexus_info,ExceptionInfo * exception)5553 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5554 NexusInfo *magick_restrict nexus_info,ExceptionInfo *exception)
5555 {
5556 MagickOffsetType
5557 count,
5558 offset;
5559
5560 MagickSizeType
5561 extent,
5562 length;
5563
5564 const unsigned char
5565 *magick_restrict p;
5566
5567 ssize_t
5568 y;
5569
5570 size_t
5571 rows;
5572
5573 if (cache_info->metacontent_extent == 0)
5574 return(MagickFalse);
5575 if (nexus_info->authentic_pixel_cache != MagickFalse)
5576 return(MagickTrue);
5577 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5578 nexus_info->region.x;
5579 length=(MagickSizeType) nexus_info->region.width*
5580 cache_info->metacontent_extent;
5581 extent=(MagickSizeType) length*nexus_info->region.height;
5582 rows=nexus_info->region.height;
5583 y=0;
5584 p=(unsigned char *) nexus_info->metacontent;
5585 switch (cache_info->type)
5586 {
5587 case MemoryCache:
5588 case MapCache:
5589 {
5590 unsigned char
5591 *magick_restrict q;
5592
5593 /*
5594 Write associated pixels to memory.
5595 */
5596 if ((cache_info->columns == nexus_info->region.width) &&
5597 (extent == (MagickSizeType) ((size_t) extent)))
5598 {
5599 length=extent;
5600 rows=1UL;
5601 }
5602 q=(unsigned char *) cache_info->metacontent+offset*
5603 cache_info->metacontent_extent;
5604 for (y=0; y < (ssize_t) rows; y++)
5605 {
5606 (void) memcpy(q,p,(size_t) length);
5607 p+=nexus_info->region.width*cache_info->metacontent_extent;
5608 q+=cache_info->columns*cache_info->metacontent_extent;
5609 }
5610 break;
5611 }
5612 case DiskCache:
5613 {
5614 /*
5615 Write associated pixels to disk.
5616 */
5617 LockSemaphoreInfo(cache_info->file_semaphore);
5618 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5619 {
5620 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5621 cache_info->cache_filename);
5622 UnlockSemaphoreInfo(cache_info->file_semaphore);
5623 return(MagickFalse);
5624 }
5625 if ((cache_info->columns == nexus_info->region.width) &&
5626 (extent <= MagickMaxBufferExtent))
5627 {
5628 length=extent;
5629 rows=1UL;
5630 }
5631 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5632 for (y=0; y < (ssize_t) rows; y++)
5633 {
5634 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5635 cache_info->number_channels*sizeof(Quantum)+offset*
5636 cache_info->metacontent_extent,length,(const unsigned char *) p);
5637 if (count != (MagickOffsetType) length)
5638 break;
5639 p+=cache_info->metacontent_extent*nexus_info->region.width;
5640 offset+=cache_info->columns;
5641 }
5642 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5643 (void) ClosePixelCacheOnDisk(cache_info);
5644 UnlockSemaphoreInfo(cache_info->file_semaphore);
5645 break;
5646 }
5647 case DistributedCache:
5648 {
5649 RectangleInfo
5650 region;
5651
5652 /*
5653 Write metacontent to distributed cache.
5654 */
5655 LockSemaphoreInfo(cache_info->file_semaphore);
5656 region=nexus_info->region;
5657 if ((cache_info->columns != nexus_info->region.width) ||
5658 (extent > MagickMaxBufferExtent))
5659 region.height=1UL;
5660 else
5661 {
5662 length=extent;
5663 rows=1UL;
5664 }
5665 for (y=0; y < (ssize_t) rows; y++)
5666 {
5667 count=WriteDistributePixelCacheMetacontent((DistributeCacheInfo *)
5668 cache_info->server_info,®ion,length,(const unsigned char *) p);
5669 if (count != (MagickOffsetType) length)
5670 break;
5671 p+=cache_info->metacontent_extent*nexus_info->region.width;
5672 region.y++;
5673 }
5674 UnlockSemaphoreInfo(cache_info->file_semaphore);
5675 break;
5676 }
5677 default:
5678 break;
5679 }
5680 if (y < (ssize_t) rows)
5681 {
5682 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5683 cache_info->cache_filename);
5684 return(MagickFalse);
5685 }
5686 if ((cache_info->debug != MagickFalse) &&
5687 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5688 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5689 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5690 nexus_info->region.width,(double) nexus_info->region.height,(double)
5691 nexus_info->region.x,(double) nexus_info->region.y);
5692 return(MagickTrue);
5693 }
5694
5695 /*
5696 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5697 % %
5698 % %
5699 % %
5700 + W r i t e C a c h e P i x e l s %
5701 % %
5702 % %
5703 % %
5704 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5705 %
5706 % WritePixelCachePixels() writes image pixels to the specified region of the
5707 % pixel cache.
5708 %
5709 % The format of the WritePixelCachePixels() method is:
5710 %
5711 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5712 % NexusInfo *nexus_info,ExceptionInfo *exception)
5713 %
5714 % A description of each parameter follows:
5715 %
5716 % o cache_info: the pixel cache.
5717 %
5718 % o nexus_info: the cache nexus to write the pixels.
5719 %
5720 % o exception: return any errors or warnings in this structure.
5721 %
5722 */
WritePixelCachePixels(CacheInfo * magick_restrict cache_info,NexusInfo * magick_restrict nexus_info,ExceptionInfo * exception)5723 static MagickBooleanType WritePixelCachePixels(
5724 CacheInfo *magick_restrict cache_info,NexusInfo *magick_restrict nexus_info,
5725 ExceptionInfo *exception)
5726 {
5727 MagickOffsetType
5728 count,
5729 offset;
5730
5731 MagickSizeType
5732 extent,
5733 length;
5734
5735 const Quantum
5736 *magick_restrict p;
5737
5738 ssize_t
5739 y;
5740
5741 size_t
5742 rows;
5743
5744 if (nexus_info->authentic_pixel_cache != MagickFalse)
5745 return(MagickTrue);
5746 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5747 nexus_info->region.x;
5748 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
5749 sizeof(Quantum);
5750 extent=length*nexus_info->region.height;
5751 rows=nexus_info->region.height;
5752 y=0;
5753 p=nexus_info->pixels;
5754 switch (cache_info->type)
5755 {
5756 case MemoryCache:
5757 case MapCache:
5758 {
5759 Quantum
5760 *magick_restrict q;
5761
5762 /*
5763 Write pixels to memory.
5764 */
5765 if ((cache_info->columns == nexus_info->region.width) &&
5766 (extent == (MagickSizeType) ((size_t) extent)))
5767 {
5768 length=extent;
5769 rows=1UL;
5770 }
5771 q=cache_info->pixels+cache_info->number_channels*offset;
5772 for (y=0; y < (ssize_t) rows; y++)
5773 {
5774 (void) memcpy(q,p,(size_t) length);
5775 p+=cache_info->number_channels*nexus_info->region.width;
5776 q+=cache_info->number_channels*cache_info->columns;
5777 }
5778 break;
5779 }
5780 case DiskCache:
5781 {
5782 /*
5783 Write pixels to disk.
5784 */
5785 LockSemaphoreInfo(cache_info->file_semaphore);
5786 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5787 {
5788 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5789 cache_info->cache_filename);
5790 UnlockSemaphoreInfo(cache_info->file_semaphore);
5791 return(MagickFalse);
5792 }
5793 if ((cache_info->columns == nexus_info->region.width) &&
5794 (extent <= MagickMaxBufferExtent))
5795 {
5796 length=extent;
5797 rows=1UL;
5798 }
5799 for (y=0; y < (ssize_t) rows; y++)
5800 {
5801 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5802 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5803 p);
5804 if (count != (MagickOffsetType) length)
5805 break;
5806 p+=cache_info->number_channels*nexus_info->region.width;
5807 offset+=cache_info->columns;
5808 }
5809 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5810 (void) ClosePixelCacheOnDisk(cache_info);
5811 UnlockSemaphoreInfo(cache_info->file_semaphore);
5812 break;
5813 }
5814 case DistributedCache:
5815 {
5816 RectangleInfo
5817 region;
5818
5819 /*
5820 Write pixels to distributed cache.
5821 */
5822 LockSemaphoreInfo(cache_info->file_semaphore);
5823 region=nexus_info->region;
5824 if ((cache_info->columns != nexus_info->region.width) ||
5825 (extent > MagickMaxBufferExtent))
5826 region.height=1UL;
5827 else
5828 {
5829 length=extent;
5830 rows=1UL;
5831 }
5832 for (y=0; y < (ssize_t) rows; y++)
5833 {
5834 count=WriteDistributePixelCachePixels((DistributeCacheInfo *)
5835 cache_info->server_info,®ion,length,(const unsigned char *) p);
5836 if (count != (MagickOffsetType) length)
5837 break;
5838 p+=cache_info->number_channels*nexus_info->region.width;
5839 region.y++;
5840 }
5841 UnlockSemaphoreInfo(cache_info->file_semaphore);
5842 break;
5843 }
5844 default:
5845 break;
5846 }
5847 if (y < (ssize_t) rows)
5848 {
5849 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5850 cache_info->cache_filename);
5851 return(MagickFalse);
5852 }
5853 if ((cache_info->debug != MagickFalse) &&
5854 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5855 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5856 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5857 nexus_info->region.width,(double) nexus_info->region.height,(double)
5858 nexus_info->region.x,(double) nexus_info->region.y);
5859 return(MagickTrue);
5860 }
5861