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