blob: 87217383440c9d2a4a39d01ea6cba4eac60a8fe1 [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);
cristyf84a1932010-01-03 18:00:18 +0000208 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 }
cristyf84a1932010-01-03 18:00:18 +0000216 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);
cristyf84a1932010-01-03 18:00:18 +0000314 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;
cristyf84a1932010-01-03 18:00:18 +0000318 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
cristyf84a1932010-01-03 18:00:18 +0000603 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);
cristyf84a1932010-01-03 18:00:18 +0000607 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;
cristyf84a1932010-01-03 18:00:18 +0000622 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000623 if (cache_resources == (SplayTreeInfo *) NULL)
624 {
cristyf84a1932010-01-03 18:00:18 +0000625 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 */
cristyf84a1932010-01-03 18:00:18 +0000651 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 */
cristyf84a1932010-01-03 18:00:18 +0000679 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000680 if (cache_info->file != -1)
681 {
cristyf84a1932010-01-03 18:00:18 +0000682 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 {
cristyf84a1932010-01-03 18:00:18 +0000716 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);
cristyf84a1932010-01-03 18:00:18 +0000722 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)
cristyf84a1932010-01-03 18:00:18 +0000737 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000738 cache_info->timestamp=time(0);
739 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
740 {
cristyf84a1932010-01-03 18:00:18 +0000741 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000742 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)
cristyf84a1932010-01-03 18:00:18 +0000765 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000766#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)
cristyf84a1932010-01-03 18:00:18 +0000781 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000782 cache_info->timestamp=time(0);
783 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
784 {
cristyf84a1932010-01-03 18:00:18 +0000785 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000786 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)
cristyf84a1932010-01-03 18:00:18 +0000809 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000810#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);
cristyf84a1932010-01-03 18:00:18 +00001533 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001534 cache_info->reference_count--;
1535 if (cache_info->reference_count != 0)
1536 {
cristyf84a1932010-01-03 18:00:18 +00001537 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001538 return((Cache) NULL);
1539 }
cristyf84a1932010-01-03 18:00:18 +00001540 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001541 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;
cristyf84a1932010-01-03 18:00:18 +00002120 LockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002121 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;
cristyf84a1932010-01-03 18:00:18 +00002130 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 }
cristyf84a1932010-01-03 18:00:18 +00002161 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 }
cristyf84a1932010-01-03 18:00:18 +00002176 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002177 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%
cristyf84a1932010-01-03 18:00:18 +00002739% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2740% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002741%
2742% A description of each parameter follows:
2743%
2744% o image: the image.
2745%
2746% o length: the pixel cache length.
2747%
cristyf84a1932010-01-03 18:00:18 +00002748% o exception: return any errors or warnings in this structure.
2749%
cristy056ba772010-01-02 23:33:54 +00002750*/
cristyf84a1932010-01-03 18:00:18 +00002751MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2752 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002753{
2754 CacheInfo
2755 *cache_info;
2756
2757 assert(image != (const Image *) NULL);
2758 assert(image->signature == MagickSignature);
2759 if (image->debug != MagickFalse)
2760 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2761 assert(image->cache != (Cache) NULL);
cristyf84a1932010-01-03 18:00:18 +00002762 cache_info=GetImagePixelCache(image,MagickTrue,exception);
cristy056ba772010-01-02 23:33:54 +00002763 assert(cache_info->signature == MagickSignature);
2764 *length=0;
2765 if ((cache_info->storage_class != MemoryCache) &&
2766 (cache_info->storage_class != MapCache))
2767 return((void *) NULL);
2768 *length=cache_info->length;
2769 return((void *) cache_info->pixels);
2770}
2771
2772/*
2773%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2774% %
2775% %
2776% %
cristyb32b90a2009-09-07 21:45:48 +00002777+ 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 +00002778% %
2779% %
2780% %
2781%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2782%
2783% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2784%
2785% The format of the GetPixelCacheStorageClass() method is:
2786%
2787% ClassType GetPixelCacheStorageClass(Cache cache)
2788%
2789% A description of each parameter follows:
2790%
2791% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2792%
2793% o cache: the pixel cache.
2794%
2795*/
2796MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
2797{
2798 CacheInfo
2799 *cache_info;
2800
2801 assert(cache != (Cache) NULL);
2802 cache_info=(CacheInfo *) cache;
2803 assert(cache_info->signature == MagickSignature);
2804 if (cache_info->debug != MagickFalse)
2805 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2806 cache_info->filename);
2807 return(cache_info->storage_class);
2808}
2809
2810/*
2811%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2812% %
2813% %
2814% %
cristyb32b90a2009-09-07 21:45:48 +00002815+ G e t P i x e l C a c h e T i l e S i z e %
2816% %
2817% %
2818% %
2819%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2820%
2821% GetPixelCacheTileSize() returns the pixel cache tile size.
2822%
2823% The format of the GetPixelCacheTileSize() method is:
2824%
2825% void GetPixelCacheTileSize(const Image *image,unsigned long *width,
2826% unsigned long *height)
2827%
2828% A description of each parameter follows:
2829%
2830% o image: the image.
2831%
2832% o width: the optimize cache tile width in pixels.
2833%
2834% o height: the optimize cache tile height in pixels.
2835%
2836*/
2837MagickExport void GetPixelCacheTileSize(const Image *image,unsigned long *width,
2838 unsigned long *height)
2839{
2840 CacheInfo
2841 *cache_info;
2842
2843 assert(image != (Image *) NULL);
2844 assert(image->signature == MagickSignature);
2845 if (image->debug != MagickFalse)
2846 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2847 assert(image->cache != (Cache) NULL);
2848 cache_info=(CacheInfo *) image->cache;
2849 assert(cache_info->signature == MagickSignature);
2850 *width=2048UL/sizeof(PixelPacket);
2851 if (GetPixelCacheType(image) == DiskCache)
cristydaa97692009-09-13 02:10:35 +00002852 *width=8192UL/sizeof(PixelPacket);
cristyb32b90a2009-09-07 21:45:48 +00002853 *height=(*width);
2854}
2855
2856/*
2857%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2858% %
2859% %
2860% %
2861+ G e t P i x e l C a c h e T y p e %
2862% %
2863% %
2864% %
2865%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2866%
2867% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2868%
2869% The format of the GetPixelCacheType() method is:
2870%
2871% CacheType GetPixelCacheType(const Image *image)
2872%
2873% A description of each parameter follows:
2874%
2875% o image: the image.
2876%
2877*/
2878MagickExport CacheType GetPixelCacheType(const Image *image)
2879{
2880 CacheInfo
2881 *cache_info;
2882
2883 assert(image != (Image *) NULL);
2884 assert(image->signature == MagickSignature);
2885 if (image->debug != MagickFalse)
2886 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2887 assert(image->cache != (Cache) NULL);
2888 cache_info=(CacheInfo *) image->cache;
2889 assert(cache_info->signature == MagickSignature);
2890 return(cache_info->type);
2891}
2892
2893/*
2894%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2895% %
2896% %
2897% %
cristy3ed852e2009-09-05 21:47:34 +00002898+ 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 %
2899% %
2900% %
2901% %
2902%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2903%
2904% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2905% pixel cache. A virtual pixel is any pixel access that is outside the
2906% boundaries of the image cache.
2907%
2908% The format of the GetPixelCacheVirtualMethod() method is:
2909%
2910% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2911%
2912% A description of each parameter follows:
2913%
2914% o image: the image.
2915%
2916*/
2917MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2918{
2919 CacheInfo
2920 *cache_info;
2921
2922 assert(image != (Image *) NULL);
2923 assert(image->signature == MagickSignature);
2924 if (image->debug != MagickFalse)
2925 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2926 assert(image->cache != (Cache) NULL);
2927 cache_info=(CacheInfo *) image->cache;
2928 assert(cache_info->signature == MagickSignature);
2929 return(cache_info->virtual_pixel_method);
2930}
2931
2932/*
2933%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2934% %
2935% %
2936% %
2937+ 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 %
2938% %
2939% %
2940% %
2941%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2942%
2943% GetVirtualIndexesFromCache() returns the indexes associated with the last
2944% call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2945%
2946% The format of the GetVirtualIndexesFromCache() method is:
2947%
2948% IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2949%
2950% A description of each parameter follows:
2951%
2952% o image: the image.
2953%
2954*/
2955static const IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2956{
2957 CacheInfo
2958 *cache_info;
2959
2960 const IndexPacket
2961 *indexes;
2962
2963 long
2964 id;
2965
2966 if (image->debug != MagickFalse)
2967 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2968 cache_info=(CacheInfo *) image->cache;
2969 id=GetOpenMPThreadId();
2970 assert(id < (long) cache_info->number_threads);
2971 indexes=GetVirtualIndexesFromNexus(image->cache,cache_info->nexus_info[id]);
2972 return(indexes);
2973}
2974
2975/*
2976%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2977% %
2978% %
2979% %
2980+ 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 %
2981% %
2982% %
2983% %
2984%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2985%
2986% GetVirtualIndexesFromNexus() returns the indexes associated with the
2987% specified cache nexus.
2988%
2989% The format of the GetVirtualIndexesFromNexus() method is:
2990%
2991% const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2992% NexusInfo *nexus_info)
2993%
2994% A description of each parameter follows:
2995%
2996% o cache: the pixel cache.
2997%
2998% o nexus_info: the cache nexus to return the colormap indexes.
2999%
3000*/
3001MagickExport const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
3002 NexusInfo *nexus_info)
3003{
3004 CacheInfo
3005 *cache_info;
3006
3007 if (cache == (Cache) NULL)
3008 return((IndexPacket *) NULL);
3009 cache_info=(CacheInfo *) cache;
3010 assert(cache_info->signature == MagickSignature);
3011 if (cache_info->storage_class == UndefinedClass)
3012 return((IndexPacket *) NULL);
3013 return(nexus_info->indexes);
3014}
3015
3016/*
3017%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3018% %
3019% %
3020% %
3021% G e t V i r t u a l I n d e x Q u e u e %
3022% %
3023% %
3024% %
3025%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3026%
3027% GetVirtualIndexQueue() returns the virtual black channel or the
3028% colormap indexes associated with the last call to QueueAuthenticPixels() or
3029% GetVirtualPixels(). NULL is returned if the black channel or colormap
3030% indexes are not available.
3031%
3032% The format of the GetVirtualIndexQueue() method is:
3033%
3034% const IndexPacket *GetVirtualIndexQueue(const Image *image)
3035%
3036% A description of each parameter follows:
3037%
3038% o image: the image.
3039%
3040*/
3041MagickExport const IndexPacket *GetVirtualIndexQueue(const Image *image)
3042{
3043 CacheInfo
3044 *cache_info;
3045
3046 assert(image != (const Image *) NULL);
3047 assert(image->signature == MagickSignature);
3048 if (image->debug != MagickFalse)
3049 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3050 assert(image->cache != (Cache) NULL);
3051 cache_info=(CacheInfo *) image->cache;
3052 assert(cache_info->signature == MagickSignature);
3053 if (cache_info->methods.get_virtual_indexes_from_handler ==
3054 (GetVirtualIndexesFromHandler) NULL)
3055 return((IndexPacket *) NULL);
3056 return(cache_info->methods.get_virtual_indexes_from_handler(image));
3057}
3058
3059/*
3060%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3061% %
3062% %
3063% %
3064+ 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 %
3065% %
3066% %
3067% %
3068%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3069%
3070% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3071% pixel cache as defined by the geometry parameters. A pointer to the pixels
3072% is returned if the pixels are transferred, otherwise a NULL is returned.
3073%
3074% The format of the GetVirtualPixelsFromNexus() method is:
3075%
3076% PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
3077% const VirtualPixelMethod method,const long x,const long y,
3078% const unsigned long columns,const unsigned long rows,
3079% NexusInfo *nexus_info,ExceptionInfo *exception)
3080%
3081% A description of each parameter follows:
3082%
3083% o image: the image.
3084%
3085% o virtual_pixel_method: the virtual pixel method.
3086%
3087% o x,y,columns,rows: These values define the perimeter of a region of
3088% pixels.
3089%
3090% o nexus_info: the cache nexus to acquire.
3091%
3092% o exception: return any errors or warnings in this structure.
3093%
3094*/
3095
3096static long
3097 DitherMatrix[64] =
3098 {
3099 0, 48, 12, 60, 3, 51, 15, 63,
3100 32, 16, 44, 28, 35, 19, 47, 31,
3101 8, 56, 4, 52, 11, 59, 7, 55,
3102 40, 24, 36, 20, 43, 27, 39, 23,
3103 2, 50, 14, 62, 1, 49, 13, 61,
3104 34, 18, 46, 30, 33, 17, 45, 29,
3105 10, 58, 6, 54, 9, 57, 5, 53,
3106 42, 26, 38, 22, 41, 25, 37, 21
3107 };
3108
3109static inline long DitherX(const unsigned long columns,const long x)
3110{
3111 long
3112 index;
3113
3114 index=x+DitherMatrix[x & 0x07]-32L;
3115 if (index < 0L)
3116 return(0L);
3117 if (index >= (long) columns)
3118 return((long) columns-1L);
3119 return(index);
3120}
3121
3122static inline long DitherY(const unsigned long rows,const long y)
3123{
3124 long
3125 index;
3126
3127 index=y+DitherMatrix[y & 0x07]-32L;
3128 if (index < 0L)
3129 return(0L);
3130 if (index >= (long) rows)
3131 return((long) rows-1L);
3132 return(index);
3133}
3134
3135static inline long EdgeX(const unsigned long columns,const long x)
3136{
3137 if (x < 0L)
3138 return(0L);
3139 if (x >= (long) columns)
3140 return((long) columns-1L);
3141 return(x);
3142}
3143
3144static inline long EdgeY(const unsigned long rows,const long y)
3145{
3146 if (y < 0L)
3147 return(0L);
3148 if (y >= (long) rows)
3149 return((long) rows-1L);
3150 return(y);
3151}
3152
3153static inline long RandomX(const unsigned long columns,RandomInfo *random_info)
3154{
3155 return((long) (columns*GetPseudoRandomValue(random_info)));
3156}
3157
3158static inline long RandomY(const unsigned long rows,RandomInfo *random_info)
3159{
3160 return((long) (rows*GetPseudoRandomValue(random_info)));
3161}
3162
3163/*
3164 VirtualPixelModulo() computes the remainder of dividing offset by extent. It
3165 returns not only the quotient (tile the offset falls in) but also the positive
3166 remainer within that tile such that 0 <= remainder < extent. This method is
3167 essentially a ldiv() using a floored modulo division rather than the normal
3168 default truncated modulo division.
3169*/
3170static inline MagickModulo VirtualPixelModulo(const long offset,
3171 const unsigned long extent)
3172{
3173 MagickModulo
3174 modulo;
3175
3176 modulo.quotient=offset/(long) extent;
3177 if (offset < 0L)
3178 modulo.quotient--;
3179 modulo.remainder=offset-modulo.quotient*(long) extent;
3180 return(modulo);
3181}
3182
3183MagickExport const PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
3184 const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
3185 const unsigned long columns,const unsigned long rows,NexusInfo *nexus_info,
3186 ExceptionInfo *exception)
3187{
3188 CacheInfo
3189 *cache_info;
3190
3191 MagickOffsetType
3192 offset;
3193
3194 MagickSizeType
3195 length,
3196 number_pixels;
3197
3198 NexusInfo
3199 **virtual_nexus;
3200
3201 PixelPacket
3202 *pixels,
3203 virtual_pixel;
3204
3205 RectangleInfo
3206 region;
3207
3208 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003209 *restrict nexus_indexes;
cristy3ed852e2009-09-05 21:47:34 +00003210
3211 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003212 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003213
3214 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003215 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003216
3217 register long
3218 u,
3219 v;
3220
3221 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003222 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003223
3224 /*
3225 Acquire pixels.
3226 */
3227 if (image->debug != MagickFalse)
3228 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3229 cache_info=(CacheInfo *) image->cache;
3230 if (cache_info->type == UndefinedCache)
3231 return((const PixelPacket *) NULL);
3232 region.x=x;
3233 region.y=y;
3234 region.width=columns;
3235 region.height=rows;
3236 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
3237 if (pixels == (PixelPacket *) NULL)
3238 return((const PixelPacket *) NULL);
3239 offset=(MagickOffsetType) region.y*cache_info->columns+region.x;
3240 length=(MagickSizeType) (region.height-1)*cache_info->columns+region.width-1;
3241 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3242 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
3243 if ((x >= 0) && ((long) (x+columns) <= (long) cache_info->columns) &&
3244 (y >= 0) && ((long) (y+rows) <= (long) cache_info->rows))
3245 {
3246 MagickBooleanType
3247 status;
3248
3249 /*
3250 Pixel request is inside cache extents.
3251 */
3252 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
3253 return(pixels);
3254 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3255 if (status == MagickFalse)
3256 return((const PixelPacket *) NULL);
3257 if ((cache_info->storage_class == PseudoClass) ||
3258 (cache_info->colorspace == CMYKColorspace))
3259 {
3260 status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
3261 if (status == MagickFalse)
3262 return((const PixelPacket *) NULL);
3263 }
3264 return(pixels);
3265 }
3266 /*
3267 Pixel request is outside cache extents.
3268 */
3269 q=pixels;
3270 indexes=GetPixelCacheNexusIndexes(cache_info,nexus_info);
3271 virtual_nexus=AcquirePixelCacheNexus(1);
3272 if (virtual_nexus == (NexusInfo **) NULL)
3273 {
3274 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3275 "UnableToGetCacheNexus","`%s'",image->filename);
3276 return((const PixelPacket *) NULL);
3277 }
3278 switch (virtual_pixel_method)
3279 {
3280 case BlackVirtualPixelMethod:
3281 {
3282 virtual_pixel.red=0;
3283 virtual_pixel.green=0;
3284 virtual_pixel.blue=0;
3285 virtual_pixel.opacity=OpaqueOpacity;
3286 break;
3287 }
3288 case GrayVirtualPixelMethod:
3289 {
3290 virtual_pixel.red=(Quantum) QuantumRange/2;
3291 virtual_pixel.green=(Quantum) QuantumRange/2;
3292 virtual_pixel.blue=(Quantum) QuantumRange/2;
3293 virtual_pixel.opacity=(Quantum) OpaqueOpacity;
3294 break;
3295 }
3296 case TransparentVirtualPixelMethod:
3297 {
3298 virtual_pixel.red=(Quantum) 0;
3299 virtual_pixel.green=(Quantum) 0;
3300 virtual_pixel.blue=(Quantum) 0;
3301 virtual_pixel.opacity=(Quantum) TransparentOpacity;
3302 break;
3303 }
3304 case MaskVirtualPixelMethod:
3305 case WhiteVirtualPixelMethod:
3306 {
3307 virtual_pixel.red=(Quantum) QuantumRange;
3308 virtual_pixel.green=(Quantum) QuantumRange;
3309 virtual_pixel.blue=(Quantum) QuantumRange;
3310 virtual_pixel.opacity=OpaqueOpacity;
3311 break;
3312 }
3313 default:
3314 {
3315 virtual_pixel=image->background_color;
3316 break;
3317 }
3318 }
3319 for (v=0; v < (long) rows; v++)
3320 {
3321 for (u=0; u < (long) columns; u+=length)
3322 {
3323 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
3324 if ((((x+u) < 0) || ((x+u) >= (long) cache_info->columns)) ||
3325 (((y+v) < 0) || ((y+v) >= (long) cache_info->rows)) || (length == 0))
3326 {
3327 MagickModulo
3328 x_modulo,
3329 y_modulo;
3330
3331 /*
3332 Transfer a single pixel.
3333 */
3334 length=(MagickSizeType) 1;
3335 switch (virtual_pixel_method)
3336 {
3337 case BackgroundVirtualPixelMethod:
3338 case ConstantVirtualPixelMethod:
3339 case BlackVirtualPixelMethod:
3340 case GrayVirtualPixelMethod:
3341 case TransparentVirtualPixelMethod:
3342 case MaskVirtualPixelMethod:
3343 case WhiteVirtualPixelMethod:
3344 {
3345 p=(&virtual_pixel);
3346 break;
3347 }
3348 case EdgeVirtualPixelMethod:
3349 default:
3350 {
3351 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3352 EdgeX(cache_info->columns,x+u),EdgeY(cache_info->rows,y+v),
3353 1UL,1UL,virtual_nexus[0],exception);
3354 break;
3355 }
3356 case RandomVirtualPixelMethod:
3357 {
3358 if (cache_info->random_info == (RandomInfo *) NULL)
3359 cache_info->random_info=AcquireRandomInfo();
3360 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3361 RandomX(cache_info->columns,cache_info->random_info),
3362 RandomY(cache_info->rows,cache_info->random_info),1UL,1UL,
3363 virtual_nexus[0],exception);
3364 break;
3365 }
3366 case DitherVirtualPixelMethod:
3367 {
3368 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3369 DitherX(cache_info->columns,x+u),DitherY(cache_info->rows,y+v),
3370 1UL,1UL,virtual_nexus[0],exception);
3371 break;
3372 }
3373 case TileVirtualPixelMethod:
3374 {
3375 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3376 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3377 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3378 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3379 exception);
3380 break;
3381 }
3382 case MirrorVirtualPixelMethod:
3383 {
3384 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3385 if ((x_modulo.quotient & 0x01) == 1L)
3386 x_modulo.remainder=(long) cache_info->columns-
3387 x_modulo.remainder-1L;
3388 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3389 if ((y_modulo.quotient & 0x01) == 1L)
3390 y_modulo.remainder=(long) cache_info->rows-
3391 y_modulo.remainder-1L;
3392 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3393 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3394 exception);
3395 break;
3396 }
3397 case CheckerTileVirtualPixelMethod:
3398 {
3399 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3400 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3401 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3402 {
3403 p=(&virtual_pixel);
3404 break;
3405 }
3406 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3407 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3408 exception);
3409 break;
3410 }
3411 case HorizontalTileVirtualPixelMethod:
3412 {
3413 if (((y+v) < 0) || ((y+v) >= (long) cache_info->rows))
3414 {
3415 p=(&virtual_pixel);
3416 break;
3417 }
3418 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3419 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3420 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3421 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3422 exception);
3423 break;
3424 }
3425 case VerticalTileVirtualPixelMethod:
3426 {
3427 if (((x+u) < 0) || ((x+u) >= (long) cache_info->columns))
3428 {
3429 p=(&virtual_pixel);
3430 break;
3431 }
3432 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3433 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3434 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3435 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3436 exception);
3437 break;
3438 }
3439 case HorizontalTileEdgeVirtualPixelMethod:
3440 {
3441 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3442 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3443 x_modulo.remainder,EdgeY(cache_info->rows,y+v),1UL,1UL,
3444 virtual_nexus[0],exception);
3445 break;
3446 }
3447 case VerticalTileEdgeVirtualPixelMethod:
3448 {
3449 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3450 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3451 EdgeX(cache_info->columns,x+u),y_modulo.remainder,1UL,1UL,
3452 virtual_nexus[0],exception);
3453 break;
3454 }
3455 }
3456 if (p == (const PixelPacket *) NULL)
3457 break;
3458 *q++=(*p);
3459 if (indexes != (IndexPacket *) NULL)
3460 {
3461 nexus_indexes=GetVirtualIndexesFromNexus(cache_info,
3462 virtual_nexus[0]);
3463 if (nexus_indexes != (const IndexPacket *) NULL)
3464 *indexes++=(*nexus_indexes);
3465 }
3466 continue;
3467 }
3468 /*
3469 Transfer a run of pixels.
3470 */
3471 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,
3472 (unsigned long) length,1UL,virtual_nexus[0],exception);
3473 if (p == (const PixelPacket *) NULL)
3474 break;
3475 (void) CopyMagickMemory(q,p,(size_t) length*sizeof(*p));
3476 q+=length;
3477 if (indexes != (IndexPacket *) NULL)
3478 {
3479 nexus_indexes=GetVirtualIndexesFromNexus(cache_info,virtual_nexus[0]);
3480 if (nexus_indexes != (const IndexPacket *) NULL)
3481 {
3482 (void) CopyMagickMemory(indexes,nexus_indexes,(size_t) length*
3483 sizeof(*nexus_indexes));
3484 indexes+=length;
3485 }
3486 }
3487 }
3488 }
3489 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3490 return(pixels);
3491}
3492
3493/*
3494%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3495% %
3496% %
3497% %
3498+ G e t V i r t u a l P i x e l C a c h e %
3499% %
3500% %
3501% %
3502%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3503%
3504% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3505% cache as defined by the geometry parameters. A pointer to the pixels
3506% is returned if the pixels are transferred, otherwise a NULL is returned.
3507%
3508% The format of the GetVirtualPixelCache() method is:
3509%
3510% const PixelPacket *GetVirtualPixelCache(const Image *image,
3511% const VirtualPixelMethod virtual_pixel_method,const long x,
3512% const long y,const unsigned long columns,const unsigned long rows,
3513% ExceptionInfo *exception)
3514%
3515% A description of each parameter follows:
3516%
3517% o image: the image.
3518%
3519% o virtual_pixel_method: the virtual pixel method.
3520%
3521% o x,y,columns,rows: These values define the perimeter of a region of
3522% pixels.
3523%
3524% o exception: return any errors or warnings in this structure.
3525%
3526*/
3527static const PixelPacket *GetVirtualPixelCache(const Image *image,
3528 const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
3529 const unsigned long columns,const unsigned long rows,ExceptionInfo *exception)
3530{
3531 CacheInfo
3532 *cache_info;
3533
3534 const PixelPacket
3535 *pixels;
3536
3537 long
3538 id;
3539
3540 if (image->debug != MagickFalse)
3541 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3542 cache_info=(CacheInfo *) image->cache;
3543 id=GetOpenMPThreadId();
3544 assert(id < (long) cache_info->number_threads);
3545 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3546 cache_info->nexus_info[id],exception);
3547 return(pixels);
3548}
3549
3550/*
3551%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3552% %
3553% %
3554% %
3555% G e t V i r t u a l P i x e l Q u e u e %
3556% %
3557% %
3558% %
3559%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3560%
3561% GetVirtualPixelQueue() returns the virtual pixels associated with the
3562% last call to QueueAuthenticPixels() or GetVirtualPixels().
3563%
3564% The format of the GetVirtualPixelQueue() method is:
3565%
3566% const PixelPacket *GetVirtualPixelQueue(const Image image)
3567%
3568% A description of each parameter follows:
3569%
3570% o image: the image.
3571%
3572*/
3573MagickExport const PixelPacket *GetVirtualPixelQueue(const Image *image)
3574{
3575 CacheInfo
3576 *cache_info;
3577
3578 assert(image != (const Image *) NULL);
3579 assert(image->signature == MagickSignature);
3580 if (image->debug != MagickFalse)
3581 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3582 assert(image->cache != (Cache) NULL);
3583 cache_info=(CacheInfo *) image->cache;
3584 assert(cache_info->signature == MagickSignature);
3585 if (cache_info->methods.get_virtual_pixels_handler ==
3586 (GetVirtualPixelsHandler) NULL)
3587 return((PixelPacket *) NULL);
3588 return(cache_info->methods.get_virtual_pixels_handler(image));
3589}
3590
3591/*
3592%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3593% %
3594% %
3595% %
3596% G e t V i r t u a l P i x e l s %
3597% %
3598% %
3599% %
3600%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3601%
3602% GetVirtualPixels() returns an immutable pixel region. If the
3603% region is successfully accessed, a pointer to it is returned, otherwise
3604% NULL is returned. The returned pointer may point to a temporary working
3605% copy of the pixels or it may point to the original pixels in memory.
3606% Performance is maximized if the selected region is part of one row, or one
3607% or more full rows, since there is opportunity to access the pixels in-place
3608% (without a copy) if the image is in RAM, or in a memory-mapped file. The
3609% returned pointer should *never* be deallocated by the user.
3610%
3611% Pixels accessed via the returned pointer represent a simple array of type
3612% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
3613% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access
3614% the black color component or to obtain the colormap indexes (of type
3615% IndexPacket) corresponding to the region.
3616%
3617% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3618%
3619% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3620% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3621% GetCacheViewAuthenticPixels() instead.
3622%
3623% The format of the GetVirtualPixels() method is:
3624%
3625% const PixelPacket *GetVirtualPixels(const Image *image,const long x,
3626% const long y,const unsigned long columns,const unsigned long rows,
3627% ExceptionInfo *exception)
3628%
3629% A description of each parameter follows:
3630%
3631% o image: the image.
3632%
3633% o x,y,columns,rows: These values define the perimeter of a region of
3634% pixels.
3635%
3636% o exception: return any errors or warnings in this structure.
3637%
3638*/
3639MagickExport const PixelPacket *GetVirtualPixels(const Image *image,
3640 const long x,const long y,const unsigned long columns,
3641 const unsigned long rows,ExceptionInfo *exception)
3642{
3643 CacheInfo
3644 *cache_info;
3645
3646 const PixelPacket
3647 *pixels;
3648
3649 assert(image != (const Image *) NULL);
3650 assert(image->signature == MagickSignature);
3651 if (image->debug != MagickFalse)
3652 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3653 assert(image->cache != (Cache) NULL);
3654 cache_info=(CacheInfo *) image->cache;
3655 assert(cache_info->signature == MagickSignature);
3656 if (cache_info->methods.get_virtual_pixel_handler ==
3657 (GetVirtualPixelHandler) NULL)
3658 return((const PixelPacket *) NULL);
3659 pixels=cache_info->methods.get_virtual_pixel_handler(image,
3660 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception);
3661 return(pixels);
3662}
3663
3664/*
3665%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3666% %
3667% %
3668% %
3669+ 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 %
3670% %
3671% %
3672% %
3673%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3674%
3675% GetVirtualPixelsCache() returns the pixels associated with the last call
3676% to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3677%
3678% The format of the GetVirtualPixelsCache() method is:
3679%
3680% PixelPacket *GetVirtualPixelsCache(const Image *image)
3681%
3682% A description of each parameter follows:
3683%
3684% o image: the image.
3685%
3686*/
3687static const PixelPacket *GetVirtualPixelsCache(const Image *image)
3688{
3689 CacheInfo
3690 *cache_info;
3691
3692 const PixelPacket
3693 *pixels;
3694
3695 long
3696 id;
3697
3698 if (image->debug != MagickFalse)
3699 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3700 cache_info=(CacheInfo *) image->cache;
3701 id=GetOpenMPThreadId();
3702 assert(id < (long) cache_info->number_threads);
3703 pixels=GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]);
3704 return(pixels);
3705}
3706
3707/*
3708%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3709% %
3710% %
3711% %
3712+ G e t V i r t u a l P i x e l s N e x u s %
3713% %
3714% %
3715% %
3716%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3717%
3718% GetVirtualPixelsNexus() returns the pixels associated with the specified
3719% cache nexus.
3720%
3721% The format of the GetVirtualPixelsNexus() method is:
3722%
3723% const IndexPacket *GetVirtualPixelsNexus(const Cache cache,
3724% NexusInfo *nexus_info)
3725%
3726% A description of each parameter follows:
3727%
3728% o cache: the pixel cache.
3729%
3730% o nexus_info: the cache nexus to return the colormap pixels.
3731%
3732*/
3733MagickExport const PixelPacket *GetVirtualPixelsNexus(const Cache cache,
3734 NexusInfo *nexus_info)
3735{
3736 CacheInfo
3737 *cache_info;
3738
3739 if (cache == (Cache) NULL)
3740 return((PixelPacket *) NULL);
3741 cache_info=(CacheInfo *) cache;
3742 assert(cache_info->signature == MagickSignature);
3743 if (cache_info->storage_class == UndefinedClass)
3744 return((PixelPacket *) NULL);
3745 return((const PixelPacket *) nexus_info->pixels);
3746}
3747
3748/*
3749%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3750% %
3751% %
3752% %
3753+ M a s k P i x e l C a c h e N e x u s %
3754% %
3755% %
3756% %
3757%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3758%
3759% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3760% The method returns MagickTrue if the pixel region is masked, otherwise
3761% MagickFalse.
3762%
3763% The format of the MaskPixelCacheNexus() method is:
3764%
3765% MagickBooleanType MaskPixelCacheNexus(Image *image,
3766% NexusInfo *nexus_info,ExceptionInfo *exception)
3767%
3768% A description of each parameter follows:
3769%
3770% o image: the image.
3771%
3772% o nexus_info: the cache nexus to clip.
3773%
3774% o exception: return any errors or warnings in this structure.
3775%
3776*/
3777
3778static inline void MagickPixelCompositeMask(const MagickPixelPacket *p,
3779 const MagickRealType alpha,const MagickPixelPacket *q,
3780 const MagickRealType beta,MagickPixelPacket *composite)
3781{
3782 MagickRealType
3783 gamma;
3784
3785 if (alpha == TransparentOpacity)
3786 {
3787 *composite=(*q);
3788 return;
3789 }
3790 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3791 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3792 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3793 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3794 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3795 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3796 composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
3797}
3798
3799static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3800 ExceptionInfo *exception)
3801{
3802 CacheInfo
3803 *cache_info;
3804
3805 MagickPixelPacket
3806 alpha,
3807 beta;
3808
3809 MagickSizeType
3810 number_pixels;
3811
3812 NexusInfo
3813 **clip_nexus,
3814 **image_nexus;
3815
3816 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003817 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003818
3819 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003820 *restrict nexus_indexes,
3821 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003822
3823 register long
3824 i;
3825
3826 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003827 *restrict p,
3828 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003829
3830 /*
3831 Apply clip mask.
3832 */
3833 if (image->debug != MagickFalse)
3834 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3835 if (image->mask == (Image *) NULL)
3836 return(MagickFalse);
3837 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
3838 if (cache_info == (Cache) NULL)
3839 return(MagickFalse);
3840 image_nexus=AcquirePixelCacheNexus(1);
3841 clip_nexus=AcquirePixelCacheNexus(1);
3842 if ((image_nexus == (NexusInfo **) NULL) ||
3843 (clip_nexus == (NexusInfo **) NULL))
3844 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
3845 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,nexus_info->region.y,
3846 nexus_info->region.width,nexus_info->region.height,image_nexus[0],
3847 exception);
3848 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
3849 q=nexus_info->pixels;
3850 nexus_indexes=nexus_info->indexes;
3851 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3852 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3853 nexus_info->region.height,clip_nexus[0],&image->exception);
3854 GetMagickPixelPacket(image,&alpha);
3855 GetMagickPixelPacket(image,&beta);
3856 number_pixels=(MagickSizeType) nexus_info->region.width*
3857 nexus_info->region.height;
3858 for (i=0; i < (long) number_pixels; i++)
3859 {
3860 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
3861 break;
3862 SetMagickPixelPacket(image,p,indexes+i,&alpha);
3863 SetMagickPixelPacket(image,q,nexus_indexes+i,&beta);
3864 MagickPixelCompositeMask(&beta,(MagickRealType) PixelIntensityToQuantum(r),
3865 &alpha,alpha.opacity,&beta);
3866 q->red=RoundToQuantum(beta.red);
3867 q->green=RoundToQuantum(beta.green);
3868 q->blue=RoundToQuantum(beta.blue);
3869 q->opacity=RoundToQuantum(beta.opacity);
3870 if (cache_info->active_index_channel != MagickFalse)
3871 nexus_indexes[i]=indexes[i];
3872 p++;
3873 q++;
3874 r++;
3875 }
3876 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3877 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
3878 if (i < (long) number_pixels)
3879 return(MagickFalse);
3880 return(MagickTrue);
3881}
3882
3883/*
3884%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3885% %
3886% %
3887% %
3888+ O p e n P i x e l C a c h e %
3889% %
3890% %
3891% %
3892%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3893%
3894% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3895% dimensions, allocating space for the image pixels and optionally the
3896% colormap indexes, and memory mapping the cache if it is disk based. The
3897% cache nexus array is initialized as well.
3898%
3899% The format of the OpenPixelCache() method is:
3900%
3901% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3902% ExceptionInfo *exception)
3903%
3904% A description of each parameter follows:
3905%
3906% o image: the image.
3907%
3908% o mode: ReadMode, WriteMode, or IOMode.
3909%
3910% o exception: return any errors or warnings in this structure.
3911%
3912*/
3913
3914static inline void AcquirePixelCachePixels(CacheInfo *cache_info)
3915{
3916 cache_info->mapped=MagickFalse;
3917 cache_info->pixels=(PixelPacket *) AcquireMagickMemory((size_t)
3918 cache_info->length);
3919 if (cache_info->pixels == (PixelPacket *) NULL)
3920 {
3921 cache_info->mapped=MagickTrue;
3922 cache_info->pixels=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
3923 cache_info->length);
3924 }
3925}
3926
3927static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3928{
3929 CacheInfo
3930 *cache_info;
3931
3932 MagickOffsetType
3933 count,
3934 extent,
3935 offset;
3936
3937 cache_info=(CacheInfo *) image->cache;
3938 if (image->debug != MagickFalse)
3939 {
3940 char
3941 format[MaxTextExtent],
3942 message[MaxTextExtent];
3943
cristyb9080c92009-12-01 20:13:26 +00003944 (void) FormatMagickSize(length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00003945 (void) FormatMagickString(message,MaxTextExtent,
3946 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3947 cache_info->cache_filename,cache_info->file,format);
3948 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3949 }
3950 if (length != (MagickSizeType) ((MagickOffsetType) length))
3951 return(MagickFalse);
3952 extent=(MagickOffsetType) MagickSeek(cache_info->file,0,SEEK_END);
3953 if (extent < 0)
3954 return(MagickFalse);
3955 if ((MagickSizeType) extent >= length)
3956 return(MagickTrue);
3957 offset=(MagickOffsetType) length-1;
3958 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3959 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3960}
3961
3962static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3963 ExceptionInfo *exception)
3964{
3965 char
3966 format[MaxTextExtent],
3967 message[MaxTextExtent];
3968
3969 CacheInfo
3970 *cache_info,
3971 source_info;
3972
3973 MagickSizeType
3974 length,
3975 number_pixels;
3976
3977 MagickStatusType
3978 status;
3979
3980 size_t
3981 packet_size;
3982
3983 unsigned long
3984 columns;
3985
3986 if (image->debug != MagickFalse)
3987 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3988 if ((image->columns == 0) || (image->rows == 0))
3989 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3990 cache_info=(CacheInfo *) image->cache;
3991 source_info=(*cache_info);
3992 source_info.file=(-1);
3993 (void) FormatMagickString(cache_info->filename,MaxTextExtent,"%s[%ld]",
3994 image->filename,GetImageIndexInList(image));
cristy87528ea2009-09-10 14:53:56 +00003995 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +00003996 cache_info->rows=image->rows;
3997 cache_info->columns=image->columns;
3998 cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
3999 (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
4000 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4001 packet_size=sizeof(PixelPacket);
4002 if (cache_info->active_index_channel != MagickFalse)
4003 packet_size+=sizeof(IndexPacket);
4004 length=number_pixels*packet_size;
4005 columns=(unsigned long) (length/cache_info->rows/packet_size);
4006 if (cache_info->columns != columns)
4007 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4008 image->filename);
4009 cache_info->length=length;
4010 status=AcquireMagickResource(AreaResource,cache_info->length);
4011 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4012 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4013 {
4014 status=AcquireMagickResource(MemoryResource,cache_info->length);
4015 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4016 (cache_info->type == MemoryCache))
4017 {
4018 AcquirePixelCachePixels(cache_info);
4019 if (cache_info->pixels == (PixelPacket *) NULL)
4020 cache_info->pixels=source_info.pixels;
4021 else
4022 {
4023 /*
4024 Create memory pixel cache.
4025 */
4026 if (image->debug != MagickFalse)
4027 {
cristy97e7a572009-12-05 15:07:53 +00004028 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004029 format);
cristy3ed852e2009-09-05 21:47:34 +00004030 (void) FormatMagickString(message,MaxTextExtent,
4031 "open %s (%s memory, %lux%lu %s)",cache_info->filename,
4032 cache_info->mapped != MagickFalse ? "anonymous" : "heap",
4033 cache_info->columns,cache_info->rows,format);
4034 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4035 message);
4036 }
4037 cache_info->storage_class=image->storage_class;
4038 cache_info->colorspace=image->colorspace;
4039 cache_info->type=MemoryCache;
4040 cache_info->indexes=(IndexPacket *) NULL;
4041 if (cache_info->active_index_channel != MagickFalse)
4042 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4043 number_pixels);
4044 if (source_info.storage_class != UndefinedClass)
4045 {
4046 status|=ClonePixelCachePixels(cache_info,&source_info,
4047 exception);
4048 RelinquishPixelCachePixels(&source_info);
4049 }
4050 return(MagickTrue);
4051 }
4052 }
4053 RelinquishMagickResource(MemoryResource,cache_info->length);
4054 }
4055 /*
4056 Create pixel cache on disk.
4057 */
4058 status=AcquireMagickResource(DiskResource,cache_info->length);
4059 if (status == MagickFalse)
4060 {
4061 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4062 "CacheResourcesExhausted","`%s'",image->filename);
4063 return(MagickFalse);
4064 }
4065 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4066 {
4067 RelinquishMagickResource(DiskResource,cache_info->length);
4068 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4069 image->filename);
4070 return(MagickFalse);
4071 }
4072 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4073 cache_info->length);
4074 if (status == MagickFalse)
4075 {
4076 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4077 image->filename);
4078 return(MagickFalse);
4079 }
4080 cache_info->storage_class=image->storage_class;
4081 cache_info->colorspace=image->colorspace;
4082 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4083 status=AcquireMagickResource(AreaResource,cache_info->length);
4084 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4085 cache_info->type=DiskCache;
4086 else
4087 {
4088 status=AcquireMagickResource(MapResource,cache_info->length);
4089 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4090 (cache_info->type != MemoryCache))
4091 cache_info->type=DiskCache;
4092 else
4093 {
4094 cache_info->pixels=(PixelPacket *) MapBlob(cache_info->file,mode,
4095 cache_info->offset,(size_t) cache_info->length);
4096 if (cache_info->pixels == (PixelPacket *) NULL)
4097 {
4098 cache_info->pixels=source_info.pixels;
4099 cache_info->type=DiskCache;
4100 }
4101 else
4102 {
4103 /*
4104 Create file-backed memory-mapped pixel cache.
4105 */
4106 (void) ClosePixelCacheOnDisk(cache_info);
4107 cache_info->type=MapCache;
4108 cache_info->mapped=MagickTrue;
4109 cache_info->indexes=(IndexPacket *) NULL;
4110 if (cache_info->active_index_channel != MagickFalse)
4111 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4112 number_pixels);
4113 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4114 {
4115 status=ClonePixelCachePixels(cache_info,&source_info,
4116 exception);
4117 RelinquishPixelCachePixels(&source_info);
4118 }
4119 if (image->debug != MagickFalse)
4120 {
cristy97e7a572009-12-05 15:07:53 +00004121 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004122 format);
cristy3ed852e2009-09-05 21:47:34 +00004123 (void) FormatMagickString(message,MaxTextExtent,
4124 "open %s (%s[%d], memory-mapped, %lux%lu %s)",
4125 cache_info->filename,cache_info->cache_filename,
4126 cache_info->file,cache_info->columns,cache_info->rows,
4127 format);
4128 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4129 message);
4130 }
4131 return(MagickTrue);
4132 }
4133 }
4134 RelinquishMagickResource(MapResource,cache_info->length);
4135 }
4136 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4137 {
4138 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4139 RelinquishPixelCachePixels(&source_info);
4140 }
4141 if (image->debug != MagickFalse)
4142 {
cristyb9080c92009-12-01 20:13:26 +00004143 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00004144 (void) FormatMagickString(message,MaxTextExtent,
4145 "open %s (%s[%d], disk, %lux%lu %s)",cache_info->filename,
4146 cache_info->cache_filename,cache_info->file,cache_info->columns,
4147 cache_info->rows,format);
4148 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4149 }
4150 return(MagickTrue);
4151}
4152
4153/*
4154%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4155% %
4156% %
4157% %
4158+ P e r s i s t P i x e l C a c h e %
4159% %
4160% %
4161% %
4162%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4163%
4164% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4165% persistent pixel cache is one that resides on disk and is not destroyed
4166% when the program exits.
4167%
4168% The format of the PersistPixelCache() method is:
4169%
4170% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4171% const MagickBooleanType attach,MagickOffsetType *offset,
4172% ExceptionInfo *exception)
4173%
4174% A description of each parameter follows:
4175%
4176% o image: the image.
4177%
4178% o filename: the persistent pixel cache filename.
4179%
cristy01b7eb02009-09-10 23:10:14 +00004180% o attach: A value other than zero initializes the persistent pixel
4181% cache.
4182%
cristy3ed852e2009-09-05 21:47:34 +00004183% o initialize: A value other than zero initializes the persistent pixel
4184% cache.
4185%
4186% o offset: the offset in the persistent cache to store pixels.
4187%
4188% o exception: return any errors or warnings in this structure.
4189%
4190*/
4191MagickExport MagickBooleanType PersistPixelCache(Image *image,
4192 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4193 ExceptionInfo *exception)
4194{
4195 CacheInfo
4196 *cache_info,
4197 *clone_info;
4198
4199 Image
4200 clone_image;
4201
4202 long
cristy688f07b2009-09-27 15:19:13 +00004203 page_size;
cristy3ed852e2009-09-05 21:47:34 +00004204
4205 MagickBooleanType
4206 status;
4207
4208 assert(image != (Image *) NULL);
4209 assert(image->signature == MagickSignature);
4210 if (image->debug != MagickFalse)
4211 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4212 assert(image->cache != (void *) NULL);
4213 assert(filename != (const char *) NULL);
4214 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004215 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004216 cache_info=(CacheInfo *) image->cache;
4217 assert(cache_info->signature == MagickSignature);
4218 if (attach != MagickFalse)
4219 {
4220 /*
cristy01b7eb02009-09-10 23:10:14 +00004221 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004222 */
4223 if (image->debug != MagickFalse)
4224 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4225 "attach persistent cache");
4226 (void) CopyMagickString(cache_info->cache_filename,filename,
4227 MaxTextExtent);
4228 cache_info->type=DiskCache;
4229 cache_info->offset=(*offset);
4230 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4231 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004232 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004233 return(MagickTrue);
4234 }
cristy01b7eb02009-09-10 23:10:14 +00004235 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4236 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004237 {
cristyf84a1932010-01-03 18:00:18 +00004238 LockSemaphoreInfo(cache_info->semaphore);
cristy01b7eb02009-09-10 23:10:14 +00004239 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004240 (cache_info->reference_count == 1))
4241 {
4242 int
4243 status;
4244
4245 /*
cristy01b7eb02009-09-10 23:10:14 +00004246 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004247 */
4248 status=rename(cache_info->cache_filename,filename);
4249 if (status == 0)
4250 {
4251 (void) CopyMagickString(cache_info->cache_filename,filename,
4252 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004253 *offset+=cache_info->length+page_size-(cache_info->length %
4254 page_size);
cristyf84a1932010-01-03 18:00:18 +00004255 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004256 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004257 if (image->debug != MagickFalse)
4258 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4259 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004260 return(MagickTrue);
4261 }
4262 }
cristyf84a1932010-01-03 18:00:18 +00004263 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004264 }
4265 /*
cristy01b7eb02009-09-10 23:10:14 +00004266 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004267 */
4268 clone_image=(*image);
4269 clone_info=(CacheInfo *) clone_image.cache;
4270 image->cache=ClonePixelCache(cache_info);
4271 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4272 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4273 cache_info->type=DiskCache;
4274 cache_info->offset=(*offset);
4275 cache_info=(CacheInfo *) image->cache;
4276 status=ClonePixelCacheNexus(cache_info,clone_info,exception);
4277 if (status != MagickFalse)
4278 {
4279 status=OpenPixelCache(image,IOMode,exception);
4280 if (status != MagickFalse)
4281 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
4282 }
cristy688f07b2009-09-27 15:19:13 +00004283 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004284 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4285 return(status);
4286}
4287
4288/*
4289%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4290% %
4291% %
4292% %
4293+ Q u e u e A u t h e n t i c N e x u s %
4294% %
4295% %
4296% %
4297%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4298%
4299% QueueAuthenticNexus() allocates an region to store image pixels as defined
4300% by the region rectangle and returns a pointer to the region. This region is
4301% subsequently transferred from the pixel cache with
4302% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4303% pixels are transferred, otherwise a NULL is returned.
4304%
4305% The format of the QueueAuthenticNexus() method is:
4306%
4307% PixelPacket *QueueAuthenticNexus(Image *image,const long x,const long y,
4308% const unsigned long columns,const unsigned long rows,
4309% NexusInfo *nexus_info,ExceptionInfo *exception)
4310%
4311% A description of each parameter follows:
4312%
4313% o image: the image.
4314%
4315% o x,y,columns,rows: These values define the perimeter of a region of
4316% pixels.
4317%
4318% o nexus_info: the cache nexus to set.
4319%
4320% o exception: return any errors or warnings in this structure.
4321%
4322*/
4323MagickExport PixelPacket *QueueAuthenticNexus(Image *image,const long x,
4324 const long y,const unsigned long columns,const unsigned long rows,
4325 NexusInfo *nexus_info,ExceptionInfo *exception)
4326{
4327 CacheInfo
4328 *cache_info;
4329
4330 MagickOffsetType
4331 offset;
4332
4333 MagickSizeType
4334 number_pixels;
4335
4336 RectangleInfo
4337 region;
4338
4339 /*
4340 Validate pixel cache geometry.
4341 */
4342 cache_info=(CacheInfo *) image->cache;
4343 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4344 {
4345 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4346 "NoPixelsDefinedInCache","`%s'",image->filename);
4347 return((PixelPacket *) NULL);
4348 }
4349 if ((x < 0) || (y < 0) || (x >= (long) cache_info->columns) ||
4350 (y >= (long) cache_info->rows))
4351 {
4352 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4353 "PixelsAreNotAuthentic","`%s'",image->filename);
4354 return((PixelPacket *) NULL);
4355 }
4356 offset=(MagickOffsetType) y*cache_info->columns+x;
4357 if (offset < 0)
4358 return((PixelPacket *) NULL);
4359 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4360 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4361 if ((MagickSizeType) offset >= number_pixels)
4362 return((PixelPacket *) NULL);
4363 /*
4364 Return pixel cache.
4365 */
4366 region.x=x;
4367 region.y=y;
4368 region.width=columns;
4369 region.height=rows;
4370 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4371}
4372
4373/*
4374%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4375% %
4376% %
4377% %
4378+ 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 %
4379% %
4380% %
4381% %
4382%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4383%
4384% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4385% defined by the region rectangle and returns a pointer to the region. This
4386% region is subsequently transferred from the pixel cache with
4387% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4388% pixels are transferred, otherwise a NULL is returned.
4389%
4390% The format of the QueueAuthenticPixelsCache() method is:
4391%
4392% PixelPacket *QueueAuthenticPixelsCache(Image *image,const long x,
4393% const long y,const unsigned long columns,const unsigned long rows,
4394% ExceptionInfo *exception)
4395%
4396% A description of each parameter follows:
4397%
4398% o image: the image.
4399%
4400% o x,y,columns,rows: These values define the perimeter of a region of
4401% pixels.
4402%
4403% o exception: return any errors or warnings in this structure.
4404%
4405*/
4406static PixelPacket *QueueAuthenticPixelsCache(Image *image,const long x,
4407 const long y,const unsigned long columns,const unsigned long rows,
4408 ExceptionInfo *exception)
4409{
4410 CacheInfo
4411 *cache_info;
4412
4413 long
4414 id;
4415
4416 PixelPacket
4417 *pixels;
4418
4419 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickFalse,exception);
4420 if (cache_info == (Cache) NULL)
4421 return((PixelPacket *) NULL);
4422 id=GetOpenMPThreadId();
4423 assert(id < (long) cache_info->number_threads);
4424 pixels=QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4425 exception);
4426 return(pixels);
4427}
4428
4429/*
4430%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4431% %
4432% %
4433% %
4434% Q u e u e A u t h e n t i c P i x e l s %
4435% %
4436% %
4437% %
4438%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4439%
4440% QueueAuthenticPixels() queues a mutable pixel region. If the region is
4441% successfully intialized a pointer to a PixelPacket array representing the
4442% region is returned, otherwise NULL is returned. The returned pointer may
4443% point to a temporary working buffer for the pixels or it may point to the
4444% final location of the pixels in memory.
4445%
4446% Write-only access means that any existing pixel values corresponding to
4447% the region are ignored. This is useful if the initial image is being
4448% created from scratch, or if the existing pixel values are to be
4449% completely replaced without need to refer to their pre-existing values.
4450% The application is free to read and write the pixel buffer returned by
4451% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4452% initialize the pixel array values. Initializing pixel array values is the
4453% application's responsibility.
4454%
4455% Performance is maximized if the selected region is part of one row, or
4456% one or more full rows, since then there is opportunity to access the
4457% pixels in-place (without a copy) if the image is in RAM, or in a
4458% memory-mapped file. The returned pointer should *never* be deallocated
4459% by the user.
4460%
4461% Pixels accessed via the returned pointer represent a simple array of type
4462% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
4463% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
4464% the black color component or the colormap indexes (of type IndexPacket)
4465% corresponding to the region. Once the PixelPacket (and/or IndexPacket)
4466% array has been updated, the changes must be saved back to the underlying
4467% image using SyncAuthenticPixels() or they may be lost.
4468%
4469% The format of the QueueAuthenticPixels() method is:
4470%
4471% PixelPacket *QueueAuthenticPixels(Image *image,const long x,const long y,
4472% const unsigned long columns,const unsigned long rows,
4473% ExceptionInfo *exception)
4474%
4475% A description of each parameter follows:
4476%
4477% o image: the image.
4478%
4479% o x,y,columns,rows: These values define the perimeter of a region of
4480% pixels.
4481%
4482% o exception: return any errors or warnings in this structure.
4483%
4484*/
4485MagickExport PixelPacket *QueueAuthenticPixels(Image *image,const long x,
4486 const long y,const unsigned long columns,const unsigned long rows,
4487 ExceptionInfo *exception)
4488{
4489 CacheInfo
4490 *cache_info;
4491
4492 PixelPacket
4493 *pixels;
4494
4495 assert(image != (Image *) NULL);
4496 assert(image->signature == MagickSignature);
4497 if (image->debug != MagickFalse)
4498 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4499 assert(image->cache != (Cache) NULL);
4500 cache_info=(CacheInfo *) image->cache;
4501 assert(cache_info->signature == MagickSignature);
4502 if (cache_info->methods.queue_authentic_pixels_handler ==
4503 (QueueAuthenticPixelsHandler) NULL)
4504 return((PixelPacket *) NULL);
4505 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4506 rows,exception);
4507 return(pixels);
4508}
4509
4510/*
4511%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4512% %
4513% %
4514% %
4515+ R e a d P i x e l C a c h e I n d e x e s %
4516% %
4517% %
4518% %
4519%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4520%
4521% ReadPixelCacheIndexes() reads colormap indexes from the specified region of
4522% the pixel cache.
4523%
4524% The format of the ReadPixelCacheIndexes() method is:
4525%
4526% MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4527% NexusInfo *nexus_info,ExceptionInfo *exception)
4528%
4529% A description of each parameter follows:
4530%
4531% o cache_info: the pixel cache.
4532%
4533% o nexus_info: the cache nexus to read the colormap indexes.
4534%
4535% o exception: return any errors or warnings in this structure.
4536%
4537*/
4538static MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4539 NexusInfo *nexus_info,ExceptionInfo *exception)
4540{
4541 MagickOffsetType
4542 count,
4543 offset;
4544
4545 MagickSizeType
4546 length,
4547 number_pixels;
4548
4549 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004550 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004551
4552 register long
4553 y;
4554
4555 unsigned long
4556 rows;
4557
4558 if (cache_info->debug != MagickFalse)
4559 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4560 cache_info->filename);
4561 if (cache_info->active_index_channel == MagickFalse)
4562 return(MagickFalse);
4563 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4564 return(MagickTrue);
4565 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4566 nexus_info->region.x;
4567 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
4568 rows=nexus_info->region.height;
4569 number_pixels=length*rows;
4570 if ((cache_info->columns == nexus_info->region.width) &&
4571 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4572 {
4573 length=number_pixels;
4574 rows=1UL;
4575 }
4576 q=nexus_info->indexes;
4577 switch (cache_info->type)
4578 {
4579 case MemoryCache:
4580 case MapCache:
4581 {
4582 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004583 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004584
4585 /*
4586 Read indexes from memory.
4587 */
4588 p=cache_info->indexes+offset;
4589 for (y=0; y < (long) rows; y++)
4590 {
4591 (void) CopyMagickMemory(q,p,(size_t) length);
4592 p+=cache_info->columns;
4593 q+=nexus_info->region.width;
4594 }
4595 break;
4596 }
4597 case DiskCache:
4598 {
4599 /*
4600 Read indexes from disk.
4601 */
4602 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4603 {
4604 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4605 cache_info->cache_filename);
4606 return(MagickFalse);
4607 }
4608 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4609 for (y=0; y < (long) rows; y++)
4610 {
4611 count=ReadPixelCacheRegion(cache_info,cache_info->offset+number_pixels*
4612 sizeof(PixelPacket)+offset*sizeof(*q),length,(unsigned char *) q);
4613 if ((MagickSizeType) count < length)
4614 break;
4615 offset+=cache_info->columns;
4616 q+=nexus_info->region.width;
4617 }
4618 if (y < (long) rows)
4619 {
4620 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4621 cache_info->cache_filename);
4622 return(MagickFalse);
4623 }
4624 break;
4625 }
4626 default:
4627 break;
4628 }
4629 if ((cache_info->debug != MagickFalse) &&
4630 (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4631 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
4632 cache_info->filename,nexus_info->region.width,nexus_info->region.height,
4633 nexus_info->region.x,nexus_info->region.y);
4634 return(MagickTrue);
4635}
4636
4637/*
4638%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4639% %
4640% %
4641% %
4642+ R e a d P i x e l C a c h e P i x e l s %
4643% %
4644% %
4645% %
4646%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4647%
4648% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4649% cache.
4650%
4651% The format of the ReadPixelCachePixels() method is:
4652%
4653% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4654% NexusInfo *nexus_info,ExceptionInfo *exception)
4655%
4656% A description of each parameter follows:
4657%
4658% o cache_info: the pixel cache.
4659%
4660% o nexus_info: the cache nexus to read the pixels.
4661%
4662% o exception: return any errors or warnings in this structure.
4663%
4664*/
4665static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4666 NexusInfo *nexus_info,ExceptionInfo *exception)
4667{
4668 MagickOffsetType
4669 count,
4670 offset;
4671
4672 MagickSizeType
4673 length,
4674 number_pixels;
4675
4676 register long
4677 y;
4678
4679 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004680 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004681
4682 unsigned long
4683 rows;
4684
4685 if (cache_info->debug != MagickFalse)
4686 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4687 cache_info->filename);
4688 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4689 return(MagickTrue);
4690 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4691 nexus_info->region.x;
4692 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
4693 rows=nexus_info->region.height;
4694 number_pixels=length*rows;
4695 if ((cache_info->columns == nexus_info->region.width) &&
4696 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4697 {
4698 length=number_pixels;
4699 rows=1UL;
4700 }
4701 q=nexus_info->pixels;
4702 switch (cache_info->type)
4703 {
4704 case MemoryCache:
4705 case MapCache:
4706 {
4707 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004708 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004709
4710 /*
4711 Read pixels from memory.
4712 */
4713 p=cache_info->pixels+offset;
4714 for (y=0; y < (long) rows; y++)
4715 {
4716 (void) CopyMagickMemory(q,p,(size_t) length);
4717 p+=cache_info->columns;
4718 q+=nexus_info->region.width;
4719 }
4720 break;
4721 }
4722 case DiskCache:
4723 {
4724 /*
4725 Read pixels from disk.
4726 */
4727 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4728 {
4729 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4730 cache_info->cache_filename);
4731 return(MagickFalse);
4732 }
4733 for (y=0; y < (long) rows; y++)
4734 {
4735 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4736 sizeof(*q),length,(unsigned char *) q);
4737 if ((MagickSizeType) count < length)
4738 break;
4739 offset+=cache_info->columns;
4740 q+=nexus_info->region.width;
4741 }
4742 if (y < (long) rows)
4743 {
4744 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4745 cache_info->cache_filename);
4746 return(MagickFalse);
4747 }
4748 break;
4749 }
4750 default:
4751 break;
4752 }
4753 if ((cache_info->debug != MagickFalse) &&
4754 (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4755 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
4756 cache_info->filename,nexus_info->region.width,nexus_info->region.height,
4757 nexus_info->region.x,nexus_info->region.y);
4758 return(MagickTrue);
4759}
4760
4761/*
4762%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4763% %
4764% %
4765% %
4766+ R e f e r e n c e P i x e l C a c h e %
4767% %
4768% %
4769% %
4770%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4771%
4772% ReferencePixelCache() increments the reference count associated with the
4773% pixel cache returning a pointer to the cache.
4774%
4775% The format of the ReferencePixelCache method is:
4776%
4777% Cache ReferencePixelCache(Cache cache_info)
4778%
4779% A description of each parameter follows:
4780%
4781% o cache_info: the pixel cache.
4782%
4783*/
4784MagickExport Cache ReferencePixelCache(Cache cache)
4785{
4786 CacheInfo
4787 *cache_info;
4788
4789 assert(cache != (Cache *) NULL);
4790 cache_info=(CacheInfo *) cache;
4791 assert(cache_info->signature == MagickSignature);
4792 if (cache_info->debug != MagickFalse)
4793 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4794 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00004795 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004796 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004797 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004798 return(cache_info);
4799}
4800
4801/*
4802%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4803% %
4804% %
4805% %
4806+ S e t P i x e l C a c h e M e t h o d s %
4807% %
4808% %
4809% %
4810%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4811%
4812% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4813%
4814% The format of the SetPixelCacheMethods() method is:
4815%
4816% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4817%
4818% A description of each parameter follows:
4819%
4820% o cache: the pixel cache.
4821%
4822% o cache_methods: Specifies a pointer to a CacheMethods structure.
4823%
4824*/
4825MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4826{
4827 CacheInfo
4828 *cache_info;
4829
4830 GetOneAuthenticPixelFromHandler
4831 get_one_authentic_pixel_from_handler;
4832
4833 GetOneVirtualPixelFromHandler
4834 get_one_virtual_pixel_from_handler;
4835
4836 /*
4837 Set cache pixel methods.
4838 */
4839 assert(cache != (Cache) NULL);
4840 assert(cache_methods != (CacheMethods *) NULL);
4841 cache_info=(CacheInfo *) cache;
4842 assert(cache_info->signature == MagickSignature);
4843 if (cache_info->debug != MagickFalse)
4844 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4845 cache_info->filename);
4846 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4847 cache_info->methods.get_virtual_pixel_handler=
4848 cache_methods->get_virtual_pixel_handler;
4849 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4850 cache_info->methods.destroy_pixel_handler=
4851 cache_methods->destroy_pixel_handler;
4852 if (cache_methods->get_virtual_indexes_from_handler !=
4853 (GetVirtualIndexesFromHandler) NULL)
4854 cache_info->methods.get_virtual_indexes_from_handler=
4855 cache_methods->get_virtual_indexes_from_handler;
4856 if (cache_methods->get_authentic_pixels_handler !=
4857 (GetAuthenticPixelsHandler) NULL)
4858 cache_info->methods.get_authentic_pixels_handler=
4859 cache_methods->get_authentic_pixels_handler;
4860 if (cache_methods->queue_authentic_pixels_handler !=
4861 (QueueAuthenticPixelsHandler) NULL)
4862 cache_info->methods.queue_authentic_pixels_handler=
4863 cache_methods->queue_authentic_pixels_handler;
4864 if (cache_methods->sync_authentic_pixels_handler !=
4865 (SyncAuthenticPixelsHandler) NULL)
4866 cache_info->methods.sync_authentic_pixels_handler=
4867 cache_methods->sync_authentic_pixels_handler;
4868 if (cache_methods->get_authentic_pixels_from_handler !=
4869 (GetAuthenticPixelsFromHandler) NULL)
4870 cache_info->methods.get_authentic_pixels_from_handler=
4871 cache_methods->get_authentic_pixels_from_handler;
4872 if (cache_methods->get_authentic_indexes_from_handler !=
4873 (GetAuthenticIndexesFromHandler) NULL)
4874 cache_info->methods.get_authentic_indexes_from_handler=
4875 cache_methods->get_authentic_indexes_from_handler;
4876 get_one_virtual_pixel_from_handler=
4877 cache_info->methods.get_one_virtual_pixel_from_handler;
4878 if (get_one_virtual_pixel_from_handler !=
4879 (GetOneVirtualPixelFromHandler) NULL)
4880 cache_info->methods.get_one_virtual_pixel_from_handler=
4881 cache_methods->get_one_virtual_pixel_from_handler;
4882 get_one_authentic_pixel_from_handler=
4883 cache_methods->get_one_authentic_pixel_from_handler;
4884 if (get_one_authentic_pixel_from_handler !=
4885 (GetOneAuthenticPixelFromHandler) NULL)
4886 cache_info->methods.get_one_authentic_pixel_from_handler=
4887 cache_methods->get_one_authentic_pixel_from_handler;
4888}
4889
4890/*
4891%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4892% %
4893% %
4894% %
4895+ S e t P i x e l C a c h e N e x u s P i x e l s %
4896% %
4897% %
4898% %
4899%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4900%
4901% SetPixelCacheNexusPixels() defines the region of the cache for the
4902% specified cache nexus.
4903%
4904% The format of the SetPixelCacheNexusPixels() method is:
4905%
4906% PixelPacket SetPixelCacheNexusPixels(const Image *image,
4907% const RectangleInfo *region,NexusInfo *nexus_info,
4908% ExceptionInfo *exception)
4909%
4910% A description of each parameter follows:
4911%
4912% o image: the image.
4913%
4914% o region: A pointer to the RectangleInfo structure that defines the
4915% region of this particular cache nexus.
4916%
4917% o nexus_info: the cache nexus to set.
4918%
4919% o exception: return any errors or warnings in this structure.
4920%
4921*/
4922static PixelPacket *SetPixelCacheNexusPixels(const Image *image,
4923 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4924{
4925 CacheInfo
4926 *cache_info;
4927
4928 MagickBooleanType
4929 status;
4930
4931 MagickOffsetType
4932 offset;
4933
4934 MagickSizeType
4935 length,
4936 number_pixels;
4937
4938 if (image->debug != MagickFalse)
4939 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4940 cache_info=(CacheInfo *) image->cache;
4941 assert(cache_info->signature == MagickSignature);
4942 if (cache_info->type == UndefinedCache)
4943 return((PixelPacket *) NULL);
4944 nexus_info->region.width=region->width == 0UL ? 1UL : region->width;
4945 nexus_info->region.height=region->height == 0UL ? 1UL : region->height;
4946 nexus_info->region.x=region->x;
4947 nexus_info->region.y=region->y;
4948 if ((cache_info->type != DiskCache) && (image->clip_mask == (Image *) NULL) &&
4949 (image->mask == (Image *) NULL))
4950 {
4951 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4952 nexus_info->region.x;
4953 length=(MagickSizeType) (nexus_info->region.height-1)*cache_info->columns+
4954 nexus_info->region.width-1;
4955 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4956 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
4957 {
4958 long
4959 x,
4960 y;
4961
4962 x=nexus_info->region.x+nexus_info->region.width;
4963 y=nexus_info->region.y+nexus_info->region.height;
4964 if ((nexus_info->region.x >= 0) &&
4965 (x <= (long) cache_info->columns) &&
4966 (nexus_info->region.y >= 0) && (y <= (long) cache_info->rows))
4967 if ((nexus_info->region.height == 1UL) ||
4968 ((nexus_info->region.x == 0) &&
4969 ((nexus_info->region.width % cache_info->columns) == 0)))
4970 {
4971 /*
4972 Pixels are accessed directly from memory.
4973 */
4974 nexus_info->pixels=cache_info->pixels+offset;
4975 nexus_info->indexes=(IndexPacket *) NULL;
4976 if (cache_info->active_index_channel != MagickFalse)
4977 nexus_info->indexes=cache_info->indexes+offset;
4978 return(nexus_info->pixels);
4979 }
4980 }
4981 }
4982 /*
4983 Pixels are stored in a cache region until they are synced to the cache.
4984 */
4985 number_pixels=(MagickSizeType) nexus_info->region.width*
4986 nexus_info->region.height;
4987 length=number_pixels*sizeof(PixelPacket);
4988 if (cache_info->active_index_channel != MagickFalse)
4989 length+=number_pixels*sizeof(IndexPacket);
4990 if (nexus_info->cache == (PixelPacket *) NULL)
4991 {
4992 nexus_info->length=length;
4993 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4994 if (status == MagickFalse)
4995 return((PixelPacket *) NULL);
4996 }
4997 else
4998 if (nexus_info->length != length)
4999 {
5000 RelinquishCacheNexusPixels(nexus_info);
5001 nexus_info->length=length;
5002 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5003 if (status == MagickFalse)
5004 return((PixelPacket *) NULL);
5005 }
5006 nexus_info->pixels=nexus_info->cache;
5007 nexus_info->indexes=(IndexPacket *) NULL;
5008 if (cache_info->active_index_channel != MagickFalse)
5009 nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
5010 return(nexus_info->pixels);
5011}
5012
5013/*
5014%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5015% %
5016% %
5017% %
5018% 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 %
5019% %
5020% %
5021% %
5022%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5023%
5024% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5025% pixel cache and returns the previous setting. A virtual pixel is any pixel
5026% access that is outside the boundaries of the image cache.
5027%
5028% The format of the SetPixelCacheVirtualMethod() method is:
5029%
5030% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5031% const VirtualPixelMethod virtual_pixel_method)
5032%
5033% A description of each parameter follows:
5034%
5035% o image: the image.
5036%
5037% o virtual_pixel_method: choose the type of virtual pixel.
5038%
5039*/
5040MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5041 const VirtualPixelMethod virtual_pixel_method)
5042{
5043 CacheInfo
5044 *cache_info;
5045
5046 VirtualPixelMethod
5047 method;
5048
5049 assert(image != (Image *) NULL);
5050 assert(image->signature == MagickSignature);
5051 if (image->debug != MagickFalse)
5052 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5053 assert(image->cache != (Cache) NULL);
5054 cache_info=(CacheInfo *) image->cache;
5055 assert(cache_info->signature == MagickSignature);
5056 method=cache_info->virtual_pixel_method;
5057 cache_info->virtual_pixel_method=virtual_pixel_method;
5058 return(method);
5059}
5060
5061/*
5062%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5063% %
5064% %
5065% %
5066+ 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 %
5067% %
5068% %
5069% %
5070%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5071%
5072% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5073% in-memory or disk cache. The method returns MagickTrue if the pixel region
5074% is synced, otherwise MagickFalse.
5075%
5076% The format of the SyncAuthenticPixelCacheNexus() method is:
5077%
5078% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5079% NexusInfo *nexus_info,ExceptionInfo *exception)
5080%
5081% A description of each parameter follows:
5082%
5083% o image: the image.
5084%
5085% o nexus_info: the cache nexus to sync.
5086%
5087% o exception: return any errors or warnings in this structure.
5088%
5089*/
5090MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5091 NexusInfo *nexus_info,ExceptionInfo *exception)
5092{
5093 CacheInfo
5094 *cache_info;
5095
5096 MagickBooleanType
5097 status;
5098
5099 /*
5100 Transfer pixels to the cache.
5101 */
5102 assert(image != (Image *) NULL);
5103 assert(image->signature == MagickSignature);
5104 if (image->debug != MagickFalse)
5105 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5106 if (image->cache == (Cache) NULL)
5107 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5108 cache_info=(CacheInfo *) image->cache;
5109 if (cache_info->type == UndefinedCache)
5110 return(MagickFalse);
5111 if ((image->clip_mask != (Image *) NULL) &&
5112 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5113 return(MagickFalse);
5114 if ((image->mask != (Image *) NULL) &&
5115 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5116 return(MagickFalse);
5117 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5118 return(MagickTrue);
5119 assert(cache_info->signature == MagickSignature);
5120 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5121 if ((cache_info->active_index_channel != MagickFalse) &&
5122 (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
5123 return(MagickFalse);
5124 return(status);
5125}
5126
5127/*
5128%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5129% %
5130% %
5131% %
5132+ S y n c A u t h e n t i c P i x e l C a c h e %
5133% %
5134% %
5135% %
5136%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5137%
5138% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5139% or disk cache. The method returns MagickTrue if the pixel region is synced,
5140% otherwise MagickFalse.
5141%
5142% The format of the SyncAuthenticPixelsCache() method is:
5143%
5144% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5145% ExceptionInfo *exception)
5146%
5147% A description of each parameter follows:
5148%
5149% o image: the image.
5150%
5151% o exception: return any errors or warnings in this structure.
5152%
5153*/
5154static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5155 ExceptionInfo *exception)
5156{
5157 CacheInfo
5158 *cache_info;
5159
5160 long
5161 id;
5162
5163 MagickBooleanType
5164 status;
5165
5166 cache_info=(CacheInfo *) image->cache;
5167 id=GetOpenMPThreadId();
5168 assert(id < (long) cache_info->number_threads);
5169 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5170 exception);
5171 return(status);
5172}
5173
5174/*
5175%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5176% %
5177% %
5178% %
5179% S y n c A u t h e n t i c P i x e l s %
5180% %
5181% %
5182% %
5183%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5184%
5185% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5186% The method returns MagickTrue if the pixel region is flushed, otherwise
5187% MagickFalse.
5188%
5189% The format of the SyncAuthenticPixels() method is:
5190%
5191% MagickBooleanType SyncAuthenticPixels(Image *image,
5192% ExceptionInfo *exception)
5193%
5194% A description of each parameter follows:
5195%
5196% o image: the image.
5197%
5198% o exception: return any errors or warnings in this structure.
5199%
5200*/
5201MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5202 ExceptionInfo *exception)
5203{
5204 CacheInfo
5205 *cache_info;
5206
5207 assert(image != (Image *) NULL);
5208 assert(image->signature == MagickSignature);
5209 if (image->debug != MagickFalse)
5210 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5211 assert(image->cache != (Cache) NULL);
5212 cache_info=(CacheInfo *) image->cache;
5213 assert(cache_info->signature == MagickSignature);
5214 if (cache_info->methods.sync_authentic_pixels_handler ==
5215 (SyncAuthenticPixelsHandler) NULL)
5216 return(MagickFalse);
5217 return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
5218}
5219
5220/*
5221%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5222% %
5223% %
5224% %
5225+ W r i t e P i x e l C a c h e I n d e x e s %
5226% %
5227% %
5228% %
5229%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5230%
5231% WritePixelCacheIndexes() writes the colormap indexes to the specified
5232% region of the pixel cache.
5233%
5234% The format of the WritePixelCacheIndexes() method is:
5235%
5236% MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5237% NexusInfo *nexus_info,ExceptionInfo *exception)
5238%
5239% A description of each parameter follows:
5240%
5241% o cache_info: the pixel cache.
5242%
5243% o nexus_info: the cache nexus to write the colormap indexes.
5244%
5245% o exception: return any errors or warnings in this structure.
5246%
5247*/
5248static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5249 NexusInfo *nexus_info,ExceptionInfo *exception)
5250{
5251 MagickOffsetType
5252 count,
5253 offset;
5254
5255 MagickSizeType
5256 length,
5257 number_pixels;
5258
5259 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005260 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005261
5262 register long
5263 y;
5264
5265 unsigned long
5266 rows;
5267
5268 if (cache_info->debug != MagickFalse)
5269 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
5270 cache_info->filename);
5271 if (cache_info->active_index_channel == MagickFalse)
5272 return(MagickFalse);
5273 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5274 return(MagickTrue);
5275 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5276 nexus_info->region.x;
5277 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
5278 rows=nexus_info->region.height;
5279 number_pixels=(MagickSizeType) length*rows;
5280 if ((cache_info->columns == nexus_info->region.width) &&
5281 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5282 {
5283 length=number_pixels;
5284 rows=1UL;
5285 }
5286 p=nexus_info->indexes;
5287 switch (cache_info->type)
5288 {
5289 case MemoryCache:
5290 case MapCache:
5291 {
5292 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005293 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005294
5295 /*
5296 Write indexes to memory.
5297 */
5298 q=cache_info->indexes+offset;
5299 for (y=0; y < (long) rows; y++)
5300 {
5301 (void) CopyMagickMemory(q,p,(size_t) length);
5302 p+=nexus_info->region.width;
5303 q+=cache_info->columns;
5304 }
5305 break;
5306 }
5307 case DiskCache:
5308 {
5309 /*
5310 Write indexes to disk.
5311 */
5312 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5313 {
5314 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5315 cache_info->cache_filename);
5316 return(MagickFalse);
5317 }
5318 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
5319 for (y=0; y < (long) rows; y++)
5320 {
5321 count=WritePixelCacheRegion(cache_info,cache_info->offset+number_pixels*
5322 sizeof(PixelPacket)+offset*sizeof(*p),length,
5323 (const unsigned char *) p);
5324 if ((MagickSizeType) count < length)
5325 break;
5326 p+=nexus_info->region.width;
5327 offset+=cache_info->columns;
5328 }
5329 if (y < (long) rows)
5330 {
5331 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5332 cache_info->cache_filename);
5333 return(MagickFalse);
5334 }
5335 break;
5336 }
5337 default:
5338 break;
5339 }
5340 if ((cache_info->debug != MagickFalse) &&
5341 (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5342 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
5343 cache_info->filename,nexus_info->region.width,nexus_info->region.height,
5344 nexus_info->region.x,nexus_info->region.y);
5345 return(MagickTrue);
5346}
5347
5348/*
5349%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5350% %
5351% %
5352% %
5353+ W r i t e C a c h e P i x e l s %
5354% %
5355% %
5356% %
5357%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5358%
5359% WritePixelCachePixels() writes image pixels to the specified region of the
5360% pixel cache.
5361%
5362% The format of the WritePixelCachePixels() method is:
5363%
5364% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5365% NexusInfo *nexus_info,ExceptionInfo *exception)
5366%
5367% A description of each parameter follows:
5368%
5369% o cache_info: the pixel cache.
5370%
5371% o nexus_info: the cache nexus to write the pixels.
5372%
5373% o exception: return any errors or warnings in this structure.
5374%
5375*/
5376static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5377 NexusInfo *nexus_info,ExceptionInfo *exception)
5378{
5379 MagickOffsetType
5380 count,
5381 offset;
5382
5383 MagickSizeType
5384 length,
5385 number_pixels;
5386
cristy3ed852e2009-09-05 21:47:34 +00005387 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005388 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005389
cristy25ffffb2009-12-07 17:15:07 +00005390 register long
5391 y;
5392
cristy3ed852e2009-09-05 21:47:34 +00005393 unsigned long
5394 rows;
5395
5396 if (cache_info->debug != MagickFalse)
5397 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
5398 cache_info->filename);
5399 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5400 return(MagickTrue);
5401 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5402 nexus_info->region.x;
5403 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
5404 rows=nexus_info->region.height;
5405 number_pixels=length*rows;
5406 if ((cache_info->columns == nexus_info->region.width) &&
5407 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5408 {
5409 length=number_pixels;
5410 rows=1UL;
5411 }
5412 p=nexus_info->pixels;
5413 switch (cache_info->type)
5414 {
5415 case MemoryCache:
5416 case MapCache:
5417 {
5418 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005419 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005420
5421 /*
5422 Write pixels to memory.
5423 */
5424 q=cache_info->pixels+offset;
5425 for (y=0; y < (long) rows; y++)
5426 {
5427 (void) CopyMagickMemory(q,p,(size_t) length);
5428 p+=nexus_info->region.width;
5429 q+=cache_info->columns;
5430 }
5431 break;
5432 }
5433 case DiskCache:
5434 {
5435 /*
5436 Write pixels to disk.
5437 */
5438 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5439 {
5440 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5441 cache_info->cache_filename);
5442 return(MagickFalse);
5443 }
5444 for (y=0; y < (long) rows; y++)
5445 {
5446 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5447 sizeof(*p),length,(const unsigned char *) p);
5448 if ((MagickSizeType) count < length)
5449 break;
5450 p+=nexus_info->region.width;
5451 offset+=cache_info->columns;
5452 }
5453 if (y < (long) rows)
5454 {
5455 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5456 cache_info->cache_filename);
5457 return(MagickFalse);
5458 }
5459 break;
5460 }
5461 default:
5462 break;
5463 }
5464 if ((cache_info->debug != MagickFalse) &&
5465 (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5466 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
5467 cache_info->filename,nexus_info->region.width,nexus_info->region.height,
5468 nexus_info->region.x,nexus_info->region.y);
5469 return(MagickTrue);
5470}