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