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