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