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