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