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