blob: a17d0ef63a0e0ad274a755cd99e3ed63b07cbecf [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% %
cristy60c44a82009-10-07 00:58:49 +0000519+ C l o n e P i x e l C a c h e P i x e l s %
cristy3ed852e2009-09-05 21:47:34 +0000520% %
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
cristy3ed852e2009-09-05 21:47:34 +00001471 assert(cache != (Cache) NULL);
1472 cache_info=(CacheInfo *) cache;
1473 assert(cache_info->signature == MagickSignature);
1474 if (cache_info->debug != MagickFalse)
1475 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1476 cache_info->filename);
1477 (void) LockSemaphoreInfo(cache_info->semaphore);
1478 cache_info->reference_count--;
1479 if (cache_info->reference_count != 0)
1480 {
1481 (void) UnlockSemaphoreInfo(cache_info->semaphore);
1482 return((Cache) NULL);
1483 }
1484 (void) UnlockSemaphoreInfo(cache_info->semaphore);
1485 if (cache_resources != (SplayTreeInfo *) NULL)
1486 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
cristy5b8de732009-09-10 23:50:40 +00001487 if (cache_info->debug != MagickFalse)
1488 {
1489 char
1490 message[MaxTextExtent];
1491
1492 (void) FormatMagickString(message,MaxTextExtent,"destroy %s",
1493 cache_info->filename);
1494 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1495 }
cristyc2e1bdd2009-09-10 23:43:34 +00001496 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1497 (cache_info->type != DiskCache)))
1498 RelinquishPixelCachePixels(cache_info);
1499 else
1500 {
1501 RelinquishPixelCachePixels(cache_info);
1502 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1503 }
cristy3ed852e2009-09-05 21:47:34 +00001504 *cache_info->cache_filename='\0';
1505 if (cache_info->nexus_info != (NexusInfo **) NULL)
1506 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1507 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001508 if (cache_info->random_info != (RandomInfo *) NULL)
1509 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
1510 cache_info->signature=(~MagickSignature);
1511 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1512 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1513 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1514 DestroySemaphoreInfo(&cache_info->semaphore);
1515 cache_info=(CacheInfo *) RelinquishAlignedMemory(cache_info);
1516 cache=(Cache) NULL;
1517 return(cache);
1518}
1519
1520/*
1521%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1522% %
1523% %
1524% %
1525+ D e s t r o y P i x e l C a c h e N e x u s %
1526% %
1527% %
1528% %
1529%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1530%
1531% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1532%
1533% The format of the DestroyPixelCacheNexus() method is:
1534%
1535% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
1536% const unsigned long number_threads)
1537%
1538% A description of each parameter follows:
1539%
1540% o nexus_info: the nexus to destroy.
1541%
1542% o number_threads: the number of nexus threads.
1543%
1544*/
1545
1546static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1547{
1548 if (nexus_info->mapped == MagickFalse)
1549 (void) RelinquishMagickMemory(nexus_info->cache);
1550 else
1551 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1552 nexus_info->cache=(PixelPacket *) NULL;
1553 nexus_info->pixels=(PixelPacket *) NULL;
1554 nexus_info->indexes=(IndexPacket *) NULL;
1555 nexus_info->length=0;
1556 nexus_info->mapped=MagickFalse;
1557}
1558
1559MagickExport NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
1560 const unsigned long number_threads)
1561{
1562 register long
1563 i;
1564
1565 assert(nexus_info != (NexusInfo **) NULL);
1566 for (i=0; i < (long) number_threads; i++)
1567 {
1568 if (nexus_info[i]->cache != (PixelPacket *) NULL)
1569 RelinquishCacheNexusPixels(nexus_info[i]);
1570 nexus_info[i]->signature=(~MagickSignature);
1571 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
1572 }
1573 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
1574 return(nexus_info);
1575}
1576
1577/*
1578%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1579% %
1580% %
1581% %
1582+ 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 %
1583% %
1584% %
1585% %
1586%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1587%
1588% DestroyPixelCacheResources() destroys the cache resources.
1589%
1590% The format of the DestroyPixelCacheResources() method is:
1591%
1592% DestroyPixelCacheResources(void)
1593%
1594*/
1595MagickExport void DestroyPixelCacheResources(void)
1596{
1597 AcquireSemaphoreInfo(&cache_semaphore);
1598 if (cache_resources != (SplayTreeInfo *) NULL)
1599 cache_resources=DestroySplayTree(cache_resources);
1600 instantiate_cache=MagickFalse;
1601 RelinquishSemaphoreInfo(cache_semaphore);
1602 DestroySemaphoreInfo(&cache_semaphore);
1603}
1604
1605/*
1606%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1607% %
1608% %
1609% %
1610+ 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 %
1611% %
1612% %
1613% %
1614%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1615%
1616% GetAuthenticIndexesFromCache() returns the indexes associated with the last
1617% call to QueueAuthenticPixelsCache() or GetAuthenticPixelsCache().
1618%
1619% The format of the GetAuthenticIndexesFromCache() method is:
1620%
1621% IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1622%
1623% A description of each parameter follows:
1624%
1625% o image: the image.
1626%
1627*/
1628static IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1629{
1630 CacheInfo
1631 *cache_info;
1632
1633 IndexPacket
1634 *indexes;
1635
1636 long
1637 id;
1638
1639 if (image->debug != MagickFalse)
1640 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1641 cache_info=(CacheInfo *) image->cache;
1642 id=GetOpenMPThreadId();
1643 assert(id < (long) cache_info->number_threads);
1644 indexes=GetPixelCacheNexusIndexes(image->cache,cache_info->nexus_info[id]);
1645 return(indexes);
1646}
1647
1648/*
1649%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1650% %
1651% %
1652% %
1653% G e t A u t h e n t i c I n d e x Q u e u e %
1654% %
1655% %
1656% %
1657%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1658%
1659% GetAuthenticIndexQueue() returns the authentic black channel or the colormap
1660% indexes associated with the last call to QueueAuthenticPixels() or
1661% GetVirtualPixels(). NULL is returned if the black channel or colormap
1662% indexes are not available.
1663%
1664% The format of the GetAuthenticIndexQueue() method is:
1665%
1666% IndexPacket *GetAuthenticIndexQueue(const Image *image)
1667%
1668% A description of each parameter follows:
1669%
1670% o image: the image.
1671%
1672*/
1673MagickExport IndexPacket *GetAuthenticIndexQueue(const Image *image)
1674{
1675 CacheInfo
1676 *cache_info;
1677
1678 assert(image != (const Image *) NULL);
1679 assert(image->signature == MagickSignature);
1680 if (image->debug != MagickFalse)
1681 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1682 assert(image->cache != (Cache) NULL);
1683 cache_info=(CacheInfo *) image->cache;
1684 assert(cache_info->signature == MagickSignature);
1685 if (cache_info->methods.get_authentic_indexes_from_handler ==
1686 (GetAuthenticIndexesFromHandler) NULL)
1687 return((IndexPacket *) NULL);
1688 return(cache_info->methods.get_authentic_indexes_from_handler(image));
1689}
1690
1691/*
1692%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1693% %
1694% %
1695% %
1696+ 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 %
1697% %
1698% %
1699% %
1700%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1701%
1702% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1703% disk pixel cache as defined by the geometry parameters. A pointer to the
1704% pixels is returned if the pixels are transferred, otherwise a NULL is
1705% returned.
1706%
1707% The format of the GetAuthenticPixelCacheNexus() method is:
1708%
1709% PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const long x,
1710% const long y,const unsigned long columns,const unsigned long rows,
1711% NexusInfo *nexus_info,ExceptionInfo *exception)
1712%
1713% A description of each parameter follows:
1714%
1715% o image: the image.
1716%
1717% o x,y,columns,rows: These values define the perimeter of a region of
1718% pixels.
1719%
1720% o nexus_info: the cache nexus to return.
1721%
1722% o exception: return any errors or warnings in this structure.
1723%
1724*/
1725
1726static inline MagickBooleanType IsNexusInCore(const CacheInfo *cache_info,
1727 NexusInfo *nexus_info)
1728{
1729 MagickOffsetType
1730 offset;
1731
1732 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1733 nexus_info->region.x;
1734 if (nexus_info->pixels != (cache_info->pixels+offset))
1735 return(MagickFalse);
1736 return(MagickTrue);
1737}
1738
1739MagickExport PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const long x,
1740 const long y,const unsigned long columns,const unsigned long rows,
1741 NexusInfo *nexus_info,ExceptionInfo *exception)
1742{
1743 CacheInfo
1744 *cache_info;
1745
1746 PixelPacket
1747 *pixels;
1748
1749 /*
1750 Transfer pixels from the cache.
1751 */
1752 assert(image != (Image *) NULL);
1753 assert(image->signature == MagickSignature);
1754 if (image->debug != MagickFalse)
1755 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1756 pixels=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
1757 if (pixels == (PixelPacket *) NULL)
1758 return((PixelPacket *) NULL);
1759 cache_info=(CacheInfo *) image->cache;
1760 assert(cache_info->signature == MagickSignature);
1761 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
1762 return(pixels);
1763 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1764 return((PixelPacket *) NULL);
1765 if (cache_info->active_index_channel != MagickFalse)
1766 if (ReadPixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse)
1767 return((PixelPacket *) NULL);
1768 return(pixels);
1769}
1770
1771/*
1772%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1773% %
1774% %
1775% %
1776+ 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 %
1777% %
1778% %
1779% %
1780%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1781%
1782% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1783% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1784%
1785% The format of the GetAuthenticPixelsFromCache() method is:
1786%
1787% PixelPacket *GetAuthenticPixelsFromCache(const Image image)
1788%
1789% A description of each parameter follows:
1790%
1791% o image: the image.
1792%
1793*/
1794static PixelPacket *GetAuthenticPixelsFromCache(const Image *image)
1795{
1796 CacheInfo
1797 *cache_info;
1798
1799 long
1800 id;
1801
1802 PixelPacket
1803 *pixels;
1804
1805 if (image->debug != MagickFalse)
1806 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1807 cache_info=(CacheInfo *) image->cache;
1808 id=GetOpenMPThreadId();
1809 assert(id < (long) cache_info->number_threads);
1810 pixels=GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]);
1811 return(pixels);
1812}
1813
1814/*
1815%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1816% %
1817% %
1818% %
1819% G e t A u t h e n t i c P i x e l Q u e u e %
1820% %
1821% %
1822% %
1823%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1824%
1825% GetAuthenticPixelQueue() returns the authentic pixels associated with the
1826% last call to QueueAuthenticPixels() or GetAuthenticPixels().
1827%
1828% The format of the GetAuthenticPixelQueue() method is:
1829%
1830% PixelPacket *GetAuthenticPixelQueue(const Image image)
1831%
1832% A description of each parameter follows:
1833%
1834% o image: the image.
1835%
1836*/
1837MagickExport PixelPacket *GetAuthenticPixelQueue(const Image *image)
1838{
1839 CacheInfo
1840 *cache_info;
1841
1842 assert(image != (const Image *) NULL);
1843 assert(image->signature == MagickSignature);
1844 if (image->debug != MagickFalse)
1845 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1846 assert(image->cache != (Cache) NULL);
1847 cache_info=(CacheInfo *) image->cache;
1848 assert(cache_info->signature == MagickSignature);
1849 if (cache_info->methods.get_authentic_pixels_from_handler ==
1850 (GetAuthenticPixelsFromHandler) NULL)
1851 return((PixelPacket *) NULL);
1852 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1853}
1854
1855/*
1856%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1857% %
1858% %
1859% %
1860% G e t A u t h e n t i c P i x e l s %
1861% %
1862% %
1863% %
1864%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1865%
1866% GetAuthenticPixels() obtains a pixel region for read/write access. If the
1867% region is successfully accessed, a pointer to a PixelPacket array
1868% representing the region is returned, otherwise NULL is returned.
1869%
1870% The returned pointer may point to a temporary working copy of the pixels
1871% or it may point to the original pixels in memory. Performance is maximized
1872% if the selected region is part of one row, or one or more full rows, since
1873% then there is opportunity to access the pixels in-place (without a copy)
1874% if the image is in RAM, or in a memory-mapped file. The returned pointer
1875% should *never* be deallocated by the user.
1876%
1877% Pixels accessed via the returned pointer represent a simple array of type
1878% PixelPacket. If the image type is CMYK or if the storage class is
1879% PseduoClass, call GetAuthenticIndexQueue() after invoking
1880% GetAuthenticPixels() to obtain the black color component or colormap indexes
1881% (of type IndexPacket) corresponding to the region. Once the PixelPacket
1882% (and/or IndexPacket) array has been updated, the changes must be saved back
1883% to the underlying image using SyncAuthenticPixels() or they may be lost.
1884%
1885% The format of the GetAuthenticPixels() method is:
1886%
1887% PixelPacket *GetAuthenticPixels(Image *image,const long x,const long y,
1888% const unsigned long columns,const unsigned long rows,
1889% ExceptionInfo *exception)
1890%
1891% A description of each parameter follows:
1892%
1893% o image: the image.
1894%
1895% o x,y,columns,rows: These values define the perimeter of a region of
1896% pixels.
1897%
1898% o exception: return any errors or warnings in this structure.
1899%
1900*/
1901MagickExport PixelPacket *GetAuthenticPixels(Image *image,const long x,
1902 const long y,const unsigned long columns,const unsigned long rows,
1903 ExceptionInfo *exception)
1904{
1905 CacheInfo
1906 *cache_info;
1907
1908 PixelPacket
1909 *pixels;
1910
1911 assert(image != (Image *) NULL);
1912 assert(image->signature == MagickSignature);
1913 if (image->debug != MagickFalse)
1914 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1915 assert(image->cache != (Cache) NULL);
1916 cache_info=(CacheInfo *) image->cache;
1917 assert(cache_info->signature == MagickSignature);
1918 if (cache_info->methods.get_authentic_pixels_handler ==
1919 (GetAuthenticPixelsHandler) NULL)
1920 return((PixelPacket *) NULL);
1921 pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1922 rows,exception);
1923 return(pixels);
1924}
1925
1926/*
1927%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1928% %
1929% %
1930% %
1931+ G e t A u t h e n t i c P i x e l s C a c h e %
1932% %
1933% %
1934% %
1935%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1936%
1937% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1938% as defined by the geometry parameters. A pointer to the pixels is returned
1939% if the pixels are transferred, otherwise a NULL is returned.
1940%
1941% The format of the GetAuthenticPixelsCache() method is:
1942%
1943% PixelPacket *GetAuthenticPixelsCache(Image *image,const long x,
1944% const long y,const unsigned long columns,const unsigned long rows,
1945% ExceptionInfo *exception)
1946%
1947% A description of each parameter follows:
1948%
1949% o image: the image.
1950%
1951% o x,y,columns,rows: These values define the perimeter of a region of
1952% pixels.
1953%
1954% o exception: return any errors or warnings in this structure.
1955%
1956*/
1957static PixelPacket *GetAuthenticPixelsCache(Image *image,const long x,
1958 const long y,const unsigned long columns,const unsigned long rows,
1959 ExceptionInfo *exception)
1960{
1961 CacheInfo
1962 *cache_info;
1963
1964 long
1965 id;
1966
1967 PixelPacket
1968 *pixels;
1969
1970 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
1971 if (cache_info == (Cache) NULL)
1972 return((PixelPacket *) NULL);
1973 id=GetOpenMPThreadId();
1974 assert(id < (long) cache_info->number_threads);
1975 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1976 cache_info->nexus_info[id],exception);
1977 return(pixels);
1978}
1979
1980/*
1981%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1982% %
1983% %
1984% %
1985+ G e t I m a g e E x t e n t %
1986% %
1987% %
1988% %
1989%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1990%
1991% GetImageExtent() returns the extent of the pixels associated with the
1992% last call to QueueAuthenticPixels() or GetAuthenticPixels().
1993%
1994% The format of the GetImageExtent() method is:
1995%
1996% MagickSizeType GetImageExtent(const Image *image)
1997%
1998% A description of each parameter follows:
1999%
2000% o image: the image.
2001%
2002*/
2003MagickExport MagickSizeType GetImageExtent(const Image *image)
2004{
2005 CacheInfo
2006 *cache_info;
2007
2008 long
2009 id;
2010
2011 MagickSizeType
2012 extent;
2013
2014 assert(image != (Image *) NULL);
2015 assert(image->signature == MagickSignature);
2016 if (image->debug != MagickFalse)
2017 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2018 assert(image->cache != (Cache) NULL);
2019 cache_info=(CacheInfo *) image->cache;
2020 assert(cache_info->signature == MagickSignature);
2021 id=GetOpenMPThreadId();
2022 assert(id < (long) cache_info->number_threads);
2023 extent=GetPixelCacheNexusExtent(image->cache,cache_info->nexus_info[id]);
2024 return(extent);
2025}
2026
2027/*
2028%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2029% %
2030% %
2031% %
2032+ G e t I m a g e P i x e l C a c h e %
2033% %
2034% %
2035% %
2036%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2037%
2038% GetImagePixelCache() ensures that there is only a single reference to the
2039% pixel cache to be modified, updating the provided cache pointer to point to
2040% a clone of the original pixel cache if necessary.
2041%
2042% The format of the GetImagePixelCache method is:
2043%
2044% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2045% ExceptionInfo *exception)
2046%
2047% A description of each parameter follows:
2048%
2049% o image: the image.
2050%
2051% o clone: any value other than MagickFalse clones the cache pixels.
2052%
2053% o exception: return any errors or warnings in this structure.
2054%
2055*/
2056
2057static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
2058{
2059 CacheInfo
2060 *cache_info;
2061
2062 /*
2063 Does the image match the pixel cache morphology?
2064 */
2065 cache_info=(CacheInfo *) image->cache;
2066 if ((image->storage_class != cache_info->storage_class) ||
2067 (image->colorspace != cache_info->colorspace) ||
2068 (image->columns != cache_info->columns) ||
2069 (image->rows != cache_info->rows) ||
2070 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2071 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2072 return(MagickFalse);
2073 return(MagickTrue);
2074}
2075
2076MagickExport Cache GetImagePixelCache(Image *image,
2077 const MagickBooleanType clone,ExceptionInfo *exception)
2078{
2079 CacheInfo
2080 *cache_info;
2081
2082 MagickSizeType
2083 time_limit;
2084
2085 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00002086 destroy,
cristy3ed852e2009-09-05 21:47:34 +00002087 status;
2088
2089 if (image->debug != MagickFalse)
2090 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2091 status=MagickTrue;
2092 (void) LockSemaphoreInfo(image->semaphore);
2093 time_limit=GetMagickResourceLimit(TimeResource);
2094 if (cache_timer == 0)
2095 cache_timer=time((time_t *) NULL);
2096 if ((time_limit != MagickResourceInfinity) &&
2097 ((MagickSizeType) (time((time_t *) NULL)-cache_timer) >= time_limit))
2098 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
2099 assert(image->cache != (Cache) NULL);
2100 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002101 destroy=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00002102 (void) LockSemaphoreInfo(cache_info->semaphore);
cristy01b7eb02009-09-10 23:10:14 +00002103 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002104 {
2105 Image
2106 clone_image;
2107
2108 CacheInfo
2109 *clone_info;
2110
2111 /*
2112 Clone pixel cache.
2113 */
2114 clone_image=(*image);
2115 clone_image.cache=ClonePixelCache(cache_info);
2116 clone_info=(CacheInfo *) clone_image.cache;
2117 status=ClonePixelCacheNexus(cache_info,clone_info,exception);
2118 if (status != MagickFalse)
2119 {
2120 status=OpenPixelCache(&clone_image,IOMode,exception);
2121 if (status != MagickFalse)
2122 {
2123 if (clone != MagickFalse)
2124 status=ClonePixelCachePixels(clone_info,cache_info,exception);
2125 if (status != MagickFalse)
2126 {
cristy4320e0e2009-09-10 15:00:08 +00002127 destroy=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00002128 image->cache=clone_image.cache;
2129 }
2130 }
2131 }
2132 }
2133 (void) UnlockSemaphoreInfo(cache_info->semaphore);
cristy4320e0e2009-09-10 15:00:08 +00002134 if (destroy != MagickFalse)
2135 DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002136 if (status != MagickFalse)
2137 {
2138 /*
2139 Ensure the image matches the pixel cache morphology.
2140 */
2141 image->taint=MagickTrue;
2142 image->type=UndefinedType;
2143 if (image->colorspace == GRAYColorspace)
2144 image->colorspace=RGBColorspace;
2145 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2146 status=OpenPixelCache(image,IOMode,exception);
2147 }
2148 (void) UnlockSemaphoreInfo(image->semaphore);
2149 if (status == MagickFalse)
2150 return((Cache) NULL);
2151 return(image->cache);
2152}
2153
2154/*
2155%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2156% %
2157% %
2158% %
2159% G e t O n e A u t h e n t i c P i x e l %
2160% %
2161% %
2162% %
2163%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2164%
2165% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2166% location. The image background color is returned if an error occurs.
2167%
2168% The format of the GetOneAuthenticPixel() method is:
2169%
2170% MagickBooleanType GetOneAuthenticPixel(const Image image,const long x,
2171% const long y,PixelPacket *pixel,ExceptionInfo *exception)
2172%
2173% A description of each parameter follows:
2174%
2175% o image: the image.
2176%
2177% o x,y: These values define the location of the pixel to return.
2178%
2179% o pixel: return a pixel at the specified (x,y) location.
2180%
2181% o exception: return any errors or warnings in this structure.
2182%
2183*/
2184MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,const long x,
2185 const long y,PixelPacket *pixel,ExceptionInfo *exception)
2186{
2187 CacheInfo
2188 *cache_info;
2189
2190 GetOneAuthenticPixelFromHandler
2191 get_one_authentic_pixel_from_handler;
2192
2193 MagickBooleanType
2194 status;
2195
2196 assert(image != (Image *) NULL);
2197 assert(image->signature == MagickSignature);
2198 if (image->debug != MagickFalse)
2199 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2200 assert(image->cache != (Cache) NULL);
2201 cache_info=(CacheInfo *) image->cache;
2202 assert(cache_info->signature == MagickSignature);
2203 *pixel=image->background_color;
2204 get_one_authentic_pixel_from_handler=
2205 cache_info->methods.get_one_authentic_pixel_from_handler;
2206 if (get_one_authentic_pixel_from_handler ==
2207 (GetOneAuthenticPixelFromHandler) NULL)
2208 return(MagickFalse);
2209 status=cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2210 pixel,exception);
2211 return(status);
2212}
2213
2214/*
2215%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2216% %
2217% %
2218% %
2219+ 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 %
2220% %
2221% %
2222% %
2223%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2224%
2225% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2226% location. The image background color is returned if an error occurs.
2227%
2228% The format of the GetOneAuthenticPixelFromCache() method is:
2229%
2230% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
2231% const long x,const long y,PixelPacket *pixel,ExceptionInfo *exception)
2232%
2233% A description of each parameter follows:
2234%
2235% o image: the image.
2236%
2237% o x,y: These values define the location of the pixel to return.
2238%
2239% o pixel: return a pixel at the specified (x,y) location.
2240%
2241% o exception: return any errors or warnings in this structure.
2242%
2243*/
2244static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
2245 const long x,const long y,PixelPacket *pixel,ExceptionInfo *exception)
2246{
2247 PixelPacket
2248 *pixels;
2249
2250 if (image->debug != MagickFalse)
2251 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2252 *pixel=image->background_color;
2253 pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2254 if (pixels == (PixelPacket *) NULL)
2255 return(MagickFalse);
2256 *pixel=(*pixels);
2257 return(MagickTrue);
2258}
2259
2260/*
2261%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2262% %
2263% %
2264% %
2265% G e t O n e V i r t u a l M a g i c k P i x e l %
2266% %
2267% %
2268% %
2269%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2270%
2271% GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2272% location. The image background color is returned if an error occurs. If
2273% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2274%
2275% The format of the GetOneVirtualMagickPixel() method is:
2276%
2277% MagickBooleanType GetOneVirtualMagickPixel(const Image image,
2278% const long x,const long y,MagickPixelPacket *pixel,
2279% ExceptionInfo exception)
2280%
2281% A description of each parameter follows:
2282%
2283% o image: the image.
2284%
2285% o x,y: these values define the location of the pixel to return.
2286%
2287% o pixel: return a pixel at the specified (x,y) location.
2288%
2289% o exception: return any errors or warnings in this structure.
2290%
2291*/
2292MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
2293 const long x,const long y,MagickPixelPacket *pixel,ExceptionInfo *exception)
2294{
2295 CacheInfo
2296 *cache_info;
2297
2298 register const IndexPacket
2299 *indexes;
2300
2301 register const PixelPacket
2302 *p;
2303
2304 assert(image != (const Image *) NULL);
2305 assert(image->signature == MagickSignature);
2306 assert(image->cache != (Cache) NULL);
2307 cache_info=(CacheInfo *) image->cache;
2308 assert(cache_info->signature == MagickSignature);
2309 GetMagickPixelPacket(image,pixel);
2310 p=GetVirtualPixelCache(image,GetPixelCacheVirtualMethod(image),x,y,1,1,
2311 exception);
2312 if (p == (const PixelPacket *) NULL)
2313 return(MagickFalse);
2314 indexes=GetVirtualIndexQueue(image);
2315 SetMagickPixelPacket(image,p,indexes,pixel);
2316 return(MagickTrue);
2317}
2318
2319/*
2320%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2321% %
2322% %
2323% %
2324% G e t O n e V i r t u a l M e t h o d P i x e l %
2325% %
2326% %
2327% %
2328%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2329%
2330% GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2331% location as defined by specified pixel method. The image background color
2332% is returned if an error occurs. If you plan to modify the pixel, use
2333% GetOneAuthenticPixel() instead.
2334%
2335% The format of the GetOneVirtualMethodPixel() method is:
2336%
2337% MagickBooleanType GetOneVirtualMethodPixel(const Image image,
2338% const VirtualPixelMethod virtual_pixel_method,const long x,
2339% const long y,Pixelpacket *pixel,ExceptionInfo exception)
2340%
2341% A description of each parameter follows:
2342%
2343% o image: the image.
2344%
2345% o virtual_pixel_method: the virtual pixel method.
2346%
2347% o x,y: These values define the location of the pixel to return.
2348%
2349% o pixel: return a pixel at the specified (x,y) location.
2350%
2351% o exception: return any errors or warnings in this structure.
2352%
2353*/
2354MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
2355 const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
2356 PixelPacket *pixel,ExceptionInfo *exception)
2357{
2358 GetOneVirtualPixelFromHandler
2359 get_one_virtual_pixel_from_handler;
2360
2361 CacheInfo
2362 *cache_info;
2363
2364 MagickBooleanType
2365 status;
2366
2367 assert(image != (const Image *) NULL);
2368 assert(image->signature == MagickSignature);
2369 assert(image->cache != (Cache) NULL);
2370 cache_info=(CacheInfo *) image->cache;
2371 assert(cache_info->signature == MagickSignature);
2372 *pixel=image->background_color;
2373 get_one_virtual_pixel_from_handler=
2374 cache_info->methods.get_one_virtual_pixel_from_handler;
2375 if (get_one_virtual_pixel_from_handler ==
2376 (GetOneVirtualPixelFromHandler) NULL)
2377 return(MagickFalse);
2378 status=get_one_virtual_pixel_from_handler(image,virtual_pixel_method,x,y,
2379 pixel,exception);
2380 return(status);
2381}
2382
2383/*
2384%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2385% %
2386% %
2387% %
2388% G e t O n e V i r t u a l P i x e l %
2389% %
2390% %
2391% %
2392%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2393%
2394% GetOneVirtualPixel() returns a single virtual pixel at the specified
2395% (x,y) location. The image background color is returned if an error occurs.
2396% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2397%
2398% The format of the GetOneVirtualPixel() method is:
2399%
2400% MagickBooleanType GetOneVirtualPixel(const Image image,const long x,
2401% const long y,PixelPacket *pixel,ExceptionInfo exception)
2402%
2403% A description of each parameter follows:
2404%
2405% o image: the image.
2406%
2407% o x,y: These values define the location of the pixel to return.
2408%
2409% o pixel: return a pixel at the specified (x,y) location.
2410%
2411% o exception: return any errors or warnings in this structure.
2412%
2413*/
2414MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
2415 const long x,const long y,PixelPacket *pixel,ExceptionInfo *exception)
2416{
2417 GetOneVirtualPixelFromHandler
2418 get_one_virtual_pixel_from_handler;
2419
2420 CacheInfo
2421 *cache_info;
2422
2423 MagickBooleanType
2424 status;
2425
2426 assert(image != (const Image *) NULL);
2427 assert(image->signature == MagickSignature);
2428 assert(image->cache != (Cache) NULL);
2429 cache_info=(CacheInfo *) image->cache;
2430 assert(cache_info->signature == MagickSignature);
2431 *pixel=image->background_color;
2432 get_one_virtual_pixel_from_handler=
2433 cache_info->methods.get_one_virtual_pixel_from_handler;
2434 if (get_one_virtual_pixel_from_handler ==
2435 (GetOneVirtualPixelFromHandler) NULL)
2436 return(MagickFalse);
2437 status=get_one_virtual_pixel_from_handler(image,GetPixelCacheVirtualMethod(
2438 image),x,y,pixel,exception);
2439 return(status);
2440}
2441
2442/*
2443%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2444% %
2445% %
2446% %
2447+ 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 %
2448% %
2449% %
2450% %
2451%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2452%
2453% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2454% specified (x,y) location. The image background color is returned if an
2455% error occurs.
2456%
2457% The format of the GetOneVirtualPixelFromCache() method is:
2458%
2459% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
2460% const VirtualPixelPacket method,const long x,const long y,
2461% PixelPacket *pixel,ExceptionInfo *exception)
2462%
2463% A description of each parameter follows:
2464%
2465% o image: the image.
2466%
2467% o virtual_pixel_method: the virtual pixel method.
2468%
2469% o x,y: These values define the location of the pixel to return.
2470%
2471% o pixel: return a pixel at the specified (x,y) location.
2472%
2473% o exception: return any errors or warnings in this structure.
2474%
2475*/
2476static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
2477 const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
2478 PixelPacket *pixel,ExceptionInfo *exception)
2479{
2480 const PixelPacket
2481 *pixels;
2482
2483 *pixel=image->background_color;
2484 pixels=GetVirtualPixelCache(image,virtual_pixel_method,x,y,1UL,1UL,exception);
2485 if (pixels == (const PixelPacket *) NULL)
2486 return(MagickFalse);
2487 *pixel=(*pixels);
2488 return(MagickTrue);
2489}
2490
2491/*
2492%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2493% %
2494% %
2495% %
2496+ G e t P i x e l C a c h e C o l o r s p a c e %
2497% %
2498% %
2499% %
2500%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2501%
2502% GetPixelCacheColorspace() returns the class type of the pixel cache.
2503%
2504% The format of the GetPixelCacheColorspace() method is:
2505%
2506% Colorspace GetPixelCacheColorspace(Cache cache)
2507%
2508% A description of each parameter follows:
2509%
2510% o cache: the pixel cache.
2511%
2512*/
2513MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
2514{
2515 CacheInfo
2516 *cache_info;
2517
2518 assert(cache != (Cache) NULL);
2519 cache_info=(CacheInfo *) cache;
2520 assert(cache_info->signature == MagickSignature);
2521 if (cache_info->debug != MagickFalse)
2522 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2523 cache_info->filename);
2524 return(cache_info->colorspace);
2525}
2526
2527/*
2528%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2529% %
2530% %
2531% %
2532+ G e t P i x e l C a c h e M e t h o d s %
2533% %
2534% %
2535% %
2536%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2537%
2538% GetPixelCacheMethods() initializes the CacheMethods structure.
2539%
2540% The format of the GetPixelCacheMethods() method is:
2541%
2542% void GetPixelCacheMethods(CacheMethods *cache_methods)
2543%
2544% A description of each parameter follows:
2545%
2546% o cache_methods: Specifies a pointer to a CacheMethods structure.
2547%
2548*/
2549MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
2550{
2551 assert(cache_methods != (CacheMethods *) NULL);
2552 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2553 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2554 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2555 cache_methods->get_virtual_indexes_from_handler=GetVirtualIndexesFromCache;
2556 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2557 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2558 cache_methods->get_authentic_indexes_from_handler=
2559 GetAuthenticIndexesFromCache;
2560 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2561 cache_methods->get_one_authentic_pixel_from_handler=
2562 GetOneAuthenticPixelFromCache;
2563 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2564 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2565 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2566}
2567
2568/*
2569%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2570% %
2571% %
2572% %
2573+ G e t P i x e l C a c h e N e x u s E x t e n t %
2574% %
2575% %
2576% %
2577%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2578%
2579% GetPixelCacheNexusExtent() returns the extent of the pixels associated with
2580% the last call to SetPixelCacheNexusPixels() or GetPixelCacheNexusPixels().
2581%
2582% The format of the GetPixelCacheNexusExtent() method is:
2583%
2584% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2585% NexusInfo *nexus_info)
2586%
2587% A description of each parameter follows:
2588%
2589% o nexus_info: the nexus info.
2590%
2591*/
2592MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2593 NexusInfo *nexus_info)
2594{
2595 CacheInfo
2596 *cache_info;
2597
2598 MagickSizeType
2599 extent;
2600
2601 if (cache == (Cache) NULL)
2602 return(0);
2603 cache_info=(CacheInfo *) cache;
2604 assert(cache_info->signature == MagickSignature);
2605 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2606 if (extent == 0)
2607 return((MagickSizeType) cache_info->columns*cache_info->rows);
2608 return(extent);
2609}
2610
2611/*
2612%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2613% %
2614% %
2615% %
2616+ 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 %
2617% %
2618% %
2619% %
2620%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2621%
2622% GetPixelCacheNexusIndexes() returns the indexes associated with the
2623% specified cache nexus.
2624%
2625% The format of the GetPixelCacheNexusIndexes() method is:
2626%
2627% IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2628% NexusInfo *nexus_info)
2629%
2630% A description of each parameter follows:
2631%
2632% o cache: the pixel cache.
2633%
2634% o nexus_info: the cache nexus to return the colormap indexes.
2635%
2636*/
2637MagickExport IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2638 NexusInfo *nexus_info)
2639{
2640 CacheInfo
2641 *cache_info;
2642
2643 if (cache == (Cache) NULL)
2644 return((IndexPacket *) NULL);
2645 cache_info=(CacheInfo *) cache;
2646 assert(cache_info->signature == MagickSignature);
2647 if (cache_info->storage_class == UndefinedClass)
2648 return((IndexPacket *) NULL);
2649 return(nexus_info->indexes);
2650}
2651
2652/*
2653%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2654% %
2655% %
2656% %
2657+ G e t P i x e l C a c h e N e x u s P i x e l s %
2658% %
2659% %
2660% %
2661%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2662%
2663% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2664% cache nexus.
2665%
2666% The format of the GetPixelCacheNexusPixels() method is:
2667%
2668% PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2669% NexusInfo *nexus_info)
2670%
2671% A description of each parameter follows:
2672%
2673% o cache: the pixel cache.
2674%
2675% o nexus_info: the cache nexus to return the pixels.
2676%
2677*/
2678MagickExport PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2679 NexusInfo *nexus_info)
2680{
2681 CacheInfo
2682 *cache_info;
2683
2684 if (cache == (Cache) NULL)
2685 return((PixelPacket *) NULL);
2686 cache_info=(CacheInfo *) cache;
2687 assert(cache_info->signature == MagickSignature);
2688 if (cache_info->debug != MagickFalse)
2689 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2690 cache_info->filename);
2691 if (cache_info->storage_class == UndefinedClass)
2692 return((PixelPacket *) NULL);
2693 return(nexus_info->pixels);
2694}
2695
2696/*
2697%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2698% %
2699% %
2700% %
cristyb32b90a2009-09-07 21:45:48 +00002701+ 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 +00002702% %
2703% %
2704% %
2705%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2706%
2707% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2708%
2709% The format of the GetPixelCacheStorageClass() method is:
2710%
2711% ClassType GetPixelCacheStorageClass(Cache cache)
2712%
2713% A description of each parameter follows:
2714%
2715% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2716%
2717% o cache: the pixel cache.
2718%
2719*/
2720MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
2721{
2722 CacheInfo
2723 *cache_info;
2724
2725 assert(cache != (Cache) NULL);
2726 cache_info=(CacheInfo *) cache;
2727 assert(cache_info->signature == MagickSignature);
2728 if (cache_info->debug != MagickFalse)
2729 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2730 cache_info->filename);
2731 return(cache_info->storage_class);
2732}
2733
2734/*
2735%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2736% %
2737% %
2738% %
cristyb32b90a2009-09-07 21:45:48 +00002739+ G e t P i x e l C a c h e T i l e S i z e %
2740% %
2741% %
2742% %
2743%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2744%
2745% GetPixelCacheTileSize() returns the pixel cache tile size.
2746%
2747% The format of the GetPixelCacheTileSize() method is:
2748%
2749% void GetPixelCacheTileSize(const Image *image,unsigned long *width,
2750% unsigned long *height)
2751%
2752% A description of each parameter follows:
2753%
2754% o image: the image.
2755%
2756% o width: the optimize cache tile width in pixels.
2757%
2758% o height: the optimize cache tile height in pixels.
2759%
2760*/
2761MagickExport void GetPixelCacheTileSize(const Image *image,unsigned long *width,
2762 unsigned long *height)
2763{
2764 CacheInfo
2765 *cache_info;
2766
2767 assert(image != (Image *) NULL);
2768 assert(image->signature == MagickSignature);
2769 if (image->debug != MagickFalse)
2770 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2771 assert(image->cache != (Cache) NULL);
2772 cache_info=(CacheInfo *) image->cache;
2773 assert(cache_info->signature == MagickSignature);
2774 *width=2048UL/sizeof(PixelPacket);
2775 if (GetPixelCacheType(image) == DiskCache)
cristydaa97692009-09-13 02:10:35 +00002776 *width=8192UL/sizeof(PixelPacket);
cristyb32b90a2009-09-07 21:45:48 +00002777 *height=(*width);
2778}
2779
2780/*
2781%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2782% %
2783% %
2784% %
2785+ G e t P i x e l C a c h e T y p e %
2786% %
2787% %
2788% %
2789%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2790%
2791% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2792%
2793% The format of the GetPixelCacheType() method is:
2794%
2795% CacheType GetPixelCacheType(const Image *image)
2796%
2797% A description of each parameter follows:
2798%
2799% o image: the image.
2800%
2801*/
2802MagickExport CacheType GetPixelCacheType(const Image *image)
2803{
2804 CacheInfo
2805 *cache_info;
2806
2807 assert(image != (Image *) NULL);
2808 assert(image->signature == MagickSignature);
2809 if (image->debug != MagickFalse)
2810 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2811 assert(image->cache != (Cache) NULL);
2812 cache_info=(CacheInfo *) image->cache;
2813 assert(cache_info->signature == MagickSignature);
2814 return(cache_info->type);
2815}
2816
2817/*
2818%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2819% %
2820% %
2821% %
cristy3ed852e2009-09-05 21:47:34 +00002822+ 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 %
2823% %
2824% %
2825% %
2826%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2827%
2828% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2829% pixel cache. A virtual pixel is any pixel access that is outside the
2830% boundaries of the image cache.
2831%
2832% The format of the GetPixelCacheVirtualMethod() method is:
2833%
2834% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2835%
2836% A description of each parameter follows:
2837%
2838% o image: the image.
2839%
2840*/
2841MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2842{
2843 CacheInfo
2844 *cache_info;
2845
2846 assert(image != (Image *) NULL);
2847 assert(image->signature == MagickSignature);
2848 if (image->debug != MagickFalse)
2849 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2850 assert(image->cache != (Cache) NULL);
2851 cache_info=(CacheInfo *) image->cache;
2852 assert(cache_info->signature == MagickSignature);
2853 return(cache_info->virtual_pixel_method);
2854}
2855
2856/*
2857%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2858% %
2859% %
2860% %
2861+ 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 %
2862% %
2863% %
2864% %
2865%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2866%
2867% GetVirtualIndexesFromCache() returns the indexes associated with the last
2868% call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2869%
2870% The format of the GetVirtualIndexesFromCache() method is:
2871%
2872% IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2873%
2874% A description of each parameter follows:
2875%
2876% o image: the image.
2877%
2878*/
2879static const IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2880{
2881 CacheInfo
2882 *cache_info;
2883
2884 const IndexPacket
2885 *indexes;
2886
2887 long
2888 id;
2889
2890 if (image->debug != MagickFalse)
2891 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2892 cache_info=(CacheInfo *) image->cache;
2893 id=GetOpenMPThreadId();
2894 assert(id < (long) cache_info->number_threads);
2895 indexes=GetVirtualIndexesFromNexus(image->cache,cache_info->nexus_info[id]);
2896 return(indexes);
2897}
2898
2899/*
2900%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2901% %
2902% %
2903% %
2904+ 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 %
2905% %
2906% %
2907% %
2908%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2909%
2910% GetVirtualIndexesFromNexus() returns the indexes associated with the
2911% specified cache nexus.
2912%
2913% The format of the GetVirtualIndexesFromNexus() method is:
2914%
2915% const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2916% NexusInfo *nexus_info)
2917%
2918% A description of each parameter follows:
2919%
2920% o cache: the pixel cache.
2921%
2922% o nexus_info: the cache nexus to return the colormap indexes.
2923%
2924*/
2925MagickExport const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2926 NexusInfo *nexus_info)
2927{
2928 CacheInfo
2929 *cache_info;
2930
2931 if (cache == (Cache) NULL)
2932 return((IndexPacket *) NULL);
2933 cache_info=(CacheInfo *) cache;
2934 assert(cache_info->signature == MagickSignature);
2935 if (cache_info->storage_class == UndefinedClass)
2936 return((IndexPacket *) NULL);
2937 return(nexus_info->indexes);
2938}
2939
2940/*
2941%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2942% %
2943% %
2944% %
2945% G e t V i r t u a l I n d e x Q u e u e %
2946% %
2947% %
2948% %
2949%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2950%
2951% GetVirtualIndexQueue() returns the virtual black channel or the
2952% colormap indexes associated with the last call to QueueAuthenticPixels() or
2953% GetVirtualPixels(). NULL is returned if the black channel or colormap
2954% indexes are not available.
2955%
2956% The format of the GetVirtualIndexQueue() method is:
2957%
2958% const IndexPacket *GetVirtualIndexQueue(const Image *image)
2959%
2960% A description of each parameter follows:
2961%
2962% o image: the image.
2963%
2964*/
2965MagickExport const IndexPacket *GetVirtualIndexQueue(const Image *image)
2966{
2967 CacheInfo
2968 *cache_info;
2969
2970 assert(image != (const Image *) NULL);
2971 assert(image->signature == MagickSignature);
2972 if (image->debug != MagickFalse)
2973 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2974 assert(image->cache != (Cache) NULL);
2975 cache_info=(CacheInfo *) image->cache;
2976 assert(cache_info->signature == MagickSignature);
2977 if (cache_info->methods.get_virtual_indexes_from_handler ==
2978 (GetVirtualIndexesFromHandler) NULL)
2979 return((IndexPacket *) NULL);
2980 return(cache_info->methods.get_virtual_indexes_from_handler(image));
2981}
2982
2983/*
2984%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2985% %
2986% %
2987% %
2988+ 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 %
2989% %
2990% %
2991% %
2992%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2993%
2994% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2995% pixel cache as defined by the geometry parameters. A pointer to the pixels
2996% is returned if the pixels are transferred, otherwise a NULL is returned.
2997%
2998% The format of the GetVirtualPixelsFromNexus() method is:
2999%
3000% PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
3001% const VirtualPixelMethod method,const long x,const long y,
3002% const unsigned long columns,const unsigned long rows,
3003% NexusInfo *nexus_info,ExceptionInfo *exception)
3004%
3005% A description of each parameter follows:
3006%
3007% o image: the image.
3008%
3009% o virtual_pixel_method: the virtual pixel method.
3010%
3011% o x,y,columns,rows: These values define the perimeter of a region of
3012% pixels.
3013%
3014% o nexus_info: the cache nexus to acquire.
3015%
3016% o exception: return any errors or warnings in this structure.
3017%
3018*/
3019
3020static long
3021 DitherMatrix[64] =
3022 {
3023 0, 48, 12, 60, 3, 51, 15, 63,
3024 32, 16, 44, 28, 35, 19, 47, 31,
3025 8, 56, 4, 52, 11, 59, 7, 55,
3026 40, 24, 36, 20, 43, 27, 39, 23,
3027 2, 50, 14, 62, 1, 49, 13, 61,
3028 34, 18, 46, 30, 33, 17, 45, 29,
3029 10, 58, 6, 54, 9, 57, 5, 53,
3030 42, 26, 38, 22, 41, 25, 37, 21
3031 };
3032
3033static inline long DitherX(const unsigned long columns,const long x)
3034{
3035 long
3036 index;
3037
3038 index=x+DitherMatrix[x & 0x07]-32L;
3039 if (index < 0L)
3040 return(0L);
3041 if (index >= (long) columns)
3042 return((long) columns-1L);
3043 return(index);
3044}
3045
3046static inline long DitherY(const unsigned long rows,const long y)
3047{
3048 long
3049 index;
3050
3051 index=y+DitherMatrix[y & 0x07]-32L;
3052 if (index < 0L)
3053 return(0L);
3054 if (index >= (long) rows)
3055 return((long) rows-1L);
3056 return(index);
3057}
3058
3059static inline long EdgeX(const unsigned long columns,const long x)
3060{
3061 if (x < 0L)
3062 return(0L);
3063 if (x >= (long) columns)
3064 return((long) columns-1L);
3065 return(x);
3066}
3067
3068static inline long EdgeY(const unsigned long rows,const long y)
3069{
3070 if (y < 0L)
3071 return(0L);
3072 if (y >= (long) rows)
3073 return((long) rows-1L);
3074 return(y);
3075}
3076
3077static inline long RandomX(const unsigned long columns,RandomInfo *random_info)
3078{
3079 return((long) (columns*GetPseudoRandomValue(random_info)));
3080}
3081
3082static inline long RandomY(const unsigned long rows,RandomInfo *random_info)
3083{
3084 return((long) (rows*GetPseudoRandomValue(random_info)));
3085}
3086
3087/*
3088 VirtualPixelModulo() computes the remainder of dividing offset by extent. It
3089 returns not only the quotient (tile the offset falls in) but also the positive
3090 remainer within that tile such that 0 <= remainder < extent. This method is
3091 essentially a ldiv() using a floored modulo division rather than the normal
3092 default truncated modulo division.
3093*/
3094static inline MagickModulo VirtualPixelModulo(const long offset,
3095 const unsigned long extent)
3096{
3097 MagickModulo
3098 modulo;
3099
3100 modulo.quotient=offset/(long) extent;
3101 if (offset < 0L)
3102 modulo.quotient--;
3103 modulo.remainder=offset-modulo.quotient*(long) extent;
3104 return(modulo);
3105}
3106
3107MagickExport const PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
3108 const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
3109 const unsigned long columns,const unsigned long rows,NexusInfo *nexus_info,
3110 ExceptionInfo *exception)
3111{
3112 CacheInfo
3113 *cache_info;
3114
3115 MagickOffsetType
3116 offset;
3117
3118 MagickSizeType
3119 length,
3120 number_pixels;
3121
3122 NexusInfo
3123 **virtual_nexus;
3124
3125 PixelPacket
3126 *pixels,
3127 virtual_pixel;
3128
3129 RectangleInfo
3130 region;
3131
3132 register const IndexPacket
3133 *__restrict nexus_indexes;
3134
3135 register const PixelPacket
3136 *__restrict p;
3137
3138 register IndexPacket
3139 *__restrict indexes;
3140
3141 register long
3142 u,
3143 v;
3144
3145 register PixelPacket
3146 *__restrict q;
3147
3148 /*
3149 Acquire pixels.
3150 */
3151 if (image->debug != MagickFalse)
3152 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3153 cache_info=(CacheInfo *) image->cache;
3154 if (cache_info->type == UndefinedCache)
3155 return((const PixelPacket *) NULL);
3156 region.x=x;
3157 region.y=y;
3158 region.width=columns;
3159 region.height=rows;
3160 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
3161 if (pixels == (PixelPacket *) NULL)
3162 return((const PixelPacket *) NULL);
3163 offset=(MagickOffsetType) region.y*cache_info->columns+region.x;
3164 length=(MagickSizeType) (region.height-1)*cache_info->columns+region.width-1;
3165 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3166 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
3167 if ((x >= 0) && ((long) (x+columns) <= (long) cache_info->columns) &&
3168 (y >= 0) && ((long) (y+rows) <= (long) cache_info->rows))
3169 {
3170 MagickBooleanType
3171 status;
3172
3173 /*
3174 Pixel request is inside cache extents.
3175 */
3176 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
3177 return(pixels);
3178 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3179 if (status == MagickFalse)
3180 return((const PixelPacket *) NULL);
3181 if ((cache_info->storage_class == PseudoClass) ||
3182 (cache_info->colorspace == CMYKColorspace))
3183 {
3184 status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
3185 if (status == MagickFalse)
3186 return((const PixelPacket *) NULL);
3187 }
3188 return(pixels);
3189 }
3190 /*
3191 Pixel request is outside cache extents.
3192 */
3193 q=pixels;
3194 indexes=GetPixelCacheNexusIndexes(cache_info,nexus_info);
3195 virtual_nexus=AcquirePixelCacheNexus(1);
3196 if (virtual_nexus == (NexusInfo **) NULL)
3197 {
3198 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3199 "UnableToGetCacheNexus","`%s'",image->filename);
3200 return((const PixelPacket *) NULL);
3201 }
3202 switch (virtual_pixel_method)
3203 {
3204 case BlackVirtualPixelMethod:
3205 {
3206 virtual_pixel.red=0;
3207 virtual_pixel.green=0;
3208 virtual_pixel.blue=0;
3209 virtual_pixel.opacity=OpaqueOpacity;
3210 break;
3211 }
3212 case GrayVirtualPixelMethod:
3213 {
3214 virtual_pixel.red=(Quantum) QuantumRange/2;
3215 virtual_pixel.green=(Quantum) QuantumRange/2;
3216 virtual_pixel.blue=(Quantum) QuantumRange/2;
3217 virtual_pixel.opacity=(Quantum) OpaqueOpacity;
3218 break;
3219 }
3220 case TransparentVirtualPixelMethod:
3221 {
3222 virtual_pixel.red=(Quantum) 0;
3223 virtual_pixel.green=(Quantum) 0;
3224 virtual_pixel.blue=(Quantum) 0;
3225 virtual_pixel.opacity=(Quantum) TransparentOpacity;
3226 break;
3227 }
3228 case MaskVirtualPixelMethod:
3229 case WhiteVirtualPixelMethod:
3230 {
3231 virtual_pixel.red=(Quantum) QuantumRange;
3232 virtual_pixel.green=(Quantum) QuantumRange;
3233 virtual_pixel.blue=(Quantum) QuantumRange;
3234 virtual_pixel.opacity=OpaqueOpacity;
3235 break;
3236 }
3237 default:
3238 {
3239 virtual_pixel=image->background_color;
3240 break;
3241 }
3242 }
3243 for (v=0; v < (long) rows; v++)
3244 {
3245 for (u=0; u < (long) columns; u+=length)
3246 {
3247 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
3248 if ((((x+u) < 0) || ((x+u) >= (long) cache_info->columns)) ||
3249 (((y+v) < 0) || ((y+v) >= (long) cache_info->rows)) || (length == 0))
3250 {
3251 MagickModulo
3252 x_modulo,
3253 y_modulo;
3254
3255 /*
3256 Transfer a single pixel.
3257 */
3258 length=(MagickSizeType) 1;
3259 switch (virtual_pixel_method)
3260 {
3261 case BackgroundVirtualPixelMethod:
3262 case ConstantVirtualPixelMethod:
3263 case BlackVirtualPixelMethod:
3264 case GrayVirtualPixelMethod:
3265 case TransparentVirtualPixelMethod:
3266 case MaskVirtualPixelMethod:
3267 case WhiteVirtualPixelMethod:
3268 {
3269 p=(&virtual_pixel);
3270 break;
3271 }
3272 case EdgeVirtualPixelMethod:
3273 default:
3274 {
3275 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3276 EdgeX(cache_info->columns,x+u),EdgeY(cache_info->rows,y+v),
3277 1UL,1UL,virtual_nexus[0],exception);
3278 break;
3279 }
3280 case RandomVirtualPixelMethod:
3281 {
3282 if (cache_info->random_info == (RandomInfo *) NULL)
3283 cache_info->random_info=AcquireRandomInfo();
3284 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3285 RandomX(cache_info->columns,cache_info->random_info),
3286 RandomY(cache_info->rows,cache_info->random_info),1UL,1UL,
3287 virtual_nexus[0],exception);
3288 break;
3289 }
3290 case DitherVirtualPixelMethod:
3291 {
3292 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3293 DitherX(cache_info->columns,x+u),DitherY(cache_info->rows,y+v),
3294 1UL,1UL,virtual_nexus[0],exception);
3295 break;
3296 }
3297 case TileVirtualPixelMethod:
3298 {
3299 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3300 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3301 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3302 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3303 exception);
3304 break;
3305 }
3306 case MirrorVirtualPixelMethod:
3307 {
3308 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3309 if ((x_modulo.quotient & 0x01) == 1L)
3310 x_modulo.remainder=(long) cache_info->columns-
3311 x_modulo.remainder-1L;
3312 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3313 if ((y_modulo.quotient & 0x01) == 1L)
3314 y_modulo.remainder=(long) cache_info->rows-
3315 y_modulo.remainder-1L;
3316 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3317 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3318 exception);
3319 break;
3320 }
3321 case CheckerTileVirtualPixelMethod:
3322 {
3323 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3324 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3325 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3326 {
3327 p=(&virtual_pixel);
3328 break;
3329 }
3330 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3331 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3332 exception);
3333 break;
3334 }
3335 case HorizontalTileVirtualPixelMethod:
3336 {
3337 if (((y+v) < 0) || ((y+v) >= (long) cache_info->rows))
3338 {
3339 p=(&virtual_pixel);
3340 break;
3341 }
3342 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3343 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3344 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3345 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3346 exception);
3347 break;
3348 }
3349 case VerticalTileVirtualPixelMethod:
3350 {
3351 if (((x+u) < 0) || ((x+u) >= (long) cache_info->columns))
3352 {
3353 p=(&virtual_pixel);
3354 break;
3355 }
3356 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3357 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3358 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3359 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3360 exception);
3361 break;
3362 }
3363 case HorizontalTileEdgeVirtualPixelMethod:
3364 {
3365 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3366 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3367 x_modulo.remainder,EdgeY(cache_info->rows,y+v),1UL,1UL,
3368 virtual_nexus[0],exception);
3369 break;
3370 }
3371 case VerticalTileEdgeVirtualPixelMethod:
3372 {
3373 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3374 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3375 EdgeX(cache_info->columns,x+u),y_modulo.remainder,1UL,1UL,
3376 virtual_nexus[0],exception);
3377 break;
3378 }
3379 }
3380 if (p == (const PixelPacket *) NULL)
3381 break;
3382 *q++=(*p);
3383 if (indexes != (IndexPacket *) NULL)
3384 {
3385 nexus_indexes=GetVirtualIndexesFromNexus(cache_info,
3386 virtual_nexus[0]);
3387 if (nexus_indexes != (const IndexPacket *) NULL)
3388 *indexes++=(*nexus_indexes);
3389 }
3390 continue;
3391 }
3392 /*
3393 Transfer a run of pixels.
3394 */
3395 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,
3396 (unsigned long) length,1UL,virtual_nexus[0],exception);
3397 if (p == (const PixelPacket *) NULL)
3398 break;
3399 (void) CopyMagickMemory(q,p,(size_t) length*sizeof(*p));
3400 q+=length;
3401 if (indexes != (IndexPacket *) NULL)
3402 {
3403 nexus_indexes=GetVirtualIndexesFromNexus(cache_info,virtual_nexus[0]);
3404 if (nexus_indexes != (const IndexPacket *) NULL)
3405 {
3406 (void) CopyMagickMemory(indexes,nexus_indexes,(size_t) length*
3407 sizeof(*nexus_indexes));
3408 indexes+=length;
3409 }
3410 }
3411 }
3412 }
3413 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3414 return(pixels);
3415}
3416
3417/*
3418%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3419% %
3420% %
3421% %
3422+ G e t V i r t u a l P i x e l C a c h e %
3423% %
3424% %
3425% %
3426%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3427%
3428% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3429% cache as defined by the geometry parameters. A pointer to the pixels
3430% is returned if the pixels are transferred, otherwise a NULL is returned.
3431%
3432% The format of the GetVirtualPixelCache() method is:
3433%
3434% const PixelPacket *GetVirtualPixelCache(const Image *image,
3435% const VirtualPixelMethod virtual_pixel_method,const long x,
3436% const long y,const unsigned long columns,const unsigned long rows,
3437% ExceptionInfo *exception)
3438%
3439% A description of each parameter follows:
3440%
3441% o image: the image.
3442%
3443% o virtual_pixel_method: the virtual pixel method.
3444%
3445% o x,y,columns,rows: These values define the perimeter of a region of
3446% pixels.
3447%
3448% o exception: return any errors or warnings in this structure.
3449%
3450*/
3451static const PixelPacket *GetVirtualPixelCache(const Image *image,
3452 const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
3453 const unsigned long columns,const unsigned long rows,ExceptionInfo *exception)
3454{
3455 CacheInfo
3456 *cache_info;
3457
3458 const PixelPacket
3459 *pixels;
3460
3461 long
3462 id;
3463
3464 if (image->debug != MagickFalse)
3465 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3466 cache_info=(CacheInfo *) image->cache;
3467 id=GetOpenMPThreadId();
3468 assert(id < (long) cache_info->number_threads);
3469 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3470 cache_info->nexus_info[id],exception);
3471 return(pixels);
3472}
3473
3474/*
3475%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3476% %
3477% %
3478% %
3479% G e t V i r t u a l P i x e l Q u e u e %
3480% %
3481% %
3482% %
3483%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3484%
3485% GetVirtualPixelQueue() returns the virtual pixels associated with the
3486% last call to QueueAuthenticPixels() or GetVirtualPixels().
3487%
3488% The format of the GetVirtualPixelQueue() method is:
3489%
3490% const PixelPacket *GetVirtualPixelQueue(const Image image)
3491%
3492% A description of each parameter follows:
3493%
3494% o image: the image.
3495%
3496*/
3497MagickExport const PixelPacket *GetVirtualPixelQueue(const Image *image)
3498{
3499 CacheInfo
3500 *cache_info;
3501
3502 assert(image != (const Image *) NULL);
3503 assert(image->signature == MagickSignature);
3504 if (image->debug != MagickFalse)
3505 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3506 assert(image->cache != (Cache) NULL);
3507 cache_info=(CacheInfo *) image->cache;
3508 assert(cache_info->signature == MagickSignature);
3509 if (cache_info->methods.get_virtual_pixels_handler ==
3510 (GetVirtualPixelsHandler) NULL)
3511 return((PixelPacket *) NULL);
3512 return(cache_info->methods.get_virtual_pixels_handler(image));
3513}
3514
3515/*
3516%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3517% %
3518% %
3519% %
3520% G e t V i r t u a l P i x e l s %
3521% %
3522% %
3523% %
3524%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3525%
3526% GetVirtualPixels() returns an immutable pixel region. If the
3527% region is successfully accessed, a pointer to it is returned, otherwise
3528% NULL is returned. The returned pointer may point to a temporary working
3529% copy of the pixels or it may point to the original pixels in memory.
3530% Performance is maximized if the selected region is part of one row, or one
3531% or more full rows, since there is opportunity to access the pixels in-place
3532% (without a copy) if the image is in RAM, or in a memory-mapped file. The
3533% returned pointer should *never* be deallocated by the user.
3534%
3535% Pixels accessed via the returned pointer represent a simple array of type
3536% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
3537% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access
3538% the black color component or to obtain the colormap indexes (of type
3539% IndexPacket) corresponding to the region.
3540%
3541% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3542%
3543% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3544% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3545% GetCacheViewAuthenticPixels() instead.
3546%
3547% The format of the GetVirtualPixels() method is:
3548%
3549% const PixelPacket *GetVirtualPixels(const Image *image,const long x,
3550% const long y,const unsigned long columns,const unsigned long rows,
3551% ExceptionInfo *exception)
3552%
3553% A description of each parameter follows:
3554%
3555% o image: the image.
3556%
3557% o x,y,columns,rows: These values define the perimeter of a region of
3558% pixels.
3559%
3560% o exception: return any errors or warnings in this structure.
3561%
3562*/
3563MagickExport const PixelPacket *GetVirtualPixels(const Image *image,
3564 const long x,const long y,const unsigned long columns,
3565 const unsigned long rows,ExceptionInfo *exception)
3566{
3567 CacheInfo
3568 *cache_info;
3569
3570 const PixelPacket
3571 *pixels;
3572
3573 assert(image != (const Image *) NULL);
3574 assert(image->signature == MagickSignature);
3575 if (image->debug != MagickFalse)
3576 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3577 assert(image->cache != (Cache) NULL);
3578 cache_info=(CacheInfo *) image->cache;
3579 assert(cache_info->signature == MagickSignature);
3580 if (cache_info->methods.get_virtual_pixel_handler ==
3581 (GetVirtualPixelHandler) NULL)
3582 return((const PixelPacket *) NULL);
3583 pixels=cache_info->methods.get_virtual_pixel_handler(image,
3584 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception);
3585 return(pixels);
3586}
3587
3588/*
3589%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3590% %
3591% %
3592% %
3593+ 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 %
3594% %
3595% %
3596% %
3597%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3598%
3599% GetVirtualPixelsCache() returns the pixels associated with the last call
3600% to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3601%
3602% The format of the GetVirtualPixelsCache() method is:
3603%
3604% PixelPacket *GetVirtualPixelsCache(const Image *image)
3605%
3606% A description of each parameter follows:
3607%
3608% o image: the image.
3609%
3610*/
3611static const PixelPacket *GetVirtualPixelsCache(const Image *image)
3612{
3613 CacheInfo
3614 *cache_info;
3615
3616 const PixelPacket
3617 *pixels;
3618
3619 long
3620 id;
3621
3622 if (image->debug != MagickFalse)
3623 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3624 cache_info=(CacheInfo *) image->cache;
3625 id=GetOpenMPThreadId();
3626 assert(id < (long) cache_info->number_threads);
3627 pixels=GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]);
3628 return(pixels);
3629}
3630
3631/*
3632%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3633% %
3634% %
3635% %
3636+ G e t V i r t u a l P i x e l s N e x u s %
3637% %
3638% %
3639% %
3640%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3641%
3642% GetVirtualPixelsNexus() returns the pixels associated with the specified
3643% cache nexus.
3644%
3645% The format of the GetVirtualPixelsNexus() method is:
3646%
3647% const IndexPacket *GetVirtualPixelsNexus(const Cache cache,
3648% NexusInfo *nexus_info)
3649%
3650% A description of each parameter follows:
3651%
3652% o cache: the pixel cache.
3653%
3654% o nexus_info: the cache nexus to return the colormap pixels.
3655%
3656*/
3657MagickExport const PixelPacket *GetVirtualPixelsNexus(const Cache cache,
3658 NexusInfo *nexus_info)
3659{
3660 CacheInfo
3661 *cache_info;
3662
3663 if (cache == (Cache) NULL)
3664 return((PixelPacket *) NULL);
3665 cache_info=(CacheInfo *) cache;
3666 assert(cache_info->signature == MagickSignature);
3667 if (cache_info->storage_class == UndefinedClass)
3668 return((PixelPacket *) NULL);
3669 return((const PixelPacket *) nexus_info->pixels);
3670}
3671
3672/*
3673%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3674% %
3675% %
3676% %
3677+ M a s k P i x e l C a c h e N e x u s %
3678% %
3679% %
3680% %
3681%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3682%
3683% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3684% The method returns MagickTrue if the pixel region is masked, otherwise
3685% MagickFalse.
3686%
3687% The format of the MaskPixelCacheNexus() method is:
3688%
3689% MagickBooleanType MaskPixelCacheNexus(Image *image,
3690% NexusInfo *nexus_info,ExceptionInfo *exception)
3691%
3692% A description of each parameter follows:
3693%
3694% o image: the image.
3695%
3696% o nexus_info: the cache nexus to clip.
3697%
3698% o exception: return any errors or warnings in this structure.
3699%
3700*/
3701
3702static inline void MagickPixelCompositeMask(const MagickPixelPacket *p,
3703 const MagickRealType alpha,const MagickPixelPacket *q,
3704 const MagickRealType beta,MagickPixelPacket *composite)
3705{
3706 MagickRealType
3707 gamma;
3708
3709 if (alpha == TransparentOpacity)
3710 {
3711 *composite=(*q);
3712 return;
3713 }
3714 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3715 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3716 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3717 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3718 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3719 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3720 composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
3721}
3722
3723static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3724 ExceptionInfo *exception)
3725{
3726 CacheInfo
3727 *cache_info;
3728
3729 MagickPixelPacket
3730 alpha,
3731 beta;
3732
3733 MagickSizeType
3734 number_pixels;
3735
3736 NexusInfo
3737 **clip_nexus,
3738 **image_nexus;
3739
3740 register const PixelPacket
3741 *__restrict r;
3742
3743 register IndexPacket
3744 *__restrict nexus_indexes,
3745 *__restrict indexes;
3746
3747 register long
3748 i;
3749
3750 register PixelPacket
3751 *__restrict p,
3752 *__restrict q;
3753
3754 /*
3755 Apply clip mask.
3756 */
3757 if (image->debug != MagickFalse)
3758 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3759 if (image->mask == (Image *) NULL)
3760 return(MagickFalse);
3761 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
3762 if (cache_info == (Cache) NULL)
3763 return(MagickFalse);
3764 image_nexus=AcquirePixelCacheNexus(1);
3765 clip_nexus=AcquirePixelCacheNexus(1);
3766 if ((image_nexus == (NexusInfo **) NULL) ||
3767 (clip_nexus == (NexusInfo **) NULL))
3768 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
3769 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,nexus_info->region.y,
3770 nexus_info->region.width,nexus_info->region.height,image_nexus[0],
3771 exception);
3772 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
3773 q=nexus_info->pixels;
3774 nexus_indexes=nexus_info->indexes;
3775 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3776 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3777 nexus_info->region.height,clip_nexus[0],&image->exception);
3778 GetMagickPixelPacket(image,&alpha);
3779 GetMagickPixelPacket(image,&beta);
3780 number_pixels=(MagickSizeType) nexus_info->region.width*
3781 nexus_info->region.height;
3782 for (i=0; i < (long) number_pixels; i++)
3783 {
3784 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
3785 break;
3786 SetMagickPixelPacket(image,p,indexes+i,&alpha);
3787 SetMagickPixelPacket(image,q,nexus_indexes+i,&beta);
3788 MagickPixelCompositeMask(&beta,(MagickRealType) PixelIntensityToQuantum(r),
3789 &alpha,alpha.opacity,&beta);
3790 q->red=RoundToQuantum(beta.red);
3791 q->green=RoundToQuantum(beta.green);
3792 q->blue=RoundToQuantum(beta.blue);
3793 q->opacity=RoundToQuantum(beta.opacity);
3794 if (cache_info->active_index_channel != MagickFalse)
3795 nexus_indexes[i]=indexes[i];
3796 p++;
3797 q++;
3798 r++;
3799 }
3800 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3801 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
3802 if (i < (long) number_pixels)
3803 return(MagickFalse);
3804 return(MagickTrue);
3805}
3806
3807/*
3808%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3809% %
3810% %
3811% %
3812+ O p e n P i x e l C a c h e %
3813% %
3814% %
3815% %
3816%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3817%
3818% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3819% dimensions, allocating space for the image pixels and optionally the
3820% colormap indexes, and memory mapping the cache if it is disk based. The
3821% cache nexus array is initialized as well.
3822%
3823% The format of the OpenPixelCache() method is:
3824%
3825% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3826% ExceptionInfo *exception)
3827%
3828% A description of each parameter follows:
3829%
3830% o image: the image.
3831%
3832% o mode: ReadMode, WriteMode, or IOMode.
3833%
3834% o exception: return any errors or warnings in this structure.
3835%
3836*/
3837
3838static inline void AcquirePixelCachePixels(CacheInfo *cache_info)
3839{
3840 cache_info->mapped=MagickFalse;
3841 cache_info->pixels=(PixelPacket *) AcquireMagickMemory((size_t)
3842 cache_info->length);
3843 if (cache_info->pixels == (PixelPacket *) NULL)
3844 {
3845 cache_info->mapped=MagickTrue;
3846 cache_info->pixels=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
3847 cache_info->length);
3848 }
3849}
3850
3851static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3852{
3853 CacheInfo
3854 *cache_info;
3855
3856 MagickOffsetType
3857 count,
3858 extent,
3859 offset;
3860
3861 cache_info=(CacheInfo *) image->cache;
3862 if (image->debug != MagickFalse)
3863 {
3864 char
3865 format[MaxTextExtent],
3866 message[MaxTextExtent];
3867
3868 (void) FormatMagickSize(length,format);
3869 (void) FormatMagickString(message,MaxTextExtent,
3870 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3871 cache_info->cache_filename,cache_info->file,format);
3872 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3873 }
3874 if (length != (MagickSizeType) ((MagickOffsetType) length))
3875 return(MagickFalse);
3876 extent=(MagickOffsetType) MagickSeek(cache_info->file,0,SEEK_END);
3877 if (extent < 0)
3878 return(MagickFalse);
3879 if ((MagickSizeType) extent >= length)
3880 return(MagickTrue);
3881 offset=(MagickOffsetType) length-1;
3882 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3883 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3884}
3885
3886static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3887 ExceptionInfo *exception)
3888{
3889 char
3890 format[MaxTextExtent],
3891 message[MaxTextExtent];
3892
3893 CacheInfo
3894 *cache_info,
3895 source_info;
3896
3897 MagickSizeType
3898 length,
3899 number_pixels;
3900
3901 MagickStatusType
3902 status;
3903
3904 size_t
3905 packet_size;
3906
3907 unsigned long
3908 columns;
3909
3910 if (image->debug != MagickFalse)
3911 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3912 if ((image->columns == 0) || (image->rows == 0))
3913 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3914 cache_info=(CacheInfo *) image->cache;
3915 source_info=(*cache_info);
3916 source_info.file=(-1);
3917 (void) FormatMagickString(cache_info->filename,MaxTextExtent,"%s[%ld]",
3918 image->filename,GetImageIndexInList(image));
cristy87528ea2009-09-10 14:53:56 +00003919 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +00003920 cache_info->rows=image->rows;
3921 cache_info->columns=image->columns;
3922 cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
3923 (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
3924 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3925 packet_size=sizeof(PixelPacket);
3926 if (cache_info->active_index_channel != MagickFalse)
3927 packet_size+=sizeof(IndexPacket);
3928 length=number_pixels*packet_size;
3929 columns=(unsigned long) (length/cache_info->rows/packet_size);
3930 if (cache_info->columns != columns)
3931 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3932 image->filename);
3933 cache_info->length=length;
3934 status=AcquireMagickResource(AreaResource,cache_info->length);
3935 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
3936 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3937 {
3938 status=AcquireMagickResource(MemoryResource,cache_info->length);
3939 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3940 (cache_info->type == MemoryCache))
3941 {
3942 AcquirePixelCachePixels(cache_info);
3943 if (cache_info->pixels == (PixelPacket *) NULL)
3944 cache_info->pixels=source_info.pixels;
3945 else
3946 {
3947 /*
3948 Create memory pixel cache.
3949 */
3950 if (image->debug != MagickFalse)
3951 {
3952 (void) FormatMagickSize(cache_info->length,format);
3953 (void) FormatMagickString(message,MaxTextExtent,
3954 "open %s (%s memory, %lux%lu %s)",cache_info->filename,
3955 cache_info->mapped != MagickFalse ? "anonymous" : "heap",
3956 cache_info->columns,cache_info->rows,format);
3957 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3958 message);
3959 }
3960 cache_info->storage_class=image->storage_class;
3961 cache_info->colorspace=image->colorspace;
3962 cache_info->type=MemoryCache;
3963 cache_info->indexes=(IndexPacket *) NULL;
3964 if (cache_info->active_index_channel != MagickFalse)
3965 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
3966 number_pixels);
3967 if (source_info.storage_class != UndefinedClass)
3968 {
3969 status|=ClonePixelCachePixels(cache_info,&source_info,
3970 exception);
3971 RelinquishPixelCachePixels(&source_info);
3972 }
3973 return(MagickTrue);
3974 }
3975 }
3976 RelinquishMagickResource(MemoryResource,cache_info->length);
3977 }
3978 /*
3979 Create pixel cache on disk.
3980 */
3981 status=AcquireMagickResource(DiskResource,cache_info->length);
3982 if (status == MagickFalse)
3983 {
3984 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3985 "CacheResourcesExhausted","`%s'",image->filename);
3986 return(MagickFalse);
3987 }
3988 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3989 {
3990 RelinquishMagickResource(DiskResource,cache_info->length);
3991 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3992 image->filename);
3993 return(MagickFalse);
3994 }
3995 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
3996 cache_info->length);
3997 if (status == MagickFalse)
3998 {
3999 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4000 image->filename);
4001 return(MagickFalse);
4002 }
4003 cache_info->storage_class=image->storage_class;
4004 cache_info->colorspace=image->colorspace;
4005 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4006 status=AcquireMagickResource(AreaResource,cache_info->length);
4007 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4008 cache_info->type=DiskCache;
4009 else
4010 {
4011 status=AcquireMagickResource(MapResource,cache_info->length);
4012 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4013 (cache_info->type != MemoryCache))
4014 cache_info->type=DiskCache;
4015 else
4016 {
4017 cache_info->pixels=(PixelPacket *) MapBlob(cache_info->file,mode,
4018 cache_info->offset,(size_t) cache_info->length);
4019 if (cache_info->pixels == (PixelPacket *) NULL)
4020 {
4021 cache_info->pixels=source_info.pixels;
4022 cache_info->type=DiskCache;
4023 }
4024 else
4025 {
4026 /*
4027 Create file-backed memory-mapped pixel cache.
4028 */
4029 (void) ClosePixelCacheOnDisk(cache_info);
4030 cache_info->type=MapCache;
4031 cache_info->mapped=MagickTrue;
4032 cache_info->indexes=(IndexPacket *) NULL;
4033 if (cache_info->active_index_channel != MagickFalse)
4034 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4035 number_pixels);
4036 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4037 {
4038 status=ClonePixelCachePixels(cache_info,&source_info,
4039 exception);
4040 RelinquishPixelCachePixels(&source_info);
4041 }
4042 if (image->debug != MagickFalse)
4043 {
4044 (void) FormatMagickSize(cache_info->length,format);
4045 (void) FormatMagickString(message,MaxTextExtent,
4046 "open %s (%s[%d], memory-mapped, %lux%lu %s)",
4047 cache_info->filename,cache_info->cache_filename,
4048 cache_info->file,cache_info->columns,cache_info->rows,
4049 format);
4050 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4051 message);
4052 }
4053 return(MagickTrue);
4054 }
4055 }
4056 RelinquishMagickResource(MapResource,cache_info->length);
4057 }
4058 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4059 {
4060 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4061 RelinquishPixelCachePixels(&source_info);
4062 }
4063 if (image->debug != MagickFalse)
4064 {
4065 (void) FormatMagickSize(cache_info->length,format);
4066 (void) FormatMagickString(message,MaxTextExtent,
4067 "open %s (%s[%d], disk, %lux%lu %s)",cache_info->filename,
4068 cache_info->cache_filename,cache_info->file,cache_info->columns,
4069 cache_info->rows,format);
4070 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4071 }
4072 return(MagickTrue);
4073}
4074
4075/*
4076%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4077% %
4078% %
4079% %
4080+ P e r s i s t P i x e l C a c h e %
4081% %
4082% %
4083% %
4084%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4085%
4086% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4087% persistent pixel cache is one that resides on disk and is not destroyed
4088% when the program exits.
4089%
4090% The format of the PersistPixelCache() method is:
4091%
4092% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4093% const MagickBooleanType attach,MagickOffsetType *offset,
4094% ExceptionInfo *exception)
4095%
4096% A description of each parameter follows:
4097%
4098% o image: the image.
4099%
4100% o filename: the persistent pixel cache filename.
4101%
cristy01b7eb02009-09-10 23:10:14 +00004102% o attach: A value other than zero initializes the persistent pixel
4103% cache.
4104%
cristy3ed852e2009-09-05 21:47:34 +00004105% o initialize: A value other than zero initializes the persistent pixel
4106% cache.
4107%
4108% o offset: the offset in the persistent cache to store pixels.
4109%
4110% o exception: return any errors or warnings in this structure.
4111%
4112*/
4113MagickExport MagickBooleanType PersistPixelCache(Image *image,
4114 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4115 ExceptionInfo *exception)
4116{
4117 CacheInfo
4118 *cache_info,
4119 *clone_info;
4120
4121 Image
4122 clone_image;
4123
4124 long
cristy688f07b2009-09-27 15:19:13 +00004125 page_size;
cristy3ed852e2009-09-05 21:47:34 +00004126
4127 MagickBooleanType
4128 status;
4129
4130 assert(image != (Image *) NULL);
4131 assert(image->signature == MagickSignature);
4132 if (image->debug != MagickFalse)
4133 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4134 assert(image->cache != (void *) NULL);
4135 assert(filename != (const char *) NULL);
4136 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004137 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004138 cache_info=(CacheInfo *) image->cache;
4139 assert(cache_info->signature == MagickSignature);
4140 if (attach != MagickFalse)
4141 {
4142 /*
cristy01b7eb02009-09-10 23:10:14 +00004143 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004144 */
4145 if (image->debug != MagickFalse)
4146 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4147 "attach persistent cache");
4148 (void) CopyMagickString(cache_info->cache_filename,filename,
4149 MaxTextExtent);
4150 cache_info->type=DiskCache;
4151 cache_info->offset=(*offset);
4152 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4153 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004154 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004155 return(MagickTrue);
4156 }
cristy01b7eb02009-09-10 23:10:14 +00004157 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4158 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004159 {
4160 (void) LockSemaphoreInfo(cache_info->semaphore);
cristy01b7eb02009-09-10 23:10:14 +00004161 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004162 (cache_info->reference_count == 1))
4163 {
4164 int
4165 status;
4166
4167 /*
cristy01b7eb02009-09-10 23:10:14 +00004168 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004169 */
4170 status=rename(cache_info->cache_filename,filename);
4171 if (status == 0)
4172 {
4173 (void) CopyMagickString(cache_info->cache_filename,filename,
4174 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004175 *offset+=cache_info->length+page_size-(cache_info->length %
4176 page_size);
cristy87528ea2009-09-10 14:53:56 +00004177 (void) UnlockSemaphoreInfo(cache_info->semaphore);
4178 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004179 if (image->debug != MagickFalse)
4180 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4181 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004182 return(MagickTrue);
4183 }
4184 }
4185 (void) UnlockSemaphoreInfo(cache_info->semaphore);
4186 }
4187 /*
cristy01b7eb02009-09-10 23:10:14 +00004188 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004189 */
4190 clone_image=(*image);
4191 clone_info=(CacheInfo *) clone_image.cache;
4192 image->cache=ClonePixelCache(cache_info);
4193 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4194 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4195 cache_info->type=DiskCache;
4196 cache_info->offset=(*offset);
4197 cache_info=(CacheInfo *) image->cache;
4198 status=ClonePixelCacheNexus(cache_info,clone_info,exception);
4199 if (status != MagickFalse)
4200 {
4201 status=OpenPixelCache(image,IOMode,exception);
4202 if (status != MagickFalse)
4203 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
4204 }
cristy688f07b2009-09-27 15:19:13 +00004205 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004206 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4207 return(status);
4208}
4209
4210/*
4211%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4212% %
4213% %
4214% %
4215+ Q u e u e A u t h e n t i c N e x u s %
4216% %
4217% %
4218% %
4219%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4220%
4221% QueueAuthenticNexus() allocates an region to store image pixels as defined
4222% by the region rectangle and returns a pointer to the region. This region is
4223% subsequently transferred from the pixel cache with
4224% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4225% pixels are transferred, otherwise a NULL is returned.
4226%
4227% The format of the QueueAuthenticNexus() method is:
4228%
4229% PixelPacket *QueueAuthenticNexus(Image *image,const long x,const long y,
4230% const unsigned long columns,const unsigned long rows,
4231% NexusInfo *nexus_info,ExceptionInfo *exception)
4232%
4233% A description of each parameter follows:
4234%
4235% o image: the image.
4236%
4237% o x,y,columns,rows: These values define the perimeter of a region of
4238% pixels.
4239%
4240% o nexus_info: the cache nexus to set.
4241%
4242% o exception: return any errors or warnings in this structure.
4243%
4244*/
4245MagickExport PixelPacket *QueueAuthenticNexus(Image *image,const long x,
4246 const long y,const unsigned long columns,const unsigned long rows,
4247 NexusInfo *nexus_info,ExceptionInfo *exception)
4248{
4249 CacheInfo
4250 *cache_info;
4251
4252 MagickOffsetType
4253 offset;
4254
4255 MagickSizeType
4256 number_pixels;
4257
4258 RectangleInfo
4259 region;
4260
4261 /*
4262 Validate pixel cache geometry.
4263 */
4264 cache_info=(CacheInfo *) image->cache;
4265 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4266 {
4267 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4268 "NoPixelsDefinedInCache","`%s'",image->filename);
4269 return((PixelPacket *) NULL);
4270 }
4271 if ((x < 0) || (y < 0) || (x >= (long) cache_info->columns) ||
4272 (y >= (long) cache_info->rows))
4273 {
4274 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4275 "PixelsAreNotAuthentic","`%s'",image->filename);
4276 return((PixelPacket *) NULL);
4277 }
4278 offset=(MagickOffsetType) y*cache_info->columns+x;
4279 if (offset < 0)
4280 return((PixelPacket *) NULL);
4281 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4282 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4283 if ((MagickSizeType) offset >= number_pixels)
4284 return((PixelPacket *) NULL);
4285 /*
4286 Return pixel cache.
4287 */
4288 region.x=x;
4289 region.y=y;
4290 region.width=columns;
4291 region.height=rows;
4292 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4293}
4294
4295/*
4296%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4297% %
4298% %
4299% %
4300+ 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 %
4301% %
4302% %
4303% %
4304%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4305%
4306% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4307% defined by the region rectangle and returns a pointer to the region. This
4308% region is subsequently transferred from the pixel cache with
4309% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4310% pixels are transferred, otherwise a NULL is returned.
4311%
4312% The format of the QueueAuthenticPixelsCache() method is:
4313%
4314% PixelPacket *QueueAuthenticPixelsCache(Image *image,const long x,
4315% const long y,const unsigned long columns,const unsigned long rows,
4316% ExceptionInfo *exception)
4317%
4318% A description of each parameter follows:
4319%
4320% o image: the image.
4321%
4322% o x,y,columns,rows: These values define the perimeter of a region of
4323% pixels.
4324%
4325% o exception: return any errors or warnings in this structure.
4326%
4327*/
4328static PixelPacket *QueueAuthenticPixelsCache(Image *image,const long x,
4329 const long y,const unsigned long columns,const unsigned long rows,
4330 ExceptionInfo *exception)
4331{
4332 CacheInfo
4333 *cache_info;
4334
4335 long
4336 id;
4337
4338 PixelPacket
4339 *pixels;
4340
4341 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickFalse,exception);
4342 if (cache_info == (Cache) NULL)
4343 return((PixelPacket *) NULL);
4344 id=GetOpenMPThreadId();
4345 assert(id < (long) cache_info->number_threads);
4346 pixels=QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4347 exception);
4348 return(pixels);
4349}
4350
4351/*
4352%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4353% %
4354% %
4355% %
4356% Q u e u e A u t h e n t i c P i x e l s %
4357% %
4358% %
4359% %
4360%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4361%
4362% QueueAuthenticPixels() queues a mutable pixel region. If the region is
4363% successfully intialized a pointer to a PixelPacket array representing the
4364% region is returned, otherwise NULL is returned. The returned pointer may
4365% point to a temporary working buffer for the pixels or it may point to the
4366% final location of the pixels in memory.
4367%
4368% Write-only access means that any existing pixel values corresponding to
4369% the region are ignored. This is useful if the initial image is being
4370% created from scratch, or if the existing pixel values are to be
4371% completely replaced without need to refer to their pre-existing values.
4372% The application is free to read and write the pixel buffer returned by
4373% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4374% initialize the pixel array values. Initializing pixel array values is the
4375% application's responsibility.
4376%
4377% Performance is maximized if the selected region is part of one row, or
4378% one or more full rows, since then there is opportunity to access the
4379% pixels in-place (without a copy) if the image is in RAM, or in a
4380% memory-mapped file. The returned pointer should *never* be deallocated
4381% by the user.
4382%
4383% Pixels accessed via the returned pointer represent a simple array of type
4384% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
4385% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
4386% the black color component or the colormap indexes (of type IndexPacket)
4387% corresponding to the region. Once the PixelPacket (and/or IndexPacket)
4388% array has been updated, the changes must be saved back to the underlying
4389% image using SyncAuthenticPixels() or they may be lost.
4390%
4391% The format of the QueueAuthenticPixels() method is:
4392%
4393% PixelPacket *QueueAuthenticPixels(Image *image,const long x,const long y,
4394% const unsigned long columns,const unsigned long rows,
4395% ExceptionInfo *exception)
4396%
4397% A description of each parameter follows:
4398%
4399% o image: the image.
4400%
4401% o x,y,columns,rows: These values define the perimeter of a region of
4402% pixels.
4403%
4404% o exception: return any errors or warnings in this structure.
4405%
4406*/
4407MagickExport PixelPacket *QueueAuthenticPixels(Image *image,const long x,
4408 const long y,const unsigned long columns,const unsigned long rows,
4409 ExceptionInfo *exception)
4410{
4411 CacheInfo
4412 *cache_info;
4413
4414 PixelPacket
4415 *pixels;
4416
4417 assert(image != (Image *) NULL);
4418 assert(image->signature == MagickSignature);
4419 if (image->debug != MagickFalse)
4420 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4421 assert(image->cache != (Cache) NULL);
4422 cache_info=(CacheInfo *) image->cache;
4423 assert(cache_info->signature == MagickSignature);
4424 if (cache_info->methods.queue_authentic_pixels_handler ==
4425 (QueueAuthenticPixelsHandler) NULL)
4426 return((PixelPacket *) NULL);
4427 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4428 rows,exception);
4429 return(pixels);
4430}
4431
4432/*
4433%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4434% %
4435% %
4436% %
4437+ R e a d P i x e l C a c h e I n d e x e s %
4438% %
4439% %
4440% %
4441%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4442%
4443% ReadPixelCacheIndexes() reads colormap indexes from the specified region of
4444% the pixel cache.
4445%
4446% The format of the ReadPixelCacheIndexes() method is:
4447%
4448% MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4449% NexusInfo *nexus_info,ExceptionInfo *exception)
4450%
4451% A description of each parameter follows:
4452%
4453% o cache_info: the pixel cache.
4454%
4455% o nexus_info: the cache nexus to read the colormap indexes.
4456%
4457% o exception: return any errors or warnings in this structure.
4458%
4459*/
4460static MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4461 NexusInfo *nexus_info,ExceptionInfo *exception)
4462{
4463 MagickOffsetType
4464 count,
4465 offset;
4466
4467 MagickSizeType
4468 length,
4469 number_pixels;
4470
4471 register IndexPacket
4472 *__restrict q;
4473
4474 register long
4475 y;
4476
4477 unsigned long
4478 rows;
4479
4480 if (cache_info->debug != MagickFalse)
4481 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4482 cache_info->filename);
4483 if (cache_info->active_index_channel == MagickFalse)
4484 return(MagickFalse);
4485 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4486 return(MagickTrue);
4487 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4488 nexus_info->region.x;
4489 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
4490 rows=nexus_info->region.height;
4491 number_pixels=length*rows;
4492 if ((cache_info->columns == nexus_info->region.width) &&
4493 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4494 {
4495 length=number_pixels;
4496 rows=1UL;
4497 }
4498 q=nexus_info->indexes;
4499 switch (cache_info->type)
4500 {
4501 case MemoryCache:
4502 case MapCache:
4503 {
4504 register IndexPacket
4505 *__restrict p;
4506
4507 /*
4508 Read indexes from memory.
4509 */
4510 p=cache_info->indexes+offset;
4511 for (y=0; y < (long) rows; y++)
4512 {
4513 (void) CopyMagickMemory(q,p,(size_t) length);
4514 p+=cache_info->columns;
4515 q+=nexus_info->region.width;
4516 }
4517 break;
4518 }
4519 case DiskCache:
4520 {
4521 /*
4522 Read indexes from disk.
4523 */
4524 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4525 {
4526 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4527 cache_info->cache_filename);
4528 return(MagickFalse);
4529 }
4530 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4531 for (y=0; y < (long) rows; y++)
4532 {
4533 count=ReadPixelCacheRegion(cache_info,cache_info->offset+number_pixels*
4534 sizeof(PixelPacket)+offset*sizeof(*q),length,(unsigned char *) q);
4535 if ((MagickSizeType) count < length)
4536 break;
4537 offset+=cache_info->columns;
4538 q+=nexus_info->region.width;
4539 }
4540 if (y < (long) rows)
4541 {
4542 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4543 cache_info->cache_filename);
4544 return(MagickFalse);
4545 }
4546 break;
4547 }
4548 default:
4549 break;
4550 }
4551 if ((cache_info->debug != MagickFalse) &&
4552 (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4553 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
4554 cache_info->filename,nexus_info->region.width,nexus_info->region.height,
4555 nexus_info->region.x,nexus_info->region.y);
4556 return(MagickTrue);
4557}
4558
4559/*
4560%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4561% %
4562% %
4563% %
4564+ R e a d P i x e l C a c h e P i x e l s %
4565% %
4566% %
4567% %
4568%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4569%
4570% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4571% cache.
4572%
4573% The format of the ReadPixelCachePixels() method is:
4574%
4575% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4576% NexusInfo *nexus_info,ExceptionInfo *exception)
4577%
4578% A description of each parameter follows:
4579%
4580% o cache_info: the pixel cache.
4581%
4582% o nexus_info: the cache nexus to read the pixels.
4583%
4584% o exception: return any errors or warnings in this structure.
4585%
4586*/
4587static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4588 NexusInfo *nexus_info,ExceptionInfo *exception)
4589{
4590 MagickOffsetType
4591 count,
4592 offset;
4593
4594 MagickSizeType
4595 length,
4596 number_pixels;
4597
4598 register long
4599 y;
4600
4601 register PixelPacket
4602 *__restrict q;
4603
4604 unsigned long
4605 rows;
4606
4607 if (cache_info->debug != MagickFalse)
4608 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4609 cache_info->filename);
4610 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4611 return(MagickTrue);
4612 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4613 nexus_info->region.x;
4614 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
4615 rows=nexus_info->region.height;
4616 number_pixels=length*rows;
4617 if ((cache_info->columns == nexus_info->region.width) &&
4618 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4619 {
4620 length=number_pixels;
4621 rows=1UL;
4622 }
4623 q=nexus_info->pixels;
4624 switch (cache_info->type)
4625 {
4626 case MemoryCache:
4627 case MapCache:
4628 {
4629 register PixelPacket
4630 *__restrict p;
4631
4632 /*
4633 Read pixels from memory.
4634 */
4635 p=cache_info->pixels+offset;
4636 for (y=0; y < (long) rows; y++)
4637 {
4638 (void) CopyMagickMemory(q,p,(size_t) length);
4639 p+=cache_info->columns;
4640 q+=nexus_info->region.width;
4641 }
4642 break;
4643 }
4644 case DiskCache:
4645 {
4646 /*
4647 Read pixels from disk.
4648 */
4649 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4650 {
4651 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4652 cache_info->cache_filename);
4653 return(MagickFalse);
4654 }
4655 for (y=0; y < (long) rows; y++)
4656 {
4657 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4658 sizeof(*q),length,(unsigned char *) q);
4659 if ((MagickSizeType) count < length)
4660 break;
4661 offset+=cache_info->columns;
4662 q+=nexus_info->region.width;
4663 }
4664 if (y < (long) rows)
4665 {
4666 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4667 cache_info->cache_filename);
4668 return(MagickFalse);
4669 }
4670 break;
4671 }
4672 default:
4673 break;
4674 }
4675 if ((cache_info->debug != MagickFalse) &&
4676 (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4677 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
4678 cache_info->filename,nexus_info->region.width,nexus_info->region.height,
4679 nexus_info->region.x,nexus_info->region.y);
4680 return(MagickTrue);
4681}
4682
4683/*
4684%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4685% %
4686% %
4687% %
4688+ R e f e r e n c e P i x e l C a c h e %
4689% %
4690% %
4691% %
4692%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4693%
4694% ReferencePixelCache() increments the reference count associated with the
4695% pixel cache returning a pointer to the cache.
4696%
4697% The format of the ReferencePixelCache method is:
4698%
4699% Cache ReferencePixelCache(Cache cache_info)
4700%
4701% A description of each parameter follows:
4702%
4703% o cache_info: the pixel cache.
4704%
4705*/
4706MagickExport Cache ReferencePixelCache(Cache cache)
4707{
4708 CacheInfo
4709 *cache_info;
4710
4711 assert(cache != (Cache *) NULL);
4712 cache_info=(CacheInfo *) cache;
4713 assert(cache_info->signature == MagickSignature);
4714 if (cache_info->debug != MagickFalse)
4715 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4716 cache_info->filename);
4717 (void) LockSemaphoreInfo(cache_info->semaphore);
4718 cache_info->reference_count++;
4719 (void) UnlockSemaphoreInfo(cache_info->semaphore);
4720 return(cache_info);
4721}
4722
4723/*
4724%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4725% %
4726% %
4727% %
4728+ S e t P i x e l C a c h e M e t h o d s %
4729% %
4730% %
4731% %
4732%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4733%
4734% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4735%
4736% The format of the SetPixelCacheMethods() method is:
4737%
4738% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4739%
4740% A description of each parameter follows:
4741%
4742% o cache: the pixel cache.
4743%
4744% o cache_methods: Specifies a pointer to a CacheMethods structure.
4745%
4746*/
4747MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4748{
4749 CacheInfo
4750 *cache_info;
4751
4752 GetOneAuthenticPixelFromHandler
4753 get_one_authentic_pixel_from_handler;
4754
4755 GetOneVirtualPixelFromHandler
4756 get_one_virtual_pixel_from_handler;
4757
4758 /*
4759 Set cache pixel methods.
4760 */
4761 assert(cache != (Cache) NULL);
4762 assert(cache_methods != (CacheMethods *) NULL);
4763 cache_info=(CacheInfo *) cache;
4764 assert(cache_info->signature == MagickSignature);
4765 if (cache_info->debug != MagickFalse)
4766 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4767 cache_info->filename);
4768 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4769 cache_info->methods.get_virtual_pixel_handler=
4770 cache_methods->get_virtual_pixel_handler;
4771 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4772 cache_info->methods.destroy_pixel_handler=
4773 cache_methods->destroy_pixel_handler;
4774 if (cache_methods->get_virtual_indexes_from_handler !=
4775 (GetVirtualIndexesFromHandler) NULL)
4776 cache_info->methods.get_virtual_indexes_from_handler=
4777 cache_methods->get_virtual_indexes_from_handler;
4778 if (cache_methods->get_authentic_pixels_handler !=
4779 (GetAuthenticPixelsHandler) NULL)
4780 cache_info->methods.get_authentic_pixels_handler=
4781 cache_methods->get_authentic_pixels_handler;
4782 if (cache_methods->queue_authentic_pixels_handler !=
4783 (QueueAuthenticPixelsHandler) NULL)
4784 cache_info->methods.queue_authentic_pixels_handler=
4785 cache_methods->queue_authentic_pixels_handler;
4786 if (cache_methods->sync_authentic_pixels_handler !=
4787 (SyncAuthenticPixelsHandler) NULL)
4788 cache_info->methods.sync_authentic_pixels_handler=
4789 cache_methods->sync_authentic_pixels_handler;
4790 if (cache_methods->get_authentic_pixels_from_handler !=
4791 (GetAuthenticPixelsFromHandler) NULL)
4792 cache_info->methods.get_authentic_pixels_from_handler=
4793 cache_methods->get_authentic_pixels_from_handler;
4794 if (cache_methods->get_authentic_indexes_from_handler !=
4795 (GetAuthenticIndexesFromHandler) NULL)
4796 cache_info->methods.get_authentic_indexes_from_handler=
4797 cache_methods->get_authentic_indexes_from_handler;
4798 get_one_virtual_pixel_from_handler=
4799 cache_info->methods.get_one_virtual_pixel_from_handler;
4800 if (get_one_virtual_pixel_from_handler !=
4801 (GetOneVirtualPixelFromHandler) NULL)
4802 cache_info->methods.get_one_virtual_pixel_from_handler=
4803 cache_methods->get_one_virtual_pixel_from_handler;
4804 get_one_authentic_pixel_from_handler=
4805 cache_methods->get_one_authentic_pixel_from_handler;
4806 if (get_one_authentic_pixel_from_handler !=
4807 (GetOneAuthenticPixelFromHandler) NULL)
4808 cache_info->methods.get_one_authentic_pixel_from_handler=
4809 cache_methods->get_one_authentic_pixel_from_handler;
4810}
4811
4812/*
4813%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4814% %
4815% %
4816% %
4817+ S e t P i x e l C a c h e N e x u s P i x e l s %
4818% %
4819% %
4820% %
4821%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4822%
4823% SetPixelCacheNexusPixels() defines the region of the cache for the
4824% specified cache nexus.
4825%
4826% The format of the SetPixelCacheNexusPixels() method is:
4827%
4828% PixelPacket SetPixelCacheNexusPixels(const Image *image,
4829% const RectangleInfo *region,NexusInfo *nexus_info,
4830% ExceptionInfo *exception)
4831%
4832% A description of each parameter follows:
4833%
4834% o image: the image.
4835%
4836% o region: A pointer to the RectangleInfo structure that defines the
4837% region of this particular cache nexus.
4838%
4839% o nexus_info: the cache nexus to set.
4840%
4841% o exception: return any errors or warnings in this structure.
4842%
4843*/
4844static PixelPacket *SetPixelCacheNexusPixels(const Image *image,
4845 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4846{
4847 CacheInfo
4848 *cache_info;
4849
4850 MagickBooleanType
4851 status;
4852
4853 MagickOffsetType
4854 offset;
4855
4856 MagickSizeType
4857 length,
4858 number_pixels;
4859
4860 if (image->debug != MagickFalse)
4861 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4862 cache_info=(CacheInfo *) image->cache;
4863 assert(cache_info->signature == MagickSignature);
4864 if (cache_info->type == UndefinedCache)
4865 return((PixelPacket *) NULL);
4866 nexus_info->region.width=region->width == 0UL ? 1UL : region->width;
4867 nexus_info->region.height=region->height == 0UL ? 1UL : region->height;
4868 nexus_info->region.x=region->x;
4869 nexus_info->region.y=region->y;
4870 if ((cache_info->type != DiskCache) && (image->clip_mask == (Image *) NULL) &&
4871 (image->mask == (Image *) NULL))
4872 {
4873 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4874 nexus_info->region.x;
4875 length=(MagickSizeType) (nexus_info->region.height-1)*cache_info->columns+
4876 nexus_info->region.width-1;
4877 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4878 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
4879 {
4880 long
4881 x,
4882 y;
4883
4884 x=nexus_info->region.x+nexus_info->region.width;
4885 y=nexus_info->region.y+nexus_info->region.height;
4886 if ((nexus_info->region.x >= 0) &&
4887 (x <= (long) cache_info->columns) &&
4888 (nexus_info->region.y >= 0) && (y <= (long) cache_info->rows))
4889 if ((nexus_info->region.height == 1UL) ||
4890 ((nexus_info->region.x == 0) &&
4891 ((nexus_info->region.width % cache_info->columns) == 0)))
4892 {
4893 /*
4894 Pixels are accessed directly from memory.
4895 */
4896 nexus_info->pixels=cache_info->pixels+offset;
4897 nexus_info->indexes=(IndexPacket *) NULL;
4898 if (cache_info->active_index_channel != MagickFalse)
4899 nexus_info->indexes=cache_info->indexes+offset;
4900 return(nexus_info->pixels);
4901 }
4902 }
4903 }
4904 /*
4905 Pixels are stored in a cache region until they are synced to the cache.
4906 */
4907 number_pixels=(MagickSizeType) nexus_info->region.width*
4908 nexus_info->region.height;
4909 length=number_pixels*sizeof(PixelPacket);
4910 if (cache_info->active_index_channel != MagickFalse)
4911 length+=number_pixels*sizeof(IndexPacket);
4912 if (nexus_info->cache == (PixelPacket *) NULL)
4913 {
4914 nexus_info->length=length;
4915 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4916 if (status == MagickFalse)
4917 return((PixelPacket *) NULL);
4918 }
4919 else
4920 if (nexus_info->length != length)
4921 {
4922 RelinquishCacheNexusPixels(nexus_info);
4923 nexus_info->length=length;
4924 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4925 if (status == MagickFalse)
4926 return((PixelPacket *) NULL);
4927 }
4928 nexus_info->pixels=nexus_info->cache;
4929 nexus_info->indexes=(IndexPacket *) NULL;
4930 if (cache_info->active_index_channel != MagickFalse)
4931 nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
4932 return(nexus_info->pixels);
4933}
4934
4935/*
4936%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4937% %
4938% %
4939% %
4940% 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 %
4941% %
4942% %
4943% %
4944%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4945%
4946% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4947% pixel cache and returns the previous setting. A virtual pixel is any pixel
4948% access that is outside the boundaries of the image cache.
4949%
4950% The format of the SetPixelCacheVirtualMethod() method is:
4951%
4952% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
4953% const VirtualPixelMethod virtual_pixel_method)
4954%
4955% A description of each parameter follows:
4956%
4957% o image: the image.
4958%
4959% o virtual_pixel_method: choose the type of virtual pixel.
4960%
4961*/
4962MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
4963 const VirtualPixelMethod virtual_pixel_method)
4964{
4965 CacheInfo
4966 *cache_info;
4967
4968 VirtualPixelMethod
4969 method;
4970
4971 assert(image != (Image *) NULL);
4972 assert(image->signature == MagickSignature);
4973 if (image->debug != MagickFalse)
4974 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4975 assert(image->cache != (Cache) NULL);
4976 cache_info=(CacheInfo *) image->cache;
4977 assert(cache_info->signature == MagickSignature);
4978 method=cache_info->virtual_pixel_method;
4979 cache_info->virtual_pixel_method=virtual_pixel_method;
4980 return(method);
4981}
4982
4983/*
4984%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4985% %
4986% %
4987% %
4988+ 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 %
4989% %
4990% %
4991% %
4992%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4993%
4994% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4995% in-memory or disk cache. The method returns MagickTrue if the pixel region
4996% is synced, otherwise MagickFalse.
4997%
4998% The format of the SyncAuthenticPixelCacheNexus() method is:
4999%
5000% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5001% NexusInfo *nexus_info,ExceptionInfo *exception)
5002%
5003% A description of each parameter follows:
5004%
5005% o image: the image.
5006%
5007% o nexus_info: the cache nexus to sync.
5008%
5009% o exception: return any errors or warnings in this structure.
5010%
5011*/
5012MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5013 NexusInfo *nexus_info,ExceptionInfo *exception)
5014{
5015 CacheInfo
5016 *cache_info;
5017
5018 MagickBooleanType
5019 status;
5020
5021 /*
5022 Transfer pixels to the cache.
5023 */
5024 assert(image != (Image *) NULL);
5025 assert(image->signature == MagickSignature);
5026 if (image->debug != MagickFalse)
5027 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5028 if (image->cache == (Cache) NULL)
5029 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5030 cache_info=(CacheInfo *) image->cache;
5031 if (cache_info->type == UndefinedCache)
5032 return(MagickFalse);
5033 if ((image->clip_mask != (Image *) NULL) &&
5034 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5035 return(MagickFalse);
5036 if ((image->mask != (Image *) NULL) &&
5037 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5038 return(MagickFalse);
5039 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5040 return(MagickTrue);
5041 assert(cache_info->signature == MagickSignature);
5042 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5043 if ((cache_info->active_index_channel != MagickFalse) &&
5044 (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
5045 return(MagickFalse);
5046 return(status);
5047}
5048
5049/*
5050%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5051% %
5052% %
5053% %
5054+ S y n c A u t h e n t i c P i x e l C a c h e %
5055% %
5056% %
5057% %
5058%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5059%
5060% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5061% or disk cache. The method returns MagickTrue if the pixel region is synced,
5062% otherwise MagickFalse.
5063%
5064% The format of the SyncAuthenticPixelsCache() method is:
5065%
5066% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5067% ExceptionInfo *exception)
5068%
5069% A description of each parameter follows:
5070%
5071% o image: the image.
5072%
5073% o exception: return any errors or warnings in this structure.
5074%
5075*/
5076static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5077 ExceptionInfo *exception)
5078{
5079 CacheInfo
5080 *cache_info;
5081
5082 long
5083 id;
5084
5085 MagickBooleanType
5086 status;
5087
5088 cache_info=(CacheInfo *) image->cache;
5089 id=GetOpenMPThreadId();
5090 assert(id < (long) cache_info->number_threads);
5091 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5092 exception);
5093 return(status);
5094}
5095
5096/*
5097%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5098% %
5099% %
5100% %
5101% S y n c A u t h e n t i c P i x e l s %
5102% %
5103% %
5104% %
5105%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5106%
5107% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5108% The method returns MagickTrue if the pixel region is flushed, otherwise
5109% MagickFalse.
5110%
5111% The format of the SyncAuthenticPixels() method is:
5112%
5113% MagickBooleanType SyncAuthenticPixels(Image *image,
5114% ExceptionInfo *exception)
5115%
5116% A description of each parameter follows:
5117%
5118% o image: the image.
5119%
5120% o exception: return any errors or warnings in this structure.
5121%
5122*/
5123MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5124 ExceptionInfo *exception)
5125{
5126 CacheInfo
5127 *cache_info;
5128
5129 assert(image != (Image *) NULL);
5130 assert(image->signature == MagickSignature);
5131 if (image->debug != MagickFalse)
5132 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5133 assert(image->cache != (Cache) NULL);
5134 cache_info=(CacheInfo *) image->cache;
5135 assert(cache_info->signature == MagickSignature);
5136 if (cache_info->methods.sync_authentic_pixels_handler ==
5137 (SyncAuthenticPixelsHandler) NULL)
5138 return(MagickFalse);
5139 return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
5140}
5141
5142/*
5143%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5144% %
5145% %
5146% %
5147+ W r i t e P i x e l C a c h e I n d e x e s %
5148% %
5149% %
5150% %
5151%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5152%
5153% WritePixelCacheIndexes() writes the colormap indexes to the specified
5154% region of the pixel cache.
5155%
5156% The format of the WritePixelCacheIndexes() method is:
5157%
5158% MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5159% NexusInfo *nexus_info,ExceptionInfo *exception)
5160%
5161% A description of each parameter follows:
5162%
5163% o cache_info: the pixel cache.
5164%
5165% o nexus_info: the cache nexus to write the colormap indexes.
5166%
5167% o exception: return any errors or warnings in this structure.
5168%
5169*/
5170static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5171 NexusInfo *nexus_info,ExceptionInfo *exception)
5172{
5173 MagickOffsetType
5174 count,
5175 offset;
5176
5177 MagickSizeType
5178 length,
5179 number_pixels;
5180
5181 register const IndexPacket
5182 *__restrict p;
5183
5184 register long
5185 y;
5186
5187 unsigned long
5188 rows;
5189
5190 if (cache_info->debug != MagickFalse)
5191 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
5192 cache_info->filename);
5193 if (cache_info->active_index_channel == MagickFalse)
5194 return(MagickFalse);
5195 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5196 return(MagickTrue);
5197 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5198 nexus_info->region.x;
5199 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
5200 rows=nexus_info->region.height;
5201 number_pixels=(MagickSizeType) length*rows;
5202 if ((cache_info->columns == nexus_info->region.width) &&
5203 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5204 {
5205 length=number_pixels;
5206 rows=1UL;
5207 }
5208 p=nexus_info->indexes;
5209 switch (cache_info->type)
5210 {
5211 case MemoryCache:
5212 case MapCache:
5213 {
5214 register IndexPacket
5215 *__restrict q;
5216
5217 /*
5218 Write indexes to memory.
5219 */
5220 q=cache_info->indexes+offset;
5221 for (y=0; y < (long) rows; y++)
5222 {
5223 (void) CopyMagickMemory(q,p,(size_t) length);
5224 p+=nexus_info->region.width;
5225 q+=cache_info->columns;
5226 }
5227 break;
5228 }
5229 case DiskCache:
5230 {
5231 /*
5232 Write indexes to disk.
5233 */
5234 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5235 {
5236 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5237 cache_info->cache_filename);
5238 return(MagickFalse);
5239 }
5240 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
5241 for (y=0; y < (long) rows; y++)
5242 {
5243 count=WritePixelCacheRegion(cache_info,cache_info->offset+number_pixels*
5244 sizeof(PixelPacket)+offset*sizeof(*p),length,
5245 (const unsigned char *) p);
5246 if ((MagickSizeType) count < length)
5247 break;
5248 p+=nexus_info->region.width;
5249 offset+=cache_info->columns;
5250 }
5251 if (y < (long) rows)
5252 {
5253 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5254 cache_info->cache_filename);
5255 return(MagickFalse);
5256 }
5257 break;
5258 }
5259 default:
5260 break;
5261 }
5262 if ((cache_info->debug != MagickFalse) &&
5263 (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5264 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
5265 cache_info->filename,nexus_info->region.width,nexus_info->region.height,
5266 nexus_info->region.x,nexus_info->region.y);
5267 return(MagickTrue);
5268}
5269
5270/*
5271%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5272% %
5273% %
5274% %
5275+ W r i t e C a c h e P i x e l s %
5276% %
5277% %
5278% %
5279%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5280%
5281% WritePixelCachePixels() writes image pixels to the specified region of the
5282% pixel cache.
5283%
5284% The format of the WritePixelCachePixels() method is:
5285%
5286% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5287% NexusInfo *nexus_info,ExceptionInfo *exception)
5288%
5289% A description of each parameter follows:
5290%
5291% o cache_info: the pixel cache.
5292%
5293% o nexus_info: the cache nexus to write the pixels.
5294%
5295% o exception: return any errors or warnings in this structure.
5296%
5297*/
5298static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5299 NexusInfo *nexus_info,ExceptionInfo *exception)
5300{
5301 MagickOffsetType
5302 count,
5303 offset;
5304
5305 MagickSizeType
5306 length,
5307 number_pixels;
5308
5309 register long
5310 y;
5311
5312 register const PixelPacket
5313 *__restrict p;
5314
5315 unsigned long
5316 rows;
5317
5318 if (cache_info->debug != MagickFalse)
5319 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
5320 cache_info->filename);
5321 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5322 return(MagickTrue);
5323 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5324 nexus_info->region.x;
5325 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
5326 rows=nexus_info->region.height;
5327 number_pixels=length*rows;
5328 if ((cache_info->columns == nexus_info->region.width) &&
5329 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5330 {
5331 length=number_pixels;
5332 rows=1UL;
5333 }
5334 p=nexus_info->pixels;
5335 switch (cache_info->type)
5336 {
5337 case MemoryCache:
5338 case MapCache:
5339 {
5340 register PixelPacket
5341 *__restrict q;
5342
5343 /*
5344 Write pixels to memory.
5345 */
5346 q=cache_info->pixels+offset;
5347 for (y=0; y < (long) rows; y++)
5348 {
5349 (void) CopyMagickMemory(q,p,(size_t) length);
5350 p+=nexus_info->region.width;
5351 q+=cache_info->columns;
5352 }
5353 break;
5354 }
5355 case DiskCache:
5356 {
5357 /*
5358 Write pixels to disk.
5359 */
5360 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5361 {
5362 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5363 cache_info->cache_filename);
5364 return(MagickFalse);
5365 }
5366 for (y=0; y < (long) rows; y++)
5367 {
5368 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5369 sizeof(*p),length,(const unsigned char *) p);
5370 if ((MagickSizeType) count < length)
5371 break;
5372 p+=nexus_info->region.width;
5373 offset+=cache_info->columns;
5374 }
5375 if (y < (long) rows)
5376 {
5377 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5378 cache_info->cache_filename);
5379 return(MagickFalse);
5380 }
5381 break;
5382 }
5383 default:
5384 break;
5385 }
5386 if ((cache_info->debug != MagickFalse) &&
5387 (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5388 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
5389 cache_info->filename,nexus_info->region.width,nexus_info->region.height,
5390 nexus_info->region.x,nexus_info->region.y);
5391 return(MagickTrue);
5392}