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