blob: 80b746622662a253177a7af20b393d6a55fb7484 [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% %
cristyb32b90a2009-09-07 21:45:48 +00002695+ G e t P i x e l C a c h e S t o r a g e C l a s s %
cristy3ed852e2009-09-05 21:47:34 +00002696% %
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% %
cristyb32b90a2009-09-07 21:45:48 +00002733+ G e t P i x e l C a c h e T i l e S i z e %
2734% %
2735% %
2736% %
2737%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2738%
2739% GetPixelCacheTileSize() returns the pixel cache tile size.
2740%
2741% The format of the GetPixelCacheTileSize() method is:
2742%
2743% void GetPixelCacheTileSize(const Image *image,unsigned long *width,
2744% unsigned long *height)
2745%
2746% A description of each parameter follows:
2747%
2748% o image: the image.
2749%
2750% o width: the optimize cache tile width in pixels.
2751%
2752% o height: the optimize cache tile height in pixels.
2753%
2754*/
2755MagickExport void GetPixelCacheTileSize(const Image *image,unsigned long *width,
2756 unsigned long *height)
2757{
2758 CacheInfo
2759 *cache_info;
2760
2761 assert(image != (Image *) NULL);
2762 assert(image->signature == MagickSignature);
2763 if (image->debug != MagickFalse)
2764 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2765 assert(image->cache != (Cache) NULL);
2766 cache_info=(CacheInfo *) image->cache;
2767 assert(cache_info->signature == MagickSignature);
2768 *width=2048UL/sizeof(PixelPacket);
2769 if (GetPixelCacheType(image) == DiskCache)
2770 *width=8196UL/sizeof(PixelPacket);
2771 *height=(*width);
2772}
2773
2774/*
2775%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2776% %
2777% %
2778% %
2779+ G e t P i x e l C a c h e T y p e %
2780% %
2781% %
2782% %
2783%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2784%
2785% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2786%
2787% The format of the GetPixelCacheType() method is:
2788%
2789% CacheType GetPixelCacheType(const Image *image)
2790%
2791% A description of each parameter follows:
2792%
2793% o image: the image.
2794%
2795*/
2796MagickExport CacheType GetPixelCacheType(const Image *image)
2797{
2798 CacheInfo
2799 *cache_info;
2800
2801 assert(image != (Image *) NULL);
2802 assert(image->signature == MagickSignature);
2803 if (image->debug != MagickFalse)
2804 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2805 assert(image->cache != (Cache) NULL);
2806 cache_info=(CacheInfo *) image->cache;
2807 assert(cache_info->signature == MagickSignature);
2808 return(cache_info->type);
2809}
2810
2811/*
2812%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2813% %
2814% %
2815% %
cristy3ed852e2009-09-05 21:47:34 +00002816+ 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 %
2817% %
2818% %
2819% %
2820%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2821%
2822% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2823% pixel cache. A virtual pixel is any pixel access that is outside the
2824% boundaries of the image cache.
2825%
2826% The format of the GetPixelCacheVirtualMethod() method is:
2827%
2828% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2829%
2830% A description of each parameter follows:
2831%
2832% o image: the image.
2833%
2834*/
2835MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2836{
2837 CacheInfo
2838 *cache_info;
2839
2840 assert(image != (Image *) NULL);
2841 assert(image->signature == MagickSignature);
2842 if (image->debug != MagickFalse)
2843 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2844 assert(image->cache != (Cache) NULL);
2845 cache_info=(CacheInfo *) image->cache;
2846 assert(cache_info->signature == MagickSignature);
2847 return(cache_info->virtual_pixel_method);
2848}
2849
2850/*
2851%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2852% %
2853% %
2854% %
2855+ 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 %
2856% %
2857% %
2858% %
2859%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2860%
2861% GetVirtualIndexesFromCache() returns the indexes associated with the last
2862% call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2863%
2864% The format of the GetVirtualIndexesFromCache() method is:
2865%
2866% IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2867%
2868% A description of each parameter follows:
2869%
2870% o image: the image.
2871%
2872*/
2873static const IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2874{
2875 CacheInfo
2876 *cache_info;
2877
2878 const IndexPacket
2879 *indexes;
2880
2881 long
2882 id;
2883
2884 if (image->debug != MagickFalse)
2885 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2886 cache_info=(CacheInfo *) image->cache;
2887 id=GetOpenMPThreadId();
2888 assert(id < (long) cache_info->number_threads);
2889 indexes=GetVirtualIndexesFromNexus(image->cache,cache_info->nexus_info[id]);
2890 return(indexes);
2891}
2892
2893/*
2894%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2895% %
2896% %
2897% %
2898+ 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 %
2899% %
2900% %
2901% %
2902%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2903%
2904% GetVirtualIndexesFromNexus() returns the indexes associated with the
2905% specified cache nexus.
2906%
2907% The format of the GetVirtualIndexesFromNexus() method is:
2908%
2909% const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2910% NexusInfo *nexus_info)
2911%
2912% A description of each parameter follows:
2913%
2914% o cache: the pixel cache.
2915%
2916% o nexus_info: the cache nexus to return the colormap indexes.
2917%
2918*/
2919MagickExport const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2920 NexusInfo *nexus_info)
2921{
2922 CacheInfo
2923 *cache_info;
2924
2925 if (cache == (Cache) NULL)
2926 return((IndexPacket *) NULL);
2927 cache_info=(CacheInfo *) cache;
2928 assert(cache_info->signature == MagickSignature);
2929 if (cache_info->storage_class == UndefinedClass)
2930 return((IndexPacket *) NULL);
2931 return(nexus_info->indexes);
2932}
2933
2934/*
2935%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2936% %
2937% %
2938% %
2939% G e t V i r t u a l I n d e x Q u e u e %
2940% %
2941% %
2942% %
2943%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2944%
2945% GetVirtualIndexQueue() returns the virtual black channel or the
2946% colormap indexes associated with the last call to QueueAuthenticPixels() or
2947% GetVirtualPixels(). NULL is returned if the black channel or colormap
2948% indexes are not available.
2949%
2950% The format of the GetVirtualIndexQueue() method is:
2951%
2952% const IndexPacket *GetVirtualIndexQueue(const Image *image)
2953%
2954% A description of each parameter follows:
2955%
2956% o image: the image.
2957%
2958*/
2959MagickExport const IndexPacket *GetVirtualIndexQueue(const Image *image)
2960{
2961 CacheInfo
2962 *cache_info;
2963
2964 assert(image != (const Image *) NULL);
2965 assert(image->signature == MagickSignature);
2966 if (image->debug != MagickFalse)
2967 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2968 assert(image->cache != (Cache) NULL);
2969 cache_info=(CacheInfo *) image->cache;
2970 assert(cache_info->signature == MagickSignature);
2971 if (cache_info->methods.get_virtual_indexes_from_handler ==
2972 (GetVirtualIndexesFromHandler) NULL)
2973 return((IndexPacket *) NULL);
2974 return(cache_info->methods.get_virtual_indexes_from_handler(image));
2975}
2976
2977/*
2978%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2979% %
2980% %
2981% %
2982+ 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 %
2983% %
2984% %
2985% %
2986%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2987%
2988% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2989% pixel cache as defined by the geometry parameters. A pointer to the pixels
2990% is returned if the pixels are transferred, otherwise a NULL is returned.
2991%
2992% The format of the GetVirtualPixelsFromNexus() method is:
2993%
2994% PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
2995% const VirtualPixelMethod method,const long x,const long y,
2996% const unsigned long columns,const unsigned long rows,
2997% NexusInfo *nexus_info,ExceptionInfo *exception)
2998%
2999% A description of each parameter follows:
3000%
3001% o image: the image.
3002%
3003% o virtual_pixel_method: the virtual pixel method.
3004%
3005% o x,y,columns,rows: These values define the perimeter of a region of
3006% pixels.
3007%
3008% o nexus_info: the cache nexus to acquire.
3009%
3010% o exception: return any errors or warnings in this structure.
3011%
3012*/
3013
3014static long
3015 DitherMatrix[64] =
3016 {
3017 0, 48, 12, 60, 3, 51, 15, 63,
3018 32, 16, 44, 28, 35, 19, 47, 31,
3019 8, 56, 4, 52, 11, 59, 7, 55,
3020 40, 24, 36, 20, 43, 27, 39, 23,
3021 2, 50, 14, 62, 1, 49, 13, 61,
3022 34, 18, 46, 30, 33, 17, 45, 29,
3023 10, 58, 6, 54, 9, 57, 5, 53,
3024 42, 26, 38, 22, 41, 25, 37, 21
3025 };
3026
3027static inline long DitherX(const unsigned long columns,const long x)
3028{
3029 long
3030 index;
3031
3032 index=x+DitherMatrix[x & 0x07]-32L;
3033 if (index < 0L)
3034 return(0L);
3035 if (index >= (long) columns)
3036 return((long) columns-1L);
3037 return(index);
3038}
3039
3040static inline long DitherY(const unsigned long rows,const long y)
3041{
3042 long
3043 index;
3044
3045 index=y+DitherMatrix[y & 0x07]-32L;
3046 if (index < 0L)
3047 return(0L);
3048 if (index >= (long) rows)
3049 return((long) rows-1L);
3050 return(index);
3051}
3052
3053static inline long EdgeX(const unsigned long columns,const long x)
3054{
3055 if (x < 0L)
3056 return(0L);
3057 if (x >= (long) columns)
3058 return((long) columns-1L);
3059 return(x);
3060}
3061
3062static inline long EdgeY(const unsigned long rows,const long y)
3063{
3064 if (y < 0L)
3065 return(0L);
3066 if (y >= (long) rows)
3067 return((long) rows-1L);
3068 return(y);
3069}
3070
3071static inline long RandomX(const unsigned long columns,RandomInfo *random_info)
3072{
3073 return((long) (columns*GetPseudoRandomValue(random_info)));
3074}
3075
3076static inline long RandomY(const unsigned long rows,RandomInfo *random_info)
3077{
3078 return((long) (rows*GetPseudoRandomValue(random_info)));
3079}
3080
3081/*
3082 VirtualPixelModulo() computes the remainder of dividing offset by extent. It
3083 returns not only the quotient (tile the offset falls in) but also the positive
3084 remainer within that tile such that 0 <= remainder < extent. This method is
3085 essentially a ldiv() using a floored modulo division rather than the normal
3086 default truncated modulo division.
3087*/
3088static inline MagickModulo VirtualPixelModulo(const long offset,
3089 const unsigned long extent)
3090{
3091 MagickModulo
3092 modulo;
3093
3094 modulo.quotient=offset/(long) extent;
3095 if (offset < 0L)
3096 modulo.quotient--;
3097 modulo.remainder=offset-modulo.quotient*(long) extent;
3098 return(modulo);
3099}
3100
3101MagickExport const PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
3102 const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
3103 const unsigned long columns,const unsigned long rows,NexusInfo *nexus_info,
3104 ExceptionInfo *exception)
3105{
3106 CacheInfo
3107 *cache_info;
3108
3109 MagickOffsetType
3110 offset;
3111
3112 MagickSizeType
3113 length,
3114 number_pixels;
3115
3116 NexusInfo
3117 **virtual_nexus;
3118
3119 PixelPacket
3120 *pixels,
3121 virtual_pixel;
3122
3123 RectangleInfo
3124 region;
3125
3126 register const IndexPacket
3127 *__restrict nexus_indexes;
3128
3129 register const PixelPacket
3130 *__restrict p;
3131
3132 register IndexPacket
3133 *__restrict indexes;
3134
3135 register long
3136 u,
3137 v;
3138
3139 register PixelPacket
3140 *__restrict q;
3141
3142 /*
3143 Acquire pixels.
3144 */
3145 if (image->debug != MagickFalse)
3146 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3147 cache_info=(CacheInfo *) image->cache;
3148 if (cache_info->type == UndefinedCache)
3149 return((const PixelPacket *) NULL);
3150 region.x=x;
3151 region.y=y;
3152 region.width=columns;
3153 region.height=rows;
3154 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
3155 if (pixels == (PixelPacket *) NULL)
3156 return((const PixelPacket *) NULL);
3157 offset=(MagickOffsetType) region.y*cache_info->columns+region.x;
3158 length=(MagickSizeType) (region.height-1)*cache_info->columns+region.width-1;
3159 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3160 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
3161 if ((x >= 0) && ((long) (x+columns) <= (long) cache_info->columns) &&
3162 (y >= 0) && ((long) (y+rows) <= (long) cache_info->rows))
3163 {
3164 MagickBooleanType
3165 status;
3166
3167 /*
3168 Pixel request is inside cache extents.
3169 */
3170 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
3171 return(pixels);
3172 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3173 if (status == MagickFalse)
3174 return((const PixelPacket *) NULL);
3175 if ((cache_info->storage_class == PseudoClass) ||
3176 (cache_info->colorspace == CMYKColorspace))
3177 {
3178 status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
3179 if (status == MagickFalse)
3180 return((const PixelPacket *) NULL);
3181 }
3182 return(pixels);
3183 }
3184 /*
3185 Pixel request is outside cache extents.
3186 */
3187 q=pixels;
3188 indexes=GetPixelCacheNexusIndexes(cache_info,nexus_info);
3189 virtual_nexus=AcquirePixelCacheNexus(1);
3190 if (virtual_nexus == (NexusInfo **) NULL)
3191 {
3192 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3193 "UnableToGetCacheNexus","`%s'",image->filename);
3194 return((const PixelPacket *) NULL);
3195 }
3196 switch (virtual_pixel_method)
3197 {
3198 case BlackVirtualPixelMethod:
3199 {
3200 virtual_pixel.red=0;
3201 virtual_pixel.green=0;
3202 virtual_pixel.blue=0;
3203 virtual_pixel.opacity=OpaqueOpacity;
3204 break;
3205 }
3206 case GrayVirtualPixelMethod:
3207 {
3208 virtual_pixel.red=(Quantum) QuantumRange/2;
3209 virtual_pixel.green=(Quantum) QuantumRange/2;
3210 virtual_pixel.blue=(Quantum) QuantumRange/2;
3211 virtual_pixel.opacity=(Quantum) OpaqueOpacity;
3212 break;
3213 }
3214 case TransparentVirtualPixelMethod:
3215 {
3216 virtual_pixel.red=(Quantum) 0;
3217 virtual_pixel.green=(Quantum) 0;
3218 virtual_pixel.blue=(Quantum) 0;
3219 virtual_pixel.opacity=(Quantum) TransparentOpacity;
3220 break;
3221 }
3222 case MaskVirtualPixelMethod:
3223 case WhiteVirtualPixelMethod:
3224 {
3225 virtual_pixel.red=(Quantum) QuantumRange;
3226 virtual_pixel.green=(Quantum) QuantumRange;
3227 virtual_pixel.blue=(Quantum) QuantumRange;
3228 virtual_pixel.opacity=OpaqueOpacity;
3229 break;
3230 }
3231 default:
3232 {
3233 virtual_pixel=image->background_color;
3234 break;
3235 }
3236 }
3237 for (v=0; v < (long) rows; v++)
3238 {
3239 for (u=0; u < (long) columns; u+=length)
3240 {
3241 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
3242 if ((((x+u) < 0) || ((x+u) >= (long) cache_info->columns)) ||
3243 (((y+v) < 0) || ((y+v) >= (long) cache_info->rows)) || (length == 0))
3244 {
3245 MagickModulo
3246 x_modulo,
3247 y_modulo;
3248
3249 /*
3250 Transfer a single pixel.
3251 */
3252 length=(MagickSizeType) 1;
3253 switch (virtual_pixel_method)
3254 {
3255 case BackgroundVirtualPixelMethod:
3256 case ConstantVirtualPixelMethod:
3257 case BlackVirtualPixelMethod:
3258 case GrayVirtualPixelMethod:
3259 case TransparentVirtualPixelMethod:
3260 case MaskVirtualPixelMethod:
3261 case WhiteVirtualPixelMethod:
3262 {
3263 p=(&virtual_pixel);
3264 break;
3265 }
3266 case EdgeVirtualPixelMethod:
3267 default:
3268 {
3269 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3270 EdgeX(cache_info->columns,x+u),EdgeY(cache_info->rows,y+v),
3271 1UL,1UL,virtual_nexus[0],exception);
3272 break;
3273 }
3274 case RandomVirtualPixelMethod:
3275 {
3276 if (cache_info->random_info == (RandomInfo *) NULL)
3277 cache_info->random_info=AcquireRandomInfo();
3278 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3279 RandomX(cache_info->columns,cache_info->random_info),
3280 RandomY(cache_info->rows,cache_info->random_info),1UL,1UL,
3281 virtual_nexus[0],exception);
3282 break;
3283 }
3284 case DitherVirtualPixelMethod:
3285 {
3286 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3287 DitherX(cache_info->columns,x+u),DitherY(cache_info->rows,y+v),
3288 1UL,1UL,virtual_nexus[0],exception);
3289 break;
3290 }
3291 case TileVirtualPixelMethod:
3292 {
3293 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3294 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3295 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3296 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3297 exception);
3298 break;
3299 }
3300 case MirrorVirtualPixelMethod:
3301 {
3302 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3303 if ((x_modulo.quotient & 0x01) == 1L)
3304 x_modulo.remainder=(long) cache_info->columns-
3305 x_modulo.remainder-1L;
3306 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3307 if ((y_modulo.quotient & 0x01) == 1L)
3308 y_modulo.remainder=(long) cache_info->rows-
3309 y_modulo.remainder-1L;
3310 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3311 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3312 exception);
3313 break;
3314 }
3315 case CheckerTileVirtualPixelMethod:
3316 {
3317 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3318 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3319 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3320 {
3321 p=(&virtual_pixel);
3322 break;
3323 }
3324 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3325 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3326 exception);
3327 break;
3328 }
3329 case HorizontalTileVirtualPixelMethod:
3330 {
3331 if (((y+v) < 0) || ((y+v) >= (long) cache_info->rows))
3332 {
3333 p=(&virtual_pixel);
3334 break;
3335 }
3336 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3337 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3338 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3339 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3340 exception);
3341 break;
3342 }
3343 case VerticalTileVirtualPixelMethod:
3344 {
3345 if (((x+u) < 0) || ((x+u) >= (long) cache_info->columns))
3346 {
3347 p=(&virtual_pixel);
3348 break;
3349 }
3350 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3351 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3352 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3353 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3354 exception);
3355 break;
3356 }
3357 case HorizontalTileEdgeVirtualPixelMethod:
3358 {
3359 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3360 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3361 x_modulo.remainder,EdgeY(cache_info->rows,y+v),1UL,1UL,
3362 virtual_nexus[0],exception);
3363 break;
3364 }
3365 case VerticalTileEdgeVirtualPixelMethod:
3366 {
3367 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3368 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3369 EdgeX(cache_info->columns,x+u),y_modulo.remainder,1UL,1UL,
3370 virtual_nexus[0],exception);
3371 break;
3372 }
3373 }
3374 if (p == (const PixelPacket *) NULL)
3375 break;
3376 *q++=(*p);
3377 if (indexes != (IndexPacket *) NULL)
3378 {
3379 nexus_indexes=GetVirtualIndexesFromNexus(cache_info,
3380 virtual_nexus[0]);
3381 if (nexus_indexes != (const IndexPacket *) NULL)
3382 *indexes++=(*nexus_indexes);
3383 }
3384 continue;
3385 }
3386 /*
3387 Transfer a run of pixels.
3388 */
3389 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,
3390 (unsigned long) length,1UL,virtual_nexus[0],exception);
3391 if (p == (const PixelPacket *) NULL)
3392 break;
3393 (void) CopyMagickMemory(q,p,(size_t) length*sizeof(*p));
3394 q+=length;
3395 if (indexes != (IndexPacket *) NULL)
3396 {
3397 nexus_indexes=GetVirtualIndexesFromNexus(cache_info,virtual_nexus[0]);
3398 if (nexus_indexes != (const IndexPacket *) NULL)
3399 {
3400 (void) CopyMagickMemory(indexes,nexus_indexes,(size_t) length*
3401 sizeof(*nexus_indexes));
3402 indexes+=length;
3403 }
3404 }
3405 }
3406 }
3407 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3408 return(pixels);
3409}
3410
3411/*
3412%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3413% %
3414% %
3415% %
3416+ G e t V i r t u a l P i x e l C a c h e %
3417% %
3418% %
3419% %
3420%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3421%
3422% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3423% cache as defined by the geometry parameters. A pointer to the pixels
3424% is returned if the pixels are transferred, otherwise a NULL is returned.
3425%
3426% The format of the GetVirtualPixelCache() method is:
3427%
3428% const PixelPacket *GetVirtualPixelCache(const Image *image,
3429% const VirtualPixelMethod virtual_pixel_method,const long x,
3430% const long y,const unsigned long columns,const unsigned long rows,
3431% ExceptionInfo *exception)
3432%
3433% A description of each parameter follows:
3434%
3435% o image: the image.
3436%
3437% o virtual_pixel_method: the virtual pixel method.
3438%
3439% o x,y,columns,rows: These values define the perimeter of a region of
3440% pixels.
3441%
3442% o exception: return any errors or warnings in this structure.
3443%
3444*/
3445static const PixelPacket *GetVirtualPixelCache(const Image *image,
3446 const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
3447 const unsigned long columns,const unsigned long rows,ExceptionInfo *exception)
3448{
3449 CacheInfo
3450 *cache_info;
3451
3452 const PixelPacket
3453 *pixels;
3454
3455 long
3456 id;
3457
3458 if (image->debug != MagickFalse)
3459 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3460 cache_info=(CacheInfo *) image->cache;
3461 id=GetOpenMPThreadId();
3462 assert(id < (long) cache_info->number_threads);
3463 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3464 cache_info->nexus_info[id],exception);
3465 return(pixels);
3466}
3467
3468/*
3469%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3470% %
3471% %
3472% %
3473% G e t V i r t u a l P i x e l Q u e u e %
3474% %
3475% %
3476% %
3477%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3478%
3479% GetVirtualPixelQueue() returns the virtual pixels associated with the
3480% last call to QueueAuthenticPixels() or GetVirtualPixels().
3481%
3482% The format of the GetVirtualPixelQueue() method is:
3483%
3484% const PixelPacket *GetVirtualPixelQueue(const Image image)
3485%
3486% A description of each parameter follows:
3487%
3488% o image: the image.
3489%
3490*/
3491MagickExport const PixelPacket *GetVirtualPixelQueue(const Image *image)
3492{
3493 CacheInfo
3494 *cache_info;
3495
3496 assert(image != (const Image *) NULL);
3497 assert(image->signature == MagickSignature);
3498 if (image->debug != MagickFalse)
3499 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3500 assert(image->cache != (Cache) NULL);
3501 cache_info=(CacheInfo *) image->cache;
3502 assert(cache_info->signature == MagickSignature);
3503 if (cache_info->methods.get_virtual_pixels_handler ==
3504 (GetVirtualPixelsHandler) NULL)
3505 return((PixelPacket *) NULL);
3506 return(cache_info->methods.get_virtual_pixels_handler(image));
3507}
3508
3509/*
3510%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3511% %
3512% %
3513% %
3514% G e t V i r t u a l P i x e l s %
3515% %
3516% %
3517% %
3518%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3519%
3520% GetVirtualPixels() returns an immutable pixel region. If the
3521% region is successfully accessed, a pointer to it is returned, otherwise
3522% NULL is returned. The returned pointer may point to a temporary working
3523% copy of the pixels or it may point to the original pixels in memory.
3524% Performance is maximized if the selected region is part of one row, or one
3525% or more full rows, since there is opportunity to access the pixels in-place
3526% (without a copy) if the image is in RAM, or in a memory-mapped file. The
3527% returned pointer should *never* be deallocated by the user.
3528%
3529% Pixels accessed via the returned pointer represent a simple array of type
3530% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
3531% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access
3532% the black color component or to obtain the colormap indexes (of type
3533% IndexPacket) corresponding to the region.
3534%
3535% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3536%
3537% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3538% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3539% GetCacheViewAuthenticPixels() instead.
3540%
3541% The format of the GetVirtualPixels() method is:
3542%
3543% const PixelPacket *GetVirtualPixels(const Image *image,const long x,
3544% const long y,const unsigned long columns,const unsigned long rows,
3545% ExceptionInfo *exception)
3546%
3547% A description of each parameter follows:
3548%
3549% o image: the image.
3550%
3551% o x,y,columns,rows: These values define the perimeter of a region of
3552% pixels.
3553%
3554% o exception: return any errors or warnings in this structure.
3555%
3556*/
3557MagickExport const PixelPacket *GetVirtualPixels(const Image *image,
3558 const long x,const long y,const unsigned long columns,
3559 const unsigned long rows,ExceptionInfo *exception)
3560{
3561 CacheInfo
3562 *cache_info;
3563
3564 const PixelPacket
3565 *pixels;
3566
3567 assert(image != (const Image *) NULL);
3568 assert(image->signature == MagickSignature);
3569 if (image->debug != MagickFalse)
3570 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3571 assert(image->cache != (Cache) NULL);
3572 cache_info=(CacheInfo *) image->cache;
3573 assert(cache_info->signature == MagickSignature);
3574 if (cache_info->methods.get_virtual_pixel_handler ==
3575 (GetVirtualPixelHandler) NULL)
3576 return((const PixelPacket *) NULL);
3577 pixels=cache_info->methods.get_virtual_pixel_handler(image,
3578 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception);
3579 return(pixels);
3580}
3581
3582/*
3583%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3584% %
3585% %
3586% %
3587+ 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 %
3588% %
3589% %
3590% %
3591%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3592%
3593% GetVirtualPixelsCache() returns the pixels associated with the last call
3594% to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3595%
3596% The format of the GetVirtualPixelsCache() method is:
3597%
3598% PixelPacket *GetVirtualPixelsCache(const Image *image)
3599%
3600% A description of each parameter follows:
3601%
3602% o image: the image.
3603%
3604*/
3605static const PixelPacket *GetVirtualPixelsCache(const Image *image)
3606{
3607 CacheInfo
3608 *cache_info;
3609
3610 const PixelPacket
3611 *pixels;
3612
3613 long
3614 id;
3615
3616 if (image->debug != MagickFalse)
3617 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3618 cache_info=(CacheInfo *) image->cache;
3619 id=GetOpenMPThreadId();
3620 assert(id < (long) cache_info->number_threads);
3621 pixels=GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]);
3622 return(pixels);
3623}
3624
3625/*
3626%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3627% %
3628% %
3629% %
3630+ G e t V i r t u a l P i x e l s N e x u s %
3631% %
3632% %
3633% %
3634%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3635%
3636% GetVirtualPixelsNexus() returns the pixels associated with the specified
3637% cache nexus.
3638%
3639% The format of the GetVirtualPixelsNexus() method is:
3640%
3641% const IndexPacket *GetVirtualPixelsNexus(const Cache cache,
3642% NexusInfo *nexus_info)
3643%
3644% A description of each parameter follows:
3645%
3646% o cache: the pixel cache.
3647%
3648% o nexus_info: the cache nexus to return the colormap pixels.
3649%
3650*/
3651MagickExport const PixelPacket *GetVirtualPixelsNexus(const Cache cache,
3652 NexusInfo *nexus_info)
3653{
3654 CacheInfo
3655 *cache_info;
3656
3657 if (cache == (Cache) NULL)
3658 return((PixelPacket *) NULL);
3659 cache_info=(CacheInfo *) cache;
3660 assert(cache_info->signature == MagickSignature);
3661 if (cache_info->storage_class == UndefinedClass)
3662 return((PixelPacket *) NULL);
3663 return((const PixelPacket *) nexus_info->pixels);
3664}
3665
3666/*
3667%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3668% %
3669% %
3670% %
3671+ M a s k P i x e l C a c h e N e x u s %
3672% %
3673% %
3674% %
3675%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3676%
3677% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3678% The method returns MagickTrue if the pixel region is masked, otherwise
3679% MagickFalse.
3680%
3681% The format of the MaskPixelCacheNexus() method is:
3682%
3683% MagickBooleanType MaskPixelCacheNexus(Image *image,
3684% NexusInfo *nexus_info,ExceptionInfo *exception)
3685%
3686% A description of each parameter follows:
3687%
3688% o image: the image.
3689%
3690% o nexus_info: the cache nexus to clip.
3691%
3692% o exception: return any errors or warnings in this structure.
3693%
3694*/
3695
3696static inline void MagickPixelCompositeMask(const MagickPixelPacket *p,
3697 const MagickRealType alpha,const MagickPixelPacket *q,
3698 const MagickRealType beta,MagickPixelPacket *composite)
3699{
3700 MagickRealType
3701 gamma;
3702
3703 if (alpha == TransparentOpacity)
3704 {
3705 *composite=(*q);
3706 return;
3707 }
3708 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3709 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3710 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3711 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3712 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3713 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3714 composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
3715}
3716
3717static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3718 ExceptionInfo *exception)
3719{
3720 CacheInfo
3721 *cache_info;
3722
3723 MagickPixelPacket
3724 alpha,
3725 beta;
3726
3727 MagickSizeType
3728 number_pixels;
3729
3730 NexusInfo
3731 **clip_nexus,
3732 **image_nexus;
3733
3734 register const PixelPacket
3735 *__restrict r;
3736
3737 register IndexPacket
3738 *__restrict nexus_indexes,
3739 *__restrict indexes;
3740
3741 register long
3742 i;
3743
3744 register PixelPacket
3745 *__restrict p,
3746 *__restrict q;
3747
3748 /*
3749 Apply clip mask.
3750 */
3751 if (image->debug != MagickFalse)
3752 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3753 if (image->mask == (Image *) NULL)
3754 return(MagickFalse);
3755 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
3756 if (cache_info == (Cache) NULL)
3757 return(MagickFalse);
3758 image_nexus=AcquirePixelCacheNexus(1);
3759 clip_nexus=AcquirePixelCacheNexus(1);
3760 if ((image_nexus == (NexusInfo **) NULL) ||
3761 (clip_nexus == (NexusInfo **) NULL))
3762 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
3763 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,nexus_info->region.y,
3764 nexus_info->region.width,nexus_info->region.height,image_nexus[0],
3765 exception);
3766 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
3767 q=nexus_info->pixels;
3768 nexus_indexes=nexus_info->indexes;
3769 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3770 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3771 nexus_info->region.height,clip_nexus[0],&image->exception);
3772 GetMagickPixelPacket(image,&alpha);
3773 GetMagickPixelPacket(image,&beta);
3774 number_pixels=(MagickSizeType) nexus_info->region.width*
3775 nexus_info->region.height;
3776 for (i=0; i < (long) number_pixels; i++)
3777 {
3778 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
3779 break;
3780 SetMagickPixelPacket(image,p,indexes+i,&alpha);
3781 SetMagickPixelPacket(image,q,nexus_indexes+i,&beta);
3782 MagickPixelCompositeMask(&beta,(MagickRealType) PixelIntensityToQuantum(r),
3783 &alpha,alpha.opacity,&beta);
3784 q->red=RoundToQuantum(beta.red);
3785 q->green=RoundToQuantum(beta.green);
3786 q->blue=RoundToQuantum(beta.blue);
3787 q->opacity=RoundToQuantum(beta.opacity);
3788 if (cache_info->active_index_channel != MagickFalse)
3789 nexus_indexes[i]=indexes[i];
3790 p++;
3791 q++;
3792 r++;
3793 }
3794 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3795 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
3796 if (i < (long) number_pixels)
3797 return(MagickFalse);
3798 return(MagickTrue);
3799}
3800
3801/*
3802%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3803% %
3804% %
3805% %
3806+ O p e n P i x e l C a c h e %
3807% %
3808% %
3809% %
3810%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3811%
3812% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3813% dimensions, allocating space for the image pixels and optionally the
3814% colormap indexes, and memory mapping the cache if it is disk based. The
3815% cache nexus array is initialized as well.
3816%
3817% The format of the OpenPixelCache() method is:
3818%
3819% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3820% ExceptionInfo *exception)
3821%
3822% A description of each parameter follows:
3823%
3824% o image: the image.
3825%
3826% o mode: ReadMode, WriteMode, or IOMode.
3827%
3828% o exception: return any errors or warnings in this structure.
3829%
3830*/
3831
3832static inline void AcquirePixelCachePixels(CacheInfo *cache_info)
3833{
3834 cache_info->mapped=MagickFalse;
3835 cache_info->pixels=(PixelPacket *) AcquireMagickMemory((size_t)
3836 cache_info->length);
3837 if (cache_info->pixels == (PixelPacket *) NULL)
3838 {
3839 cache_info->mapped=MagickTrue;
3840 cache_info->pixels=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
3841 cache_info->length);
3842 }
3843}
3844
3845static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3846{
3847 CacheInfo
3848 *cache_info;
3849
3850 MagickOffsetType
3851 count,
3852 extent,
3853 offset;
3854
3855 cache_info=(CacheInfo *) image->cache;
3856 if (image->debug != MagickFalse)
3857 {
3858 char
3859 format[MaxTextExtent],
3860 message[MaxTextExtent];
3861
3862 (void) FormatMagickSize(length,format);
3863 (void) FormatMagickString(message,MaxTextExtent,
3864 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3865 cache_info->cache_filename,cache_info->file,format);
3866 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3867 }
3868 if (length != (MagickSizeType) ((MagickOffsetType) length))
3869 return(MagickFalse);
3870 extent=(MagickOffsetType) MagickSeek(cache_info->file,0,SEEK_END);
3871 if (extent < 0)
3872 return(MagickFalse);
3873 if ((MagickSizeType) extent >= length)
3874 return(MagickTrue);
3875 offset=(MagickOffsetType) length-1;
3876 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3877 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3878}
3879
3880static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3881 ExceptionInfo *exception)
3882{
3883 char
3884 format[MaxTextExtent],
3885 message[MaxTextExtent];
3886
3887 CacheInfo
3888 *cache_info,
3889 source_info;
3890
3891 MagickSizeType
3892 length,
3893 number_pixels;
3894
3895 MagickStatusType
3896 status;
3897
3898 size_t
3899 packet_size;
3900
3901 unsigned long
3902 columns;
3903
3904 if (image->debug != MagickFalse)
3905 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3906 if ((image->columns == 0) || (image->rows == 0))
3907 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3908 cache_info=(CacheInfo *) image->cache;
3909 source_info=(*cache_info);
3910 source_info.file=(-1);
3911 (void) FormatMagickString(cache_info->filename,MaxTextExtent,"%s[%ld]",
3912 image->filename,GetImageIndexInList(image));
3913 cache_info->rows=image->rows;
3914 cache_info->columns=image->columns;
3915 cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
3916 (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
3917 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3918 packet_size=sizeof(PixelPacket);
3919 if (cache_info->active_index_channel != MagickFalse)
3920 packet_size+=sizeof(IndexPacket);
3921 length=number_pixels*packet_size;
3922 columns=(unsigned long) (length/cache_info->rows/packet_size);
3923 if (cache_info->columns != columns)
3924 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3925 image->filename);
3926 cache_info->length=length;
3927 status=AcquireMagickResource(AreaResource,cache_info->length);
3928 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
3929 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3930 {
3931 status=AcquireMagickResource(MemoryResource,cache_info->length);
3932 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3933 (cache_info->type == MemoryCache))
3934 {
3935 AcquirePixelCachePixels(cache_info);
3936 if (cache_info->pixels == (PixelPacket *) NULL)
3937 cache_info->pixels=source_info.pixels;
3938 else
3939 {
3940 /*
3941 Create memory pixel cache.
3942 */
3943 if (image->debug != MagickFalse)
3944 {
3945 (void) FormatMagickSize(cache_info->length,format);
3946 (void) FormatMagickString(message,MaxTextExtent,
3947 "open %s (%s memory, %lux%lu %s)",cache_info->filename,
3948 cache_info->mapped != MagickFalse ? "anonymous" : "heap",
3949 cache_info->columns,cache_info->rows,format);
3950 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3951 message);
3952 }
3953 cache_info->storage_class=image->storage_class;
3954 cache_info->colorspace=image->colorspace;
3955 cache_info->type=MemoryCache;
3956 cache_info->indexes=(IndexPacket *) NULL;
3957 if (cache_info->active_index_channel != MagickFalse)
3958 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
3959 number_pixels);
3960 if (source_info.storage_class != UndefinedClass)
3961 {
3962 status|=ClonePixelCachePixels(cache_info,&source_info,
3963 exception);
3964 RelinquishPixelCachePixels(&source_info);
3965 }
3966 return(MagickTrue);
3967 }
3968 }
3969 RelinquishMagickResource(MemoryResource,cache_info->length);
3970 }
3971 /*
3972 Create pixel cache on disk.
3973 */
3974 status=AcquireMagickResource(DiskResource,cache_info->length);
3975 if (status == MagickFalse)
3976 {
3977 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3978 "CacheResourcesExhausted","`%s'",image->filename);
3979 return(MagickFalse);
3980 }
3981 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3982 {
3983 RelinquishMagickResource(DiskResource,cache_info->length);
3984 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3985 image->filename);
3986 return(MagickFalse);
3987 }
3988 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
3989 cache_info->length);
3990 if (status == MagickFalse)
3991 {
3992 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3993 image->filename);
3994 return(MagickFalse);
3995 }
3996 cache_info->storage_class=image->storage_class;
3997 cache_info->colorspace=image->colorspace;
3998 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
3999 status=AcquireMagickResource(AreaResource,cache_info->length);
4000 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4001 cache_info->type=DiskCache;
4002 else
4003 {
4004 status=AcquireMagickResource(MapResource,cache_info->length);
4005 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4006 (cache_info->type != MemoryCache))
4007 cache_info->type=DiskCache;
4008 else
4009 {
4010 cache_info->pixels=(PixelPacket *) MapBlob(cache_info->file,mode,
4011 cache_info->offset,(size_t) cache_info->length);
4012 if (cache_info->pixels == (PixelPacket *) NULL)
4013 {
4014 cache_info->pixels=source_info.pixels;
4015 cache_info->type=DiskCache;
4016 }
4017 else
4018 {
4019 /*
4020 Create file-backed memory-mapped pixel cache.
4021 */
4022 (void) ClosePixelCacheOnDisk(cache_info);
4023 cache_info->type=MapCache;
4024 cache_info->mapped=MagickTrue;
4025 cache_info->indexes=(IndexPacket *) NULL;
4026 if (cache_info->active_index_channel != MagickFalse)
4027 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4028 number_pixels);
4029 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4030 {
4031 status=ClonePixelCachePixels(cache_info,&source_info,
4032 exception);
4033 RelinquishPixelCachePixels(&source_info);
4034 }
4035 if (image->debug != MagickFalse)
4036 {
4037 (void) FormatMagickSize(cache_info->length,format);
4038 (void) FormatMagickString(message,MaxTextExtent,
4039 "open %s (%s[%d], memory-mapped, %lux%lu %s)",
4040 cache_info->filename,cache_info->cache_filename,
4041 cache_info->file,cache_info->columns,cache_info->rows,
4042 format);
4043 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4044 message);
4045 }
4046 return(MagickTrue);
4047 }
4048 }
4049 RelinquishMagickResource(MapResource,cache_info->length);
4050 }
4051 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4052 {
4053 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4054 RelinquishPixelCachePixels(&source_info);
4055 }
4056 if (image->debug != MagickFalse)
4057 {
4058 (void) FormatMagickSize(cache_info->length,format);
4059 (void) FormatMagickString(message,MaxTextExtent,
4060 "open %s (%s[%d], disk, %lux%lu %s)",cache_info->filename,
4061 cache_info->cache_filename,cache_info->file,cache_info->columns,
4062 cache_info->rows,format);
4063 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4064 }
4065 return(MagickTrue);
4066}
4067
4068/*
4069%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4070% %
4071% %
4072% %
4073+ P e r s i s t P i x e l C a c h e %
4074% %
4075% %
4076% %
4077%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4078%
4079% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4080% persistent pixel cache is one that resides on disk and is not destroyed
4081% when the program exits.
4082%
4083% The format of the PersistPixelCache() method is:
4084%
4085% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4086% const MagickBooleanType attach,MagickOffsetType *offset,
4087% ExceptionInfo *exception)
4088%
4089% A description of each parameter follows:
4090%
4091% o image: the image.
4092%
4093% o filename: the persistent pixel cache filename.
4094%
4095% o initialize: A value other than zero initializes the persistent pixel
4096% cache.
4097%
4098% o offset: the offset in the persistent cache to store pixels.
4099%
4100% o exception: return any errors or warnings in this structure.
4101%
4102*/
4103MagickExport MagickBooleanType PersistPixelCache(Image *image,
4104 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4105 ExceptionInfo *exception)
4106{
4107 CacheInfo
4108 *cache_info,
4109 *clone_info;
4110
4111 Image
4112 clone_image;
4113
4114 long
4115 pagesize;
4116
4117 MagickBooleanType
4118 status;
4119
4120 assert(image != (Image *) NULL);
4121 assert(image->signature == MagickSignature);
4122 if (image->debug != MagickFalse)
4123 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4124 assert(image->cache != (void *) NULL);
4125 assert(filename != (const char *) NULL);
4126 assert(offset != (MagickOffsetType *) NULL);
4127 pagesize=(-1);
4128#if defined(MAGICKCORE_HAVE_SYSCONF) && defined(_SC_PAGESIZE)
4129 pagesize=sysconf(_SC_PAGESIZE);
4130#elif defined(MAGICKCORE_HAVE_GETPAGESIZE) && defined(MAGICKCORE_POSIX_SUPPORT)
4131 pagesize=getpagesize();
4132#endif
4133 if (pagesize <= 0)
4134 pagesize=4096;
4135 cache_info=(CacheInfo *) image->cache;
4136 assert(cache_info->signature == MagickSignature);
4137 if (attach != MagickFalse)
4138 {
4139 /*
4140 Attach persistent pixel cache.
4141 */
4142 if (image->debug != MagickFalse)
4143 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4144 "attach persistent cache");
4145 (void) CopyMagickString(cache_info->cache_filename,filename,
4146 MaxTextExtent);
4147 cache_info->type=DiskCache;
4148 cache_info->offset=(*offset);
4149 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4150 return(MagickFalse);
4151 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
4152 *offset+=cache_info->length+pagesize-(cache_info->length % pagesize);
4153 return(MagickTrue);
4154 }
4155 if ((cache_info->type != MemoryCache) && (cache_info->reference_count == 1))
4156 {
4157 (void) LockSemaphoreInfo(cache_info->semaphore);
4158 if ((cache_info->type != MemoryCache) &&
4159 (cache_info->reference_count == 1))
4160 {
4161 int
4162 status;
4163
4164 /*
4165 Usurp resident persistent pixel cache.
4166 */
4167 status=rename(cache_info->cache_filename,filename);
4168 if (status == 0)
4169 {
4170 (void) CopyMagickString(cache_info->cache_filename,filename,
4171 MaxTextExtent);
4172 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
4173 *offset+=cache_info->length+pagesize-(cache_info->length %
4174 pagesize);
4175 if (image->debug != MagickFalse)
4176 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4177 "Usurp resident persistent cache");
4178 (void) UnlockSemaphoreInfo(cache_info->semaphore);
4179 return(MagickTrue);
4180 }
4181 }
4182 (void) UnlockSemaphoreInfo(cache_info->semaphore);
4183 }
4184 /*
4185 Attach persistent pixel cache.
4186 */
4187 clone_image=(*image);
4188 clone_info=(CacheInfo *) clone_image.cache;
4189 image->cache=ClonePixelCache(cache_info);
4190 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4191 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4192 cache_info->type=DiskCache;
4193 cache_info->offset=(*offset);
4194 cache_info=(CacheInfo *) image->cache;
4195 status=ClonePixelCacheNexus(cache_info,clone_info,exception);
4196 if (status != MagickFalse)
4197 {
4198 status=OpenPixelCache(image,IOMode,exception);
4199 if (status != MagickFalse)
4200 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
4201 }
4202 *offset+=cache_info->length+pagesize-(cache_info->length % pagesize);
4203 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4204 return(status);
4205}
4206
4207/*
4208%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4209% %
4210% %
4211% %
4212+ Q u e u e A u t h e n t i c N e x u s %
4213% %
4214% %
4215% %
4216%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4217%
4218% QueueAuthenticNexus() allocates an region to store image pixels as defined
4219% by the region rectangle and returns a pointer to the region. This region is
4220% subsequently transferred from the pixel cache with
4221% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4222% pixels are transferred, otherwise a NULL is returned.
4223%
4224% The format of the QueueAuthenticNexus() method is:
4225%
4226% PixelPacket *QueueAuthenticNexus(Image *image,const long x,const long y,
4227% const unsigned long columns,const unsigned long rows,
4228% NexusInfo *nexus_info,ExceptionInfo *exception)
4229%
4230% A description of each parameter follows:
4231%
4232% o image: the image.
4233%
4234% o x,y,columns,rows: These values define the perimeter of a region of
4235% pixels.
4236%
4237% o nexus_info: the cache nexus to set.
4238%
4239% o exception: return any errors or warnings in this structure.
4240%
4241*/
4242MagickExport PixelPacket *QueueAuthenticNexus(Image *image,const long x,
4243 const long y,const unsigned long columns,const unsigned long rows,
4244 NexusInfo *nexus_info,ExceptionInfo *exception)
4245{
4246 CacheInfo
4247 *cache_info;
4248
4249 MagickOffsetType
4250 offset;
4251
4252 MagickSizeType
4253 number_pixels;
4254
4255 RectangleInfo
4256 region;
4257
4258 /*
4259 Validate pixel cache geometry.
4260 */
4261 cache_info=(CacheInfo *) image->cache;
4262 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4263 {
4264 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4265 "NoPixelsDefinedInCache","`%s'",image->filename);
4266 return((PixelPacket *) NULL);
4267 }
4268 if ((x < 0) || (y < 0) || (x >= (long) cache_info->columns) ||
4269 (y >= (long) cache_info->rows))
4270 {
4271 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4272 "PixelsAreNotAuthentic","`%s'",image->filename);
4273 return((PixelPacket *) NULL);
4274 }
4275 offset=(MagickOffsetType) y*cache_info->columns+x;
4276 if (offset < 0)
4277 return((PixelPacket *) NULL);
4278 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4279 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4280 if ((MagickSizeType) offset >= number_pixels)
4281 return((PixelPacket *) NULL);
4282 /*
4283 Return pixel cache.
4284 */
4285 region.x=x;
4286 region.y=y;
4287 region.width=columns;
4288 region.height=rows;
4289 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4290}
4291
4292/*
4293%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4294% %
4295% %
4296% %
4297+ 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 %
4298% %
4299% %
4300% %
4301%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4302%
4303% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4304% defined by the region rectangle and returns a pointer to the region. This
4305% region is subsequently transferred from the pixel cache with
4306% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4307% pixels are transferred, otherwise a NULL is returned.
4308%
4309% The format of the QueueAuthenticPixelsCache() method is:
4310%
4311% PixelPacket *QueueAuthenticPixelsCache(Image *image,const long x,
4312% const long y,const unsigned long columns,const unsigned long rows,
4313% ExceptionInfo *exception)
4314%
4315% A description of each parameter follows:
4316%
4317% o image: the image.
4318%
4319% o x,y,columns,rows: These values define the perimeter of a region of
4320% pixels.
4321%
4322% o exception: return any errors or warnings in this structure.
4323%
4324*/
4325static PixelPacket *QueueAuthenticPixelsCache(Image *image,const long x,
4326 const long y,const unsigned long columns,const unsigned long rows,
4327 ExceptionInfo *exception)
4328{
4329 CacheInfo
4330 *cache_info;
4331
4332 long
4333 id;
4334
4335 PixelPacket
4336 *pixels;
4337
4338 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickFalse,exception);
4339 if (cache_info == (Cache) NULL)
4340 return((PixelPacket *) NULL);
4341 id=GetOpenMPThreadId();
4342 assert(id < (long) cache_info->number_threads);
4343 pixels=QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4344 exception);
4345 return(pixels);
4346}
4347
4348/*
4349%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4350% %
4351% %
4352% %
4353% Q u e u e A u t h e n t i c P i x e l s %
4354% %
4355% %
4356% %
4357%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4358%
4359% QueueAuthenticPixels() queues a mutable pixel region. If the region is
4360% successfully intialized a pointer to a PixelPacket array representing the
4361% region is returned, otherwise NULL is returned. The returned pointer may
4362% point to a temporary working buffer for the pixels or it may point to the
4363% final location of the pixels in memory.
4364%
4365% Write-only access means that any existing pixel values corresponding to
4366% the region are ignored. This is useful if the initial image is being
4367% created from scratch, or if the existing pixel values are to be
4368% completely replaced without need to refer to their pre-existing values.
4369% The application is free to read and write the pixel buffer returned by
4370% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4371% initialize the pixel array values. Initializing pixel array values is the
4372% application's responsibility.
4373%
4374% Performance is maximized if the selected region is part of one row, or
4375% one or more full rows, since then there is opportunity to access the
4376% pixels in-place (without a copy) if the image is in RAM, or in a
4377% memory-mapped file. The returned pointer should *never* be deallocated
4378% by the user.
4379%
4380% Pixels accessed via the returned pointer represent a simple array of type
4381% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
4382% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
4383% the black color component or the colormap indexes (of type IndexPacket)
4384% corresponding to the region. Once the PixelPacket (and/or IndexPacket)
4385% array has been updated, the changes must be saved back to the underlying
4386% image using SyncAuthenticPixels() or they may be lost.
4387%
4388% The format of the QueueAuthenticPixels() method is:
4389%
4390% PixelPacket *QueueAuthenticPixels(Image *image,const long x,const long y,
4391% const unsigned long columns,const unsigned long rows,
4392% ExceptionInfo *exception)
4393%
4394% A description of each parameter follows:
4395%
4396% o image: the image.
4397%
4398% o x,y,columns,rows: These values define the perimeter of a region of
4399% pixels.
4400%
4401% o exception: return any errors or warnings in this structure.
4402%
4403*/
4404MagickExport PixelPacket *QueueAuthenticPixels(Image *image,const long x,
4405 const long y,const unsigned long columns,const unsigned long rows,
4406 ExceptionInfo *exception)
4407{
4408 CacheInfo
4409 *cache_info;
4410
4411 PixelPacket
4412 *pixels;
4413
4414 assert(image != (Image *) NULL);
4415 assert(image->signature == MagickSignature);
4416 if (image->debug != MagickFalse)
4417 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4418 assert(image->cache != (Cache) NULL);
4419 cache_info=(CacheInfo *) image->cache;
4420 assert(cache_info->signature == MagickSignature);
4421 if (cache_info->methods.queue_authentic_pixels_handler ==
4422 (QueueAuthenticPixelsHandler) NULL)
4423 return((PixelPacket *) NULL);
4424 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4425 rows,exception);
4426 return(pixels);
4427}
4428
4429/*
4430%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4431% %
4432% %
4433% %
4434+ R e a d P i x e l C a c h e I n d e x e s %
4435% %
4436% %
4437% %
4438%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4439%
4440% ReadPixelCacheIndexes() reads colormap indexes from the specified region of
4441% the pixel cache.
4442%
4443% The format of the ReadPixelCacheIndexes() method is:
4444%
4445% MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4446% NexusInfo *nexus_info,ExceptionInfo *exception)
4447%
4448% A description of each parameter follows:
4449%
4450% o cache_info: the pixel cache.
4451%
4452% o nexus_info: the cache nexus to read the colormap indexes.
4453%
4454% o exception: return any errors or warnings in this structure.
4455%
4456*/
4457static MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4458 NexusInfo *nexus_info,ExceptionInfo *exception)
4459{
4460 MagickOffsetType
4461 count,
4462 offset;
4463
4464 MagickSizeType
4465 length,
4466 number_pixels;
4467
4468 register IndexPacket
4469 *__restrict q;
4470
4471 register long
4472 y;
4473
4474 unsigned long
4475 rows;
4476
4477 if (cache_info->debug != MagickFalse)
4478 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4479 cache_info->filename);
4480 if (cache_info->active_index_channel == MagickFalse)
4481 return(MagickFalse);
4482 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4483 return(MagickTrue);
4484 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4485 nexus_info->region.x;
4486 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
4487 rows=nexus_info->region.height;
4488 number_pixels=length*rows;
4489 if ((cache_info->columns == nexus_info->region.width) &&
4490 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4491 {
4492 length=number_pixels;
4493 rows=1UL;
4494 }
4495 q=nexus_info->indexes;
4496 switch (cache_info->type)
4497 {
4498 case MemoryCache:
4499 case MapCache:
4500 {
4501 register IndexPacket
4502 *__restrict p;
4503
4504 /*
4505 Read indexes from memory.
4506 */
4507 p=cache_info->indexes+offset;
4508 for (y=0; y < (long) rows; y++)
4509 {
4510 (void) CopyMagickMemory(q,p,(size_t) length);
4511 p+=cache_info->columns;
4512 q+=nexus_info->region.width;
4513 }
4514 break;
4515 }
4516 case DiskCache:
4517 {
4518 /*
4519 Read indexes from disk.
4520 */
4521 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4522 {
4523 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4524 cache_info->cache_filename);
4525 return(MagickFalse);
4526 }
4527 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4528 for (y=0; y < (long) rows; y++)
4529 {
4530 count=ReadPixelCacheRegion(cache_info,cache_info->offset+number_pixels*
4531 sizeof(PixelPacket)+offset*sizeof(*q),length,(unsigned char *) q);
4532 if ((MagickSizeType) count < length)
4533 break;
4534 offset+=cache_info->columns;
4535 q+=nexus_info->region.width;
4536 }
4537 if (y < (long) rows)
4538 {
4539 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4540 cache_info->cache_filename);
4541 return(MagickFalse);
4542 }
4543 break;
4544 }
4545 default:
4546 break;
4547 }
4548 if ((cache_info->debug != MagickFalse) &&
4549 (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4550 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
4551 cache_info->filename,nexus_info->region.width,nexus_info->region.height,
4552 nexus_info->region.x,nexus_info->region.y);
4553 return(MagickTrue);
4554}
4555
4556/*
4557%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4558% %
4559% %
4560% %
4561+ R e a d P i x e l C a c h e P i x e l s %
4562% %
4563% %
4564% %
4565%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4566%
4567% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4568% cache.
4569%
4570% The format of the ReadPixelCachePixels() method is:
4571%
4572% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4573% NexusInfo *nexus_info,ExceptionInfo *exception)
4574%
4575% A description of each parameter follows:
4576%
4577% o cache_info: the pixel cache.
4578%
4579% o nexus_info: the cache nexus to read the pixels.
4580%
4581% o exception: return any errors or warnings in this structure.
4582%
4583*/
4584static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4585 NexusInfo *nexus_info,ExceptionInfo *exception)
4586{
4587 MagickOffsetType
4588 count,
4589 offset;
4590
4591 MagickSizeType
4592 length,
4593 number_pixels;
4594
4595 register long
4596 y;
4597
4598 register PixelPacket
4599 *__restrict q;
4600
4601 unsigned long
4602 rows;
4603
4604 if (cache_info->debug != MagickFalse)
4605 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4606 cache_info->filename);
4607 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4608 return(MagickTrue);
4609 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4610 nexus_info->region.x;
4611 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
4612 rows=nexus_info->region.height;
4613 number_pixels=length*rows;
4614 if ((cache_info->columns == nexus_info->region.width) &&
4615 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4616 {
4617 length=number_pixels;
4618 rows=1UL;
4619 }
4620 q=nexus_info->pixels;
4621 switch (cache_info->type)
4622 {
4623 case MemoryCache:
4624 case MapCache:
4625 {
4626 register PixelPacket
4627 *__restrict p;
4628
4629 /*
4630 Read pixels from memory.
4631 */
4632 p=cache_info->pixels+offset;
4633 for (y=0; y < (long) rows; y++)
4634 {
4635 (void) CopyMagickMemory(q,p,(size_t) length);
4636 p+=cache_info->columns;
4637 q+=nexus_info->region.width;
4638 }
4639 break;
4640 }
4641 case DiskCache:
4642 {
4643 /*
4644 Read pixels from disk.
4645 */
4646 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4647 {
4648 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4649 cache_info->cache_filename);
4650 return(MagickFalse);
4651 }
4652 for (y=0; y < (long) rows; y++)
4653 {
4654 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4655 sizeof(*q),length,(unsigned char *) q);
4656 if ((MagickSizeType) count < length)
4657 break;
4658 offset+=cache_info->columns;
4659 q+=nexus_info->region.width;
4660 }
4661 if (y < (long) rows)
4662 {
4663 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4664 cache_info->cache_filename);
4665 return(MagickFalse);
4666 }
4667 break;
4668 }
4669 default:
4670 break;
4671 }
4672 if ((cache_info->debug != MagickFalse) &&
4673 (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4674 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
4675 cache_info->filename,nexus_info->region.width,nexus_info->region.height,
4676 nexus_info->region.x,nexus_info->region.y);
4677 return(MagickTrue);
4678}
4679
4680/*
4681%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4682% %
4683% %
4684% %
4685+ R e f e r e n c e P i x e l C a c h e %
4686% %
4687% %
4688% %
4689%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4690%
4691% ReferencePixelCache() increments the reference count associated with the
4692% pixel cache returning a pointer to the cache.
4693%
4694% The format of the ReferencePixelCache method is:
4695%
4696% Cache ReferencePixelCache(Cache cache_info)
4697%
4698% A description of each parameter follows:
4699%
4700% o cache_info: the pixel cache.
4701%
4702*/
4703MagickExport Cache ReferencePixelCache(Cache cache)
4704{
4705 CacheInfo
4706 *cache_info;
4707
4708 assert(cache != (Cache *) NULL);
4709 cache_info=(CacheInfo *) cache;
4710 assert(cache_info->signature == MagickSignature);
4711 if (cache_info->debug != MagickFalse)
4712 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4713 cache_info->filename);
4714 (void) LockSemaphoreInfo(cache_info->semaphore);
4715 cache_info->reference_count++;
4716 (void) UnlockSemaphoreInfo(cache_info->semaphore);
4717 return(cache_info);
4718}
4719
4720/*
4721%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4722% %
4723% %
4724% %
4725+ S e t P i x e l C a c h e M e t h o d s %
4726% %
4727% %
4728% %
4729%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4730%
4731% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4732%
4733% The format of the SetPixelCacheMethods() method is:
4734%
4735% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4736%
4737% A description of each parameter follows:
4738%
4739% o cache: the pixel cache.
4740%
4741% o cache_methods: Specifies a pointer to a CacheMethods structure.
4742%
4743*/
4744MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4745{
4746 CacheInfo
4747 *cache_info;
4748
4749 GetOneAuthenticPixelFromHandler
4750 get_one_authentic_pixel_from_handler;
4751
4752 GetOneVirtualPixelFromHandler
4753 get_one_virtual_pixel_from_handler;
4754
4755 /*
4756 Set cache pixel methods.
4757 */
4758 assert(cache != (Cache) NULL);
4759 assert(cache_methods != (CacheMethods *) NULL);
4760 cache_info=(CacheInfo *) cache;
4761 assert(cache_info->signature == MagickSignature);
4762 if (cache_info->debug != MagickFalse)
4763 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4764 cache_info->filename);
4765 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4766 cache_info->methods.get_virtual_pixel_handler=
4767 cache_methods->get_virtual_pixel_handler;
4768 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4769 cache_info->methods.destroy_pixel_handler=
4770 cache_methods->destroy_pixel_handler;
4771 if (cache_methods->get_virtual_indexes_from_handler !=
4772 (GetVirtualIndexesFromHandler) NULL)
4773 cache_info->methods.get_virtual_indexes_from_handler=
4774 cache_methods->get_virtual_indexes_from_handler;
4775 if (cache_methods->get_authentic_pixels_handler !=
4776 (GetAuthenticPixelsHandler) NULL)
4777 cache_info->methods.get_authentic_pixels_handler=
4778 cache_methods->get_authentic_pixels_handler;
4779 if (cache_methods->queue_authentic_pixels_handler !=
4780 (QueueAuthenticPixelsHandler) NULL)
4781 cache_info->methods.queue_authentic_pixels_handler=
4782 cache_methods->queue_authentic_pixels_handler;
4783 if (cache_methods->sync_authentic_pixels_handler !=
4784 (SyncAuthenticPixelsHandler) NULL)
4785 cache_info->methods.sync_authentic_pixels_handler=
4786 cache_methods->sync_authentic_pixels_handler;
4787 if (cache_methods->get_authentic_pixels_from_handler !=
4788 (GetAuthenticPixelsFromHandler) NULL)
4789 cache_info->methods.get_authentic_pixels_from_handler=
4790 cache_methods->get_authentic_pixels_from_handler;
4791 if (cache_methods->get_authentic_indexes_from_handler !=
4792 (GetAuthenticIndexesFromHandler) NULL)
4793 cache_info->methods.get_authentic_indexes_from_handler=
4794 cache_methods->get_authentic_indexes_from_handler;
4795 get_one_virtual_pixel_from_handler=
4796 cache_info->methods.get_one_virtual_pixel_from_handler;
4797 if (get_one_virtual_pixel_from_handler !=
4798 (GetOneVirtualPixelFromHandler) NULL)
4799 cache_info->methods.get_one_virtual_pixel_from_handler=
4800 cache_methods->get_one_virtual_pixel_from_handler;
4801 get_one_authentic_pixel_from_handler=
4802 cache_methods->get_one_authentic_pixel_from_handler;
4803 if (get_one_authentic_pixel_from_handler !=
4804 (GetOneAuthenticPixelFromHandler) NULL)
4805 cache_info->methods.get_one_authentic_pixel_from_handler=
4806 cache_methods->get_one_authentic_pixel_from_handler;
4807}
4808
4809/*
4810%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4811% %
4812% %
4813% %
4814+ S e t P i x e l C a c h e N e x u s P i x e l s %
4815% %
4816% %
4817% %
4818%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4819%
4820% SetPixelCacheNexusPixels() defines the region of the cache for the
4821% specified cache nexus.
4822%
4823% The format of the SetPixelCacheNexusPixels() method is:
4824%
4825% PixelPacket SetPixelCacheNexusPixels(const Image *image,
4826% const RectangleInfo *region,NexusInfo *nexus_info,
4827% ExceptionInfo *exception)
4828%
4829% A description of each parameter follows:
4830%
4831% o image: the image.
4832%
4833% o region: A pointer to the RectangleInfo structure that defines the
4834% region of this particular cache nexus.
4835%
4836% o nexus_info: the cache nexus to set.
4837%
4838% o exception: return any errors or warnings in this structure.
4839%
4840*/
4841static PixelPacket *SetPixelCacheNexusPixels(const Image *image,
4842 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4843{
4844 CacheInfo
4845 *cache_info;
4846
4847 MagickBooleanType
4848 status;
4849
4850 MagickOffsetType
4851 offset;
4852
4853 MagickSizeType
4854 length,
4855 number_pixels;
4856
4857 if (image->debug != MagickFalse)
4858 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4859 cache_info=(CacheInfo *) image->cache;
4860 assert(cache_info->signature == MagickSignature);
4861 if (cache_info->type == UndefinedCache)
4862 return((PixelPacket *) NULL);
4863 nexus_info->region.width=region->width == 0UL ? 1UL : region->width;
4864 nexus_info->region.height=region->height == 0UL ? 1UL : region->height;
4865 nexus_info->region.x=region->x;
4866 nexus_info->region.y=region->y;
4867 if ((cache_info->type != DiskCache) && (image->clip_mask == (Image *) NULL) &&
4868 (image->mask == (Image *) NULL))
4869 {
4870 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4871 nexus_info->region.x;
4872 length=(MagickSizeType) (nexus_info->region.height-1)*cache_info->columns+
4873 nexus_info->region.width-1;
4874 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4875 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
4876 {
4877 long
4878 x,
4879 y;
4880
4881 x=nexus_info->region.x+nexus_info->region.width;
4882 y=nexus_info->region.y+nexus_info->region.height;
4883 if ((nexus_info->region.x >= 0) &&
4884 (x <= (long) cache_info->columns) &&
4885 (nexus_info->region.y >= 0) && (y <= (long) cache_info->rows))
4886 if ((nexus_info->region.height == 1UL) ||
4887 ((nexus_info->region.x == 0) &&
4888 ((nexus_info->region.width % cache_info->columns) == 0)))
4889 {
4890 /*
4891 Pixels are accessed directly from memory.
4892 */
4893 nexus_info->pixels=cache_info->pixels+offset;
4894 nexus_info->indexes=(IndexPacket *) NULL;
4895 if (cache_info->active_index_channel != MagickFalse)
4896 nexus_info->indexes=cache_info->indexes+offset;
4897 return(nexus_info->pixels);
4898 }
4899 }
4900 }
4901 /*
4902 Pixels are stored in a cache region until they are synced to the cache.
4903 */
4904 number_pixels=(MagickSizeType) nexus_info->region.width*
4905 nexus_info->region.height;
4906 length=number_pixels*sizeof(PixelPacket);
4907 if (cache_info->active_index_channel != MagickFalse)
4908 length+=number_pixels*sizeof(IndexPacket);
4909 if (nexus_info->cache == (PixelPacket *) NULL)
4910 {
4911 nexus_info->length=length;
4912 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4913 if (status == MagickFalse)
4914 return((PixelPacket *) NULL);
4915 }
4916 else
4917 if (nexus_info->length != length)
4918 {
4919 RelinquishCacheNexusPixels(nexus_info);
4920 nexus_info->length=length;
4921 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4922 if (status == MagickFalse)
4923 return((PixelPacket *) NULL);
4924 }
4925 nexus_info->pixels=nexus_info->cache;
4926 nexus_info->indexes=(IndexPacket *) NULL;
4927 if (cache_info->active_index_channel != MagickFalse)
4928 nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
4929 return(nexus_info->pixels);
4930}
4931
4932/*
4933%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4934% %
4935% %
4936% %
4937% 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 %
4938% %
4939% %
4940% %
4941%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4942%
4943% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4944% pixel cache and returns the previous setting. A virtual pixel is any pixel
4945% access that is outside the boundaries of the image cache.
4946%
4947% The format of the SetPixelCacheVirtualMethod() method is:
4948%
4949% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
4950% const VirtualPixelMethod virtual_pixel_method)
4951%
4952% A description of each parameter follows:
4953%
4954% o image: the image.
4955%
4956% o virtual_pixel_method: choose the type of virtual pixel.
4957%
4958*/
4959MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
4960 const VirtualPixelMethod virtual_pixel_method)
4961{
4962 CacheInfo
4963 *cache_info;
4964
4965 VirtualPixelMethod
4966 method;
4967
4968 assert(image != (Image *) NULL);
4969 assert(image->signature == MagickSignature);
4970 if (image->debug != MagickFalse)
4971 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4972 assert(image->cache != (Cache) NULL);
4973 cache_info=(CacheInfo *) image->cache;
4974 assert(cache_info->signature == MagickSignature);
4975 method=cache_info->virtual_pixel_method;
4976 cache_info->virtual_pixel_method=virtual_pixel_method;
4977 return(method);
4978}
4979
4980/*
4981%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4982% %
4983% %
4984% %
4985+ 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 %
4986% %
4987% %
4988% %
4989%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4990%
4991% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4992% in-memory or disk cache. The method returns MagickTrue if the pixel region
4993% is synced, otherwise MagickFalse.
4994%
4995% The format of the SyncAuthenticPixelCacheNexus() method is:
4996%
4997% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4998% NexusInfo *nexus_info,ExceptionInfo *exception)
4999%
5000% A description of each parameter follows:
5001%
5002% o image: the image.
5003%
5004% o nexus_info: the cache nexus to sync.
5005%
5006% o exception: return any errors or warnings in this structure.
5007%
5008*/
5009MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5010 NexusInfo *nexus_info,ExceptionInfo *exception)
5011{
5012 CacheInfo
5013 *cache_info;
5014
5015 MagickBooleanType
5016 status;
5017
5018 /*
5019 Transfer pixels to the cache.
5020 */
5021 assert(image != (Image *) NULL);
5022 assert(image->signature == MagickSignature);
5023 if (image->debug != MagickFalse)
5024 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5025 if (image->cache == (Cache) NULL)
5026 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5027 cache_info=(CacheInfo *) image->cache;
5028 if (cache_info->type == UndefinedCache)
5029 return(MagickFalse);
5030 if ((image->clip_mask != (Image *) NULL) &&
5031 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5032 return(MagickFalse);
5033 if ((image->mask != (Image *) NULL) &&
5034 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5035 return(MagickFalse);
5036 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5037 return(MagickTrue);
5038 assert(cache_info->signature == MagickSignature);
5039 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5040 if ((cache_info->active_index_channel != MagickFalse) &&
5041 (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
5042 return(MagickFalse);
5043 return(status);
5044}
5045
5046/*
5047%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5048% %
5049% %
5050% %
5051+ S y n c A u t h e n t i c P i x e l C a c h e %
5052% %
5053% %
5054% %
5055%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5056%
5057% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5058% or disk cache. The method returns MagickTrue if the pixel region is synced,
5059% otherwise MagickFalse.
5060%
5061% The format of the SyncAuthenticPixelsCache() method is:
5062%
5063% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5064% ExceptionInfo *exception)
5065%
5066% A description of each parameter follows:
5067%
5068% o image: the image.
5069%
5070% o exception: return any errors or warnings in this structure.
5071%
5072*/
5073static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5074 ExceptionInfo *exception)
5075{
5076 CacheInfo
5077 *cache_info;
5078
5079 long
5080 id;
5081
5082 MagickBooleanType
5083 status;
5084
5085 cache_info=(CacheInfo *) image->cache;
5086 id=GetOpenMPThreadId();
5087 assert(id < (long) cache_info->number_threads);
5088 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5089 exception);
5090 return(status);
5091}
5092
5093/*
5094%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5095% %
5096% %
5097% %
5098% S y n c A u t h e n t i c P i x e l s %
5099% %
5100% %
5101% %
5102%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5103%
5104% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5105% The method returns MagickTrue if the pixel region is flushed, otherwise
5106% MagickFalse.
5107%
5108% The format of the SyncAuthenticPixels() method is:
5109%
5110% MagickBooleanType SyncAuthenticPixels(Image *image,
5111% ExceptionInfo *exception)
5112%
5113% A description of each parameter follows:
5114%
5115% o image: the image.
5116%
5117% o exception: return any errors or warnings in this structure.
5118%
5119*/
5120MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5121 ExceptionInfo *exception)
5122{
5123 CacheInfo
5124 *cache_info;
5125
5126 assert(image != (Image *) NULL);
5127 assert(image->signature == MagickSignature);
5128 if (image->debug != MagickFalse)
5129 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5130 assert(image->cache != (Cache) NULL);
5131 cache_info=(CacheInfo *) image->cache;
5132 assert(cache_info->signature == MagickSignature);
5133 if (cache_info->methods.sync_authentic_pixels_handler ==
5134 (SyncAuthenticPixelsHandler) NULL)
5135 return(MagickFalse);
5136 return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
5137}
5138
5139/*
5140%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5141% %
5142% %
5143% %
5144+ W r i t e P i x e l C a c h e I n d e x e s %
5145% %
5146% %
5147% %
5148%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5149%
5150% WritePixelCacheIndexes() writes the colormap indexes to the specified
5151% region of the pixel cache.
5152%
5153% The format of the WritePixelCacheIndexes() method is:
5154%
5155% MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5156% NexusInfo *nexus_info,ExceptionInfo *exception)
5157%
5158% A description of each parameter follows:
5159%
5160% o cache_info: the pixel cache.
5161%
5162% o nexus_info: the cache nexus to write the colormap indexes.
5163%
5164% o exception: return any errors or warnings in this structure.
5165%
5166*/
5167static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5168 NexusInfo *nexus_info,ExceptionInfo *exception)
5169{
5170 MagickOffsetType
5171 count,
5172 offset;
5173
5174 MagickSizeType
5175 length,
5176 number_pixels;
5177
5178 register const IndexPacket
5179 *__restrict p;
5180
5181 register long
5182 y;
5183
5184 unsigned long
5185 rows;
5186
5187 if (cache_info->debug != MagickFalse)
5188 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
5189 cache_info->filename);
5190 if (cache_info->active_index_channel == MagickFalse)
5191 return(MagickFalse);
5192 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5193 return(MagickTrue);
5194 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5195 nexus_info->region.x;
5196 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
5197 rows=nexus_info->region.height;
5198 number_pixels=(MagickSizeType) length*rows;
5199 if ((cache_info->columns == nexus_info->region.width) &&
5200 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5201 {
5202 length=number_pixels;
5203 rows=1UL;
5204 }
5205 p=nexus_info->indexes;
5206 switch (cache_info->type)
5207 {
5208 case MemoryCache:
5209 case MapCache:
5210 {
5211 register IndexPacket
5212 *__restrict q;
5213
5214 /*
5215 Write indexes to memory.
5216 */
5217 q=cache_info->indexes+offset;
5218 for (y=0; y < (long) rows; y++)
5219 {
5220 (void) CopyMagickMemory(q,p,(size_t) length);
5221 p+=nexus_info->region.width;
5222 q+=cache_info->columns;
5223 }
5224 break;
5225 }
5226 case DiskCache:
5227 {
5228 /*
5229 Write indexes to disk.
5230 */
5231 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5232 {
5233 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5234 cache_info->cache_filename);
5235 return(MagickFalse);
5236 }
5237 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
5238 for (y=0; y < (long) rows; y++)
5239 {
5240 count=WritePixelCacheRegion(cache_info,cache_info->offset+number_pixels*
5241 sizeof(PixelPacket)+offset*sizeof(*p),length,
5242 (const unsigned char *) p);
5243 if ((MagickSizeType) count < length)
5244 break;
5245 p+=nexus_info->region.width;
5246 offset+=cache_info->columns;
5247 }
5248 if (y < (long) rows)
5249 {
5250 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5251 cache_info->cache_filename);
5252 return(MagickFalse);
5253 }
5254 break;
5255 }
5256 default:
5257 break;
5258 }
5259 if ((cache_info->debug != MagickFalse) &&
5260 (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5261 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
5262 cache_info->filename,nexus_info->region.width,nexus_info->region.height,
5263 nexus_info->region.x,nexus_info->region.y);
5264 return(MagickTrue);
5265}
5266
5267/*
5268%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5269% %
5270% %
5271% %
5272+ W r i t e C a c h e P i x e l s %
5273% %
5274% %
5275% %
5276%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5277%
5278% WritePixelCachePixels() writes image pixels to the specified region of the
5279% pixel cache.
5280%
5281% The format of the WritePixelCachePixels() method is:
5282%
5283% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5284% NexusInfo *nexus_info,ExceptionInfo *exception)
5285%
5286% A description of each parameter follows:
5287%
5288% o cache_info: the pixel cache.
5289%
5290% o nexus_info: the cache nexus to write the pixels.
5291%
5292% o exception: return any errors or warnings in this structure.
5293%
5294*/
5295static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5296 NexusInfo *nexus_info,ExceptionInfo *exception)
5297{
5298 MagickOffsetType
5299 count,
5300 offset;
5301
5302 MagickSizeType
5303 length,
5304 number_pixels;
5305
5306 register long
5307 y;
5308
5309 register const PixelPacket
5310 *__restrict p;
5311
5312 unsigned long
5313 rows;
5314
5315 if (cache_info->debug != MagickFalse)
5316 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
5317 cache_info->filename);
5318 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5319 return(MagickTrue);
5320 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5321 nexus_info->region.x;
5322 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
5323 rows=nexus_info->region.height;
5324 number_pixels=length*rows;
5325 if ((cache_info->columns == nexus_info->region.width) &&
5326 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5327 {
5328 length=number_pixels;
5329 rows=1UL;
5330 }
5331 p=nexus_info->pixels;
5332 switch (cache_info->type)
5333 {
5334 case MemoryCache:
5335 case MapCache:
5336 {
5337 register PixelPacket
5338 *__restrict q;
5339
5340 /*
5341 Write pixels to memory.
5342 */
5343 q=cache_info->pixels+offset;
5344 for (y=0; y < (long) rows; y++)
5345 {
5346 (void) CopyMagickMemory(q,p,(size_t) length);
5347 p+=nexus_info->region.width;
5348 q+=cache_info->columns;
5349 }
5350 break;
5351 }
5352 case DiskCache:
5353 {
5354 /*
5355 Write pixels to disk.
5356 */
5357 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5358 {
5359 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5360 cache_info->cache_filename);
5361 return(MagickFalse);
5362 }
5363 for (y=0; y < (long) rows; y++)
5364 {
5365 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5366 sizeof(*p),length,(const unsigned char *) p);
5367 if ((MagickSizeType) count < length)
5368 break;
5369 p+=nexus_info->region.width;
5370 offset+=cache_info->columns;
5371 }
5372 if (y < (long) rows)
5373 {
5374 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5375 cache_info->cache_filename);
5376 return(MagickFalse);
5377 }
5378 break;
5379 }
5380 default:
5381 break;
5382 }
5383 if ((cache_info->debug != MagickFalse) &&
5384 (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5385 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
5386 cache_info->filename,nexus_info->region.width,nexus_info->region.height,
5387 nexus_info->region.x,nexus_info->region.y);
5388 return(MagickTrue);
5389}