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