blob: 4f39ee1558a2e36938bd24a0471d2eacc565b948 [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
cristy73724512010-04-12 14:43:14 +00001811 if (cache_info->type == PingCache)
1812 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001813 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1814 nexus_info->region.x;
1815 if (nexus_info->pixels != (cache_info->pixels+offset))
1816 return(MagickFalse);
1817 return(MagickTrue);
1818}
1819
1820MagickExport PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const long x,
1821 const long y,const unsigned long columns,const unsigned long rows,
1822 NexusInfo *nexus_info,ExceptionInfo *exception)
1823{
1824 CacheInfo
1825 *cache_info;
1826
1827 PixelPacket
1828 *pixels;
1829
1830 /*
1831 Transfer pixels from the cache.
1832 */
1833 assert(image != (Image *) NULL);
1834 assert(image->signature == MagickSignature);
1835 if (image->debug != MagickFalse)
1836 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1837 pixels=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
1838 if (pixels == (PixelPacket *) NULL)
1839 return((PixelPacket *) NULL);
1840 cache_info=(CacheInfo *) image->cache;
1841 assert(cache_info->signature == MagickSignature);
1842 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
1843 return(pixels);
1844 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1845 return((PixelPacket *) NULL);
1846 if (cache_info->active_index_channel != MagickFalse)
1847 if (ReadPixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse)
1848 return((PixelPacket *) NULL);
1849 return(pixels);
1850}
1851
1852/*
1853%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1854% %
1855% %
1856% %
1857+ 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 %
1858% %
1859% %
1860% %
1861%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1862%
1863% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1864% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1865%
1866% The format of the GetAuthenticPixelsFromCache() method is:
1867%
1868% PixelPacket *GetAuthenticPixelsFromCache(const Image image)
1869%
1870% A description of each parameter follows:
1871%
1872% o image: the image.
1873%
1874*/
1875static PixelPacket *GetAuthenticPixelsFromCache(const Image *image)
1876{
1877 CacheInfo
1878 *cache_info;
1879
1880 long
1881 id;
1882
1883 PixelPacket
1884 *pixels;
1885
1886 if (image->debug != MagickFalse)
1887 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1888 cache_info=(CacheInfo *) image->cache;
1889 id=GetOpenMPThreadId();
1890 assert(id < (long) cache_info->number_threads);
1891 pixels=GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]);
1892 return(pixels);
1893}
1894
1895/*
1896%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1897% %
1898% %
1899% %
1900% G e t A u t h e n t i c P i x e l Q u e u e %
1901% %
1902% %
1903% %
1904%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1905%
1906% GetAuthenticPixelQueue() returns the authentic pixels associated with the
1907% last call to QueueAuthenticPixels() or GetAuthenticPixels().
1908%
1909% The format of the GetAuthenticPixelQueue() method is:
1910%
1911% PixelPacket *GetAuthenticPixelQueue(const Image image)
1912%
1913% A description of each parameter follows:
1914%
1915% o image: the image.
1916%
1917*/
1918MagickExport PixelPacket *GetAuthenticPixelQueue(const Image *image)
1919{
1920 CacheInfo
1921 *cache_info;
1922
1923 assert(image != (const Image *) NULL);
1924 assert(image->signature == MagickSignature);
1925 if (image->debug != MagickFalse)
1926 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1927 assert(image->cache != (Cache) NULL);
1928 cache_info=(CacheInfo *) image->cache;
1929 assert(cache_info->signature == MagickSignature);
1930 if (cache_info->methods.get_authentic_pixels_from_handler ==
1931 (GetAuthenticPixelsFromHandler) NULL)
1932 return((PixelPacket *) NULL);
1933 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1934}
1935
1936/*
1937%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1938% %
1939% %
1940% %
1941% G e t A u t h e n t i c P i x e l s %
1942% %
1943% %
1944% %
1945%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1946%
1947% GetAuthenticPixels() obtains a pixel region for read/write access. If the
1948% region is successfully accessed, a pointer to a PixelPacket array
1949% representing the region is returned, otherwise NULL is returned.
1950%
1951% The returned pointer may point to a temporary working copy of the pixels
1952% or it may point to the original pixels in memory. Performance is maximized
1953% if the selected region is part of one row, or one or more full rows, since
1954% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001955% if the image is in memory, or in a memory-mapped file. The returned pointer
1956% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001957%
1958% Pixels accessed via the returned pointer represent a simple array of type
1959% PixelPacket. If the image type is CMYK or if the storage class is
1960% PseduoClass, call GetAuthenticIndexQueue() after invoking
1961% GetAuthenticPixels() to obtain the black color component or colormap indexes
1962% (of type IndexPacket) corresponding to the region. Once the PixelPacket
1963% (and/or IndexPacket) array has been updated, the changes must be saved back
1964% to the underlying image using SyncAuthenticPixels() or they may be lost.
1965%
1966% The format of the GetAuthenticPixels() method is:
1967%
1968% PixelPacket *GetAuthenticPixels(Image *image,const long x,const long y,
1969% const unsigned long columns,const unsigned long rows,
1970% ExceptionInfo *exception)
1971%
1972% A description of each parameter follows:
1973%
1974% o image: the image.
1975%
1976% o x,y,columns,rows: These values define the perimeter of a region of
1977% pixels.
1978%
1979% o exception: return any errors or warnings in this structure.
1980%
1981*/
1982MagickExport PixelPacket *GetAuthenticPixels(Image *image,const long x,
1983 const long y,const unsigned long columns,const unsigned long rows,
1984 ExceptionInfo *exception)
1985{
1986 CacheInfo
1987 *cache_info;
1988
1989 PixelPacket
1990 *pixels;
1991
1992 assert(image != (Image *) NULL);
1993 assert(image->signature == MagickSignature);
1994 if (image->debug != MagickFalse)
1995 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1996 assert(image->cache != (Cache) NULL);
1997 cache_info=(CacheInfo *) image->cache;
1998 assert(cache_info->signature == MagickSignature);
1999 if (cache_info->methods.get_authentic_pixels_handler ==
2000 (GetAuthenticPixelsHandler) NULL)
2001 return((PixelPacket *) NULL);
2002 pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
2003 rows,exception);
2004 return(pixels);
2005}
2006
2007/*
2008%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2009% %
2010% %
2011% %
2012+ G e t A u t h e n t i c P i x e l s C a c h e %
2013% %
2014% %
2015% %
2016%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2017%
2018% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
2019% as defined by the geometry parameters. A pointer to the pixels is returned
2020% if the pixels are transferred, otherwise a NULL is returned.
2021%
2022% The format of the GetAuthenticPixelsCache() method is:
2023%
2024% PixelPacket *GetAuthenticPixelsCache(Image *image,const long x,
2025% const long y,const unsigned long columns,const unsigned long rows,
2026% ExceptionInfo *exception)
2027%
2028% A description of each parameter follows:
2029%
2030% o image: the image.
2031%
2032% o x,y,columns,rows: These values define the perimeter of a region of
2033% pixels.
2034%
2035% o exception: return any errors or warnings in this structure.
2036%
2037*/
2038static PixelPacket *GetAuthenticPixelsCache(Image *image,const long x,
2039 const long y,const unsigned long columns,const unsigned long rows,
2040 ExceptionInfo *exception)
2041{
2042 CacheInfo
2043 *cache_info;
2044
2045 long
2046 id;
2047
2048 PixelPacket
2049 *pixels;
2050
2051 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
2052 if (cache_info == (Cache) NULL)
2053 return((PixelPacket *) NULL);
2054 id=GetOpenMPThreadId();
2055 assert(id < (long) cache_info->number_threads);
2056 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
2057 cache_info->nexus_info[id],exception);
2058 return(pixels);
2059}
2060
2061/*
2062%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2063% %
2064% %
2065% %
2066+ G e t I m a g e E x t e n t %
2067% %
2068% %
2069% %
2070%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2071%
2072% GetImageExtent() returns the extent of the pixels associated with the
2073% last call to QueueAuthenticPixels() or GetAuthenticPixels().
2074%
2075% The format of the GetImageExtent() method is:
2076%
2077% MagickSizeType GetImageExtent(const Image *image)
2078%
2079% A description of each parameter follows:
2080%
2081% o image: the image.
2082%
2083*/
2084MagickExport MagickSizeType GetImageExtent(const Image *image)
2085{
2086 CacheInfo
2087 *cache_info;
2088
2089 long
2090 id;
2091
2092 MagickSizeType
2093 extent;
2094
2095 assert(image != (Image *) NULL);
2096 assert(image->signature == MagickSignature);
2097 if (image->debug != MagickFalse)
2098 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2099 assert(image->cache != (Cache) NULL);
2100 cache_info=(CacheInfo *) image->cache;
2101 assert(cache_info->signature == MagickSignature);
2102 id=GetOpenMPThreadId();
2103 assert(id < (long) cache_info->number_threads);
2104 extent=GetPixelCacheNexusExtent(image->cache,cache_info->nexus_info[id]);
2105 return(extent);
2106}
2107
2108/*
2109%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2110% %
2111% %
2112% %
2113+ G e t I m a g e P i x e l C a c h e %
2114% %
2115% %
2116% %
2117%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2118%
2119% GetImagePixelCache() ensures that there is only a single reference to the
2120% pixel cache to be modified, updating the provided cache pointer to point to
2121% a clone of the original pixel cache if necessary.
2122%
2123% The format of the GetImagePixelCache method is:
2124%
2125% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2126% ExceptionInfo *exception)
2127%
2128% A description of each parameter follows:
2129%
2130% o image: the image.
2131%
2132% o clone: any value other than MagickFalse clones the cache pixels.
2133%
2134% o exception: return any errors or warnings in this structure.
2135%
2136*/
2137
2138static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
2139{
2140 CacheInfo
2141 *cache_info;
2142
2143 /*
2144 Does the image match the pixel cache morphology?
2145 */
2146 cache_info=(CacheInfo *) image->cache;
2147 if ((image->storage_class != cache_info->storage_class) ||
2148 (image->colorspace != cache_info->colorspace) ||
2149 (image->columns != cache_info->columns) ||
2150 (image->rows != cache_info->rows) ||
2151 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2152 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2153 return(MagickFalse);
2154 return(MagickTrue);
2155}
2156
2157MagickExport Cache GetImagePixelCache(Image *image,
2158 const MagickBooleanType clone,ExceptionInfo *exception)
2159{
2160 CacheInfo
2161 *cache_info;
2162
cristy3ed852e2009-09-05 21:47:34 +00002163 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00002164 destroy,
cristy3ed852e2009-09-05 21:47:34 +00002165 status;
2166
cristy50a10922010-02-15 18:35:25 +00002167 static MagickSizeType
2168 time_limit = 0;
2169
cristy3ed852e2009-09-05 21:47:34 +00002170 if (image->debug != MagickFalse)
2171 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy50a10922010-02-15 18:35:25 +00002172 if (time_limit == 0)
2173 time_limit=GetMagickResourceLimit(TimeResource);
2174 if (time_limit != MagickResourceInfinity)
2175 {
2176 static time_t
2177 cache_timer = 0;
2178
2179 if (cache_timer == 0)
2180 cache_timer=time((time_t *) NULL);
2181 if ((MagickSizeType) (time((time_t *) NULL)-cache_timer) >= time_limit)
2182 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
2183 }
cristyc4f9f132010-03-04 18:50:01 +00002184 status=MagickTrue;
2185 LockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002186 assert(image->cache != (Cache) NULL);
2187 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002188 destroy=MagickFalse;
cristy01b7eb02009-09-10 23:10:14 +00002189 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002190 {
cristyaaa0cb62010-02-15 17:47:27 +00002191 LockSemaphoreInfo(cache_info->semaphore);
2192 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002193 {
cristyaaa0cb62010-02-15 17:47:27 +00002194 Image
2195 clone_image;
2196
2197 CacheInfo
2198 *clone_info;
2199
2200 /*
2201 Clone pixel cache.
2202 */
2203 clone_image=(*image);
2204 clone_image.cache=ClonePixelCache(cache_info);
2205 clone_info=(CacheInfo *) clone_image.cache;
2206 status=ClonePixelCacheNexus(cache_info,clone_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002207 if (status != MagickFalse)
2208 {
cristyaaa0cb62010-02-15 17:47:27 +00002209 status=OpenPixelCache(&clone_image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00002210 if (status != MagickFalse)
2211 {
cristyaaa0cb62010-02-15 17:47:27 +00002212 if (clone != MagickFalse)
2213 status=ClonePixelCachePixels(clone_info,cache_info,
2214 exception);
2215 if (status != MagickFalse)
2216 {
2217 destroy=MagickTrue;
2218 image->cache=clone_image.cache;
2219 }
cristy3ed852e2009-09-05 21:47:34 +00002220 }
2221 }
2222 }
cristyaaa0cb62010-02-15 17:47:27 +00002223 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002224 }
cristy4320e0e2009-09-10 15:00:08 +00002225 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002226 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002227 if (status != MagickFalse)
2228 {
2229 /*
2230 Ensure the image matches the pixel cache morphology.
2231 */
2232 image->taint=MagickTrue;
2233 image->type=UndefinedType;
2234 if (image->colorspace == GRAYColorspace)
2235 image->colorspace=RGBColorspace;
2236 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2237 status=OpenPixelCache(image,IOMode,exception);
2238 }
cristyf84a1932010-01-03 18:00:18 +00002239 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002240 if (status == MagickFalse)
2241 return((Cache) NULL);
2242 return(image->cache);
2243}
2244
2245/*
2246%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2247% %
2248% %
2249% %
2250% G e t O n e A u t h e n t i c P i x e l %
2251% %
2252% %
2253% %
2254%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2255%
2256% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2257% location. The image background color is returned if an error occurs.
2258%
2259% The format of the GetOneAuthenticPixel() method is:
2260%
2261% MagickBooleanType GetOneAuthenticPixel(const Image image,const long x,
2262% const long y,PixelPacket *pixel,ExceptionInfo *exception)
2263%
2264% A description of each parameter follows:
2265%
2266% o image: the image.
2267%
2268% o x,y: These values define the location of the pixel to return.
2269%
2270% o pixel: return a pixel at the specified (x,y) location.
2271%
2272% o exception: return any errors or warnings in this structure.
2273%
2274*/
2275MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,const long x,
2276 const long y,PixelPacket *pixel,ExceptionInfo *exception)
2277{
2278 CacheInfo
2279 *cache_info;
2280
2281 GetOneAuthenticPixelFromHandler
2282 get_one_authentic_pixel_from_handler;
2283
2284 MagickBooleanType
2285 status;
2286
2287 assert(image != (Image *) NULL);
2288 assert(image->signature == MagickSignature);
2289 if (image->debug != MagickFalse)
2290 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2291 assert(image->cache != (Cache) NULL);
2292 cache_info=(CacheInfo *) image->cache;
2293 assert(cache_info->signature == MagickSignature);
2294 *pixel=image->background_color;
2295 get_one_authentic_pixel_from_handler=
2296 cache_info->methods.get_one_authentic_pixel_from_handler;
2297 if (get_one_authentic_pixel_from_handler ==
2298 (GetOneAuthenticPixelFromHandler) NULL)
2299 return(MagickFalse);
2300 status=cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2301 pixel,exception);
2302 return(status);
2303}
2304
2305/*
2306%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2307% %
2308% %
2309% %
2310+ 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 %
2311% %
2312% %
2313% %
2314%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2315%
2316% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2317% location. The image background color is returned if an error occurs.
2318%
2319% The format of the GetOneAuthenticPixelFromCache() method is:
2320%
2321% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
2322% const long x,const long y,PixelPacket *pixel,ExceptionInfo *exception)
2323%
2324% A description of each parameter follows:
2325%
2326% o image: the image.
2327%
2328% o x,y: These values define the location of the pixel to return.
2329%
2330% o pixel: return a pixel at the specified (x,y) location.
2331%
2332% o exception: return any errors or warnings in this structure.
2333%
2334*/
2335static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
2336 const long x,const long y,PixelPacket *pixel,ExceptionInfo *exception)
2337{
2338 PixelPacket
2339 *pixels;
2340
2341 if (image->debug != MagickFalse)
2342 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2343 *pixel=image->background_color;
2344 pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2345 if (pixels == (PixelPacket *) NULL)
2346 return(MagickFalse);
2347 *pixel=(*pixels);
2348 return(MagickTrue);
2349}
2350
2351/*
2352%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2353% %
2354% %
2355% %
2356% G e t O n e V i r t u a l M a g i c k P i x e l %
2357% %
2358% %
2359% %
2360%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2361%
2362% GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2363% location. The image background color is returned if an error occurs. If
2364% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2365%
2366% The format of the GetOneVirtualMagickPixel() method is:
2367%
2368% MagickBooleanType GetOneVirtualMagickPixel(const Image image,
2369% const long x,const long y,MagickPixelPacket *pixel,
2370% ExceptionInfo exception)
2371%
2372% A description of each parameter follows:
2373%
2374% o image: the image.
2375%
2376% o x,y: these values define the location of the pixel to return.
2377%
2378% o pixel: return a pixel at the specified (x,y) location.
2379%
2380% o exception: return any errors or warnings in this structure.
2381%
2382*/
2383MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
2384 const long x,const long y,MagickPixelPacket *pixel,ExceptionInfo *exception)
2385{
2386 CacheInfo
2387 *cache_info;
2388
2389 register const IndexPacket
2390 *indexes;
2391
2392 register const PixelPacket
2393 *p;
2394
2395 assert(image != (const Image *) NULL);
2396 assert(image->signature == MagickSignature);
2397 assert(image->cache != (Cache) NULL);
2398 cache_info=(CacheInfo *) image->cache;
2399 assert(cache_info->signature == MagickSignature);
2400 GetMagickPixelPacket(image,pixel);
2401 p=GetVirtualPixelCache(image,GetPixelCacheVirtualMethod(image),x,y,1,1,
2402 exception);
2403 if (p == (const PixelPacket *) NULL)
2404 return(MagickFalse);
2405 indexes=GetVirtualIndexQueue(image);
2406 SetMagickPixelPacket(image,p,indexes,pixel);
2407 return(MagickTrue);
2408}
2409
2410/*
2411%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2412% %
2413% %
2414% %
2415% G e t O n e V i r t u a l M e t h o d P i x e l %
2416% %
2417% %
2418% %
2419%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2420%
2421% GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2422% location as defined by specified pixel method. The image background color
2423% is returned if an error occurs. If you plan to modify the pixel, use
2424% GetOneAuthenticPixel() instead.
2425%
2426% The format of the GetOneVirtualMethodPixel() method is:
2427%
2428% MagickBooleanType GetOneVirtualMethodPixel(const Image image,
2429% const VirtualPixelMethod virtual_pixel_method,const long x,
2430% const long y,Pixelpacket *pixel,ExceptionInfo exception)
2431%
2432% A description of each parameter follows:
2433%
2434% o image: the image.
2435%
2436% o virtual_pixel_method: the virtual pixel method.
2437%
2438% o x,y: These values define the location of the pixel to return.
2439%
2440% o pixel: return a pixel at the specified (x,y) location.
2441%
2442% o exception: return any errors or warnings in this structure.
2443%
2444*/
2445MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
2446 const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
2447 PixelPacket *pixel,ExceptionInfo *exception)
2448{
2449 GetOneVirtualPixelFromHandler
2450 get_one_virtual_pixel_from_handler;
2451
2452 CacheInfo
2453 *cache_info;
2454
2455 MagickBooleanType
2456 status;
2457
2458 assert(image != (const Image *) NULL);
2459 assert(image->signature == MagickSignature);
2460 assert(image->cache != (Cache) NULL);
2461 cache_info=(CacheInfo *) image->cache;
2462 assert(cache_info->signature == MagickSignature);
2463 *pixel=image->background_color;
2464 get_one_virtual_pixel_from_handler=
2465 cache_info->methods.get_one_virtual_pixel_from_handler;
2466 if (get_one_virtual_pixel_from_handler ==
2467 (GetOneVirtualPixelFromHandler) NULL)
2468 return(MagickFalse);
2469 status=get_one_virtual_pixel_from_handler(image,virtual_pixel_method,x,y,
2470 pixel,exception);
2471 return(status);
2472}
2473
2474/*
2475%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2476% %
2477% %
2478% %
2479% G e t O n e V i r t u a l P i x e l %
2480% %
2481% %
2482% %
2483%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2484%
2485% GetOneVirtualPixel() returns a single virtual pixel at the specified
2486% (x,y) location. The image background color is returned if an error occurs.
2487% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2488%
2489% The format of the GetOneVirtualPixel() method is:
2490%
2491% MagickBooleanType GetOneVirtualPixel(const Image image,const long x,
2492% const long y,PixelPacket *pixel,ExceptionInfo exception)
2493%
2494% A description of each parameter follows:
2495%
2496% o image: the image.
2497%
2498% o x,y: These values define the location of the pixel to return.
2499%
2500% o pixel: return a pixel at the specified (x,y) location.
2501%
2502% o exception: return any errors or warnings in this structure.
2503%
2504*/
2505MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
2506 const long x,const long y,PixelPacket *pixel,ExceptionInfo *exception)
2507{
2508 GetOneVirtualPixelFromHandler
2509 get_one_virtual_pixel_from_handler;
2510
2511 CacheInfo
2512 *cache_info;
2513
2514 MagickBooleanType
2515 status;
2516
2517 assert(image != (const Image *) NULL);
2518 assert(image->signature == MagickSignature);
2519 assert(image->cache != (Cache) NULL);
2520 cache_info=(CacheInfo *) image->cache;
2521 assert(cache_info->signature == MagickSignature);
2522 *pixel=image->background_color;
2523 get_one_virtual_pixel_from_handler=
2524 cache_info->methods.get_one_virtual_pixel_from_handler;
2525 if (get_one_virtual_pixel_from_handler ==
2526 (GetOneVirtualPixelFromHandler) NULL)
2527 return(MagickFalse);
2528 status=get_one_virtual_pixel_from_handler(image,GetPixelCacheVirtualMethod(
2529 image),x,y,pixel,exception);
2530 return(status);
2531}
2532
2533/*
2534%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2535% %
2536% %
2537% %
2538+ 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 %
2539% %
2540% %
2541% %
2542%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2543%
2544% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2545% specified (x,y) location. The image background color is returned if an
2546% error occurs.
2547%
2548% The format of the GetOneVirtualPixelFromCache() method is:
2549%
2550% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
2551% const VirtualPixelPacket method,const long x,const long y,
2552% PixelPacket *pixel,ExceptionInfo *exception)
2553%
2554% A description of each parameter follows:
2555%
2556% o image: the image.
2557%
2558% o virtual_pixel_method: the virtual pixel method.
2559%
2560% o x,y: These values define the location of the pixel to return.
2561%
2562% o pixel: return a pixel at the specified (x,y) location.
2563%
2564% o exception: return any errors or warnings in this structure.
2565%
2566*/
2567static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
2568 const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
2569 PixelPacket *pixel,ExceptionInfo *exception)
2570{
2571 const PixelPacket
2572 *pixels;
2573
2574 *pixel=image->background_color;
2575 pixels=GetVirtualPixelCache(image,virtual_pixel_method,x,y,1UL,1UL,exception);
2576 if (pixels == (const PixelPacket *) NULL)
2577 return(MagickFalse);
2578 *pixel=(*pixels);
2579 return(MagickTrue);
2580}
2581
2582/*
2583%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2584% %
2585% %
2586% %
2587+ G e t P i x e l C a c h e C o l o r s p a c e %
2588% %
2589% %
2590% %
2591%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2592%
2593% GetPixelCacheColorspace() returns the class type of the pixel cache.
2594%
2595% The format of the GetPixelCacheColorspace() method is:
2596%
2597% Colorspace GetPixelCacheColorspace(Cache cache)
2598%
2599% A description of each parameter follows:
2600%
2601% o cache: the pixel cache.
2602%
2603*/
2604MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
2605{
2606 CacheInfo
2607 *cache_info;
2608
2609 assert(cache != (Cache) NULL);
2610 cache_info=(CacheInfo *) cache;
2611 assert(cache_info->signature == MagickSignature);
2612 if (cache_info->debug != MagickFalse)
2613 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2614 cache_info->filename);
2615 return(cache_info->colorspace);
2616}
2617
2618/*
2619%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2620% %
2621% %
2622% %
2623+ G e t P i x e l C a c h e M e t h o d s %
2624% %
2625% %
2626% %
2627%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2628%
2629% GetPixelCacheMethods() initializes the CacheMethods structure.
2630%
2631% The format of the GetPixelCacheMethods() method is:
2632%
2633% void GetPixelCacheMethods(CacheMethods *cache_methods)
2634%
2635% A description of each parameter follows:
2636%
2637% o cache_methods: Specifies a pointer to a CacheMethods structure.
2638%
2639*/
2640MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
2641{
2642 assert(cache_methods != (CacheMethods *) NULL);
2643 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2644 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2645 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2646 cache_methods->get_virtual_indexes_from_handler=GetVirtualIndexesFromCache;
2647 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2648 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2649 cache_methods->get_authentic_indexes_from_handler=
2650 GetAuthenticIndexesFromCache;
2651 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2652 cache_methods->get_one_authentic_pixel_from_handler=
2653 GetOneAuthenticPixelFromCache;
2654 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2655 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2656 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2657}
2658
2659/*
2660%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2661% %
2662% %
2663% %
2664+ G e t P i x e l C a c h e N e x u s E x t e n t %
2665% %
2666% %
2667% %
2668%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2669%
2670% GetPixelCacheNexusExtent() returns the extent of the pixels associated with
2671% the last call to SetPixelCacheNexusPixels() or GetPixelCacheNexusPixels().
2672%
2673% The format of the GetPixelCacheNexusExtent() method is:
2674%
2675% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2676% NexusInfo *nexus_info)
2677%
2678% A description of each parameter follows:
2679%
2680% o nexus_info: the nexus info.
2681%
2682*/
2683MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2684 NexusInfo *nexus_info)
2685{
2686 CacheInfo
2687 *cache_info;
2688
2689 MagickSizeType
2690 extent;
2691
2692 if (cache == (Cache) NULL)
2693 return(0);
2694 cache_info=(CacheInfo *) cache;
2695 assert(cache_info->signature == MagickSignature);
2696 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2697 if (extent == 0)
2698 return((MagickSizeType) cache_info->columns*cache_info->rows);
2699 return(extent);
2700}
2701
2702/*
2703%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2704% %
2705% %
2706% %
2707+ 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 %
2708% %
2709% %
2710% %
2711%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2712%
2713% GetPixelCacheNexusIndexes() returns the indexes associated with the
2714% specified cache nexus.
2715%
2716% The format of the GetPixelCacheNexusIndexes() method is:
2717%
2718% IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2719% NexusInfo *nexus_info)
2720%
2721% A description of each parameter follows:
2722%
2723% o cache: the pixel cache.
2724%
2725% o nexus_info: the cache nexus to return the colormap indexes.
2726%
2727*/
2728MagickExport IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2729 NexusInfo *nexus_info)
2730{
2731 CacheInfo
2732 *cache_info;
2733
2734 if (cache == (Cache) NULL)
2735 return((IndexPacket *) NULL);
2736 cache_info=(CacheInfo *) cache;
2737 assert(cache_info->signature == MagickSignature);
2738 if (cache_info->storage_class == UndefinedClass)
2739 return((IndexPacket *) NULL);
2740 return(nexus_info->indexes);
2741}
2742
2743/*
2744%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2745% %
2746% %
2747% %
2748+ G e t P i x e l C a c h e N e x u s P i x e l s %
2749% %
2750% %
2751% %
2752%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2753%
2754% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2755% cache nexus.
2756%
2757% The format of the GetPixelCacheNexusPixels() method is:
2758%
2759% PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2760% NexusInfo *nexus_info)
2761%
2762% A description of each parameter follows:
2763%
2764% o cache: the pixel cache.
2765%
2766% o nexus_info: the cache nexus to return the pixels.
2767%
2768*/
2769MagickExport PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2770 NexusInfo *nexus_info)
2771{
2772 CacheInfo
2773 *cache_info;
2774
2775 if (cache == (Cache) NULL)
2776 return((PixelPacket *) NULL);
2777 cache_info=(CacheInfo *) cache;
2778 assert(cache_info->signature == MagickSignature);
2779 if (cache_info->debug != MagickFalse)
2780 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2781 cache_info->filename);
2782 if (cache_info->storage_class == UndefinedClass)
2783 return((PixelPacket *) NULL);
2784 return(nexus_info->pixels);
2785}
2786
2787/*
2788%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2789% %
2790% %
2791% %
cristy056ba772010-01-02 23:33:54 +00002792+ G e t P i x e l C a c h e P i x e l s %
2793% %
2794% %
2795% %
2796%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2797%
2798% GetPixelCachePixels() returns the pixels associated with the specified image.
2799%
2800% The format of the GetPixelCachePixels() method is:
2801%
cristyf84a1932010-01-03 18:00:18 +00002802% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2803% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002804%
2805% A description of each parameter follows:
2806%
2807% o image: the image.
2808%
2809% o length: the pixel cache length.
2810%
cristyf84a1932010-01-03 18:00:18 +00002811% o exception: return any errors or warnings in this structure.
2812%
cristy056ba772010-01-02 23:33:54 +00002813*/
cristyf84a1932010-01-03 18:00:18 +00002814MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2815 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002816{
2817 CacheInfo
2818 *cache_info;
2819
2820 assert(image != (const Image *) NULL);
2821 assert(image->signature == MagickSignature);
2822 if (image->debug != MagickFalse)
2823 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2824 assert(image->cache != (Cache) NULL);
cristyc4c8d132010-01-07 01:58:38 +00002825 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
cristy056ba772010-01-02 23:33:54 +00002826 assert(cache_info->signature == MagickSignature);
2827 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002828 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002829 return((void *) NULL);
2830 *length=cache_info->length;
2831 return((void *) cache_info->pixels);
2832}
2833
2834/*
2835%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2836% %
2837% %
2838% %
cristyb32b90a2009-09-07 21:45:48 +00002839+ 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 +00002840% %
2841% %
2842% %
2843%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2844%
2845% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2846%
2847% The format of the GetPixelCacheStorageClass() method is:
2848%
2849% ClassType GetPixelCacheStorageClass(Cache cache)
2850%
2851% A description of each parameter follows:
2852%
2853% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2854%
2855% o cache: the pixel cache.
2856%
2857*/
2858MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
2859{
2860 CacheInfo
2861 *cache_info;
2862
2863 assert(cache != (Cache) NULL);
2864 cache_info=(CacheInfo *) cache;
2865 assert(cache_info->signature == MagickSignature);
2866 if (cache_info->debug != MagickFalse)
2867 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2868 cache_info->filename);
2869 return(cache_info->storage_class);
2870}
2871
2872/*
2873%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2874% %
2875% %
2876% %
cristyb32b90a2009-09-07 21:45:48 +00002877+ G e t P i x e l C a c h e T i l e S i z e %
2878% %
2879% %
2880% %
2881%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2882%
2883% GetPixelCacheTileSize() returns the pixel cache tile size.
2884%
2885% The format of the GetPixelCacheTileSize() method is:
2886%
2887% void GetPixelCacheTileSize(const Image *image,unsigned long *width,
2888% unsigned long *height)
2889%
2890% A description of each parameter follows:
2891%
2892% o image: the image.
2893%
2894% o width: the optimize cache tile width in pixels.
2895%
2896% o height: the optimize cache tile height in pixels.
2897%
2898*/
2899MagickExport void GetPixelCacheTileSize(const Image *image,unsigned long *width,
2900 unsigned long *height)
2901{
2902 CacheInfo
2903 *cache_info;
2904
2905 assert(image != (Image *) NULL);
2906 assert(image->signature == MagickSignature);
2907 if (image->debug != MagickFalse)
2908 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2909 assert(image->cache != (Cache) NULL);
2910 cache_info=(CacheInfo *) image->cache;
2911 assert(cache_info->signature == MagickSignature);
2912 *width=2048UL/sizeof(PixelPacket);
2913 if (GetPixelCacheType(image) == DiskCache)
cristydaa97692009-09-13 02:10:35 +00002914 *width=8192UL/sizeof(PixelPacket);
cristyb32b90a2009-09-07 21:45:48 +00002915 *height=(*width);
2916}
2917
2918/*
2919%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2920% %
2921% %
2922% %
2923+ G e t P i x e l C a c h e T y p e %
2924% %
2925% %
2926% %
2927%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2928%
2929% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2930%
2931% The format of the GetPixelCacheType() method is:
2932%
2933% CacheType GetPixelCacheType(const Image *image)
2934%
2935% A description of each parameter follows:
2936%
2937% o image: the image.
2938%
2939*/
2940MagickExport CacheType GetPixelCacheType(const Image *image)
2941{
2942 CacheInfo
2943 *cache_info;
2944
2945 assert(image != (Image *) NULL);
2946 assert(image->signature == MagickSignature);
2947 if (image->debug != MagickFalse)
2948 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2949 assert(image->cache != (Cache) NULL);
2950 cache_info=(CacheInfo *) image->cache;
2951 assert(cache_info->signature == MagickSignature);
2952 return(cache_info->type);
2953}
2954
2955/*
2956%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2957% %
2958% %
2959% %
cristy3ed852e2009-09-05 21:47:34 +00002960+ 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 %
2961% %
2962% %
2963% %
2964%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2965%
2966% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2967% pixel cache. A virtual pixel is any pixel access that is outside the
2968% boundaries of the image cache.
2969%
2970% The format of the GetPixelCacheVirtualMethod() method is:
2971%
2972% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2973%
2974% A description of each parameter follows:
2975%
2976% o image: the image.
2977%
2978*/
2979MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2980{
2981 CacheInfo
2982 *cache_info;
2983
2984 assert(image != (Image *) NULL);
2985 assert(image->signature == MagickSignature);
2986 if (image->debug != MagickFalse)
2987 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2988 assert(image->cache != (Cache) NULL);
2989 cache_info=(CacheInfo *) image->cache;
2990 assert(cache_info->signature == MagickSignature);
2991 return(cache_info->virtual_pixel_method);
2992}
2993
2994/*
2995%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2996% %
2997% %
2998% %
2999+ 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 %
3000% %
3001% %
3002% %
3003%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3004%
3005% GetVirtualIndexesFromCache() returns the indexes associated with the last
3006% call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3007%
3008% The format of the GetVirtualIndexesFromCache() method is:
3009%
3010% IndexPacket *GetVirtualIndexesFromCache(const Image *image)
3011%
3012% A description of each parameter follows:
3013%
3014% o image: the image.
3015%
3016*/
3017static const IndexPacket *GetVirtualIndexesFromCache(const Image *image)
3018{
3019 CacheInfo
3020 *cache_info;
3021
3022 const IndexPacket
3023 *indexes;
3024
3025 long
3026 id;
3027
3028 if (image->debug != MagickFalse)
3029 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3030 cache_info=(CacheInfo *) image->cache;
3031 id=GetOpenMPThreadId();
3032 assert(id < (long) cache_info->number_threads);
3033 indexes=GetVirtualIndexesFromNexus(image->cache,cache_info->nexus_info[id]);
3034 return(indexes);
3035}
3036
3037/*
3038%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3039% %
3040% %
3041% %
3042+ 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 %
3043% %
3044% %
3045% %
3046%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3047%
3048% GetVirtualIndexesFromNexus() returns the indexes associated with the
3049% specified cache nexus.
3050%
3051% The format of the GetVirtualIndexesFromNexus() method is:
3052%
3053% const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
3054% NexusInfo *nexus_info)
3055%
3056% A description of each parameter follows:
3057%
3058% o cache: the pixel cache.
3059%
3060% o nexus_info: the cache nexus to return the colormap indexes.
3061%
3062*/
3063MagickExport const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
3064 NexusInfo *nexus_info)
3065{
3066 CacheInfo
3067 *cache_info;
3068
3069 if (cache == (Cache) NULL)
3070 return((IndexPacket *) NULL);
3071 cache_info=(CacheInfo *) cache;
3072 assert(cache_info->signature == MagickSignature);
3073 if (cache_info->storage_class == UndefinedClass)
3074 return((IndexPacket *) NULL);
3075 return(nexus_info->indexes);
3076}
3077
3078/*
3079%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3080% %
3081% %
3082% %
3083% G e t V i r t u a l I n d e x Q u e u e %
3084% %
3085% %
3086% %
3087%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3088%
3089% GetVirtualIndexQueue() returns the virtual black channel or the
3090% colormap indexes associated with the last call to QueueAuthenticPixels() or
3091% GetVirtualPixels(). NULL is returned if the black channel or colormap
3092% indexes are not available.
3093%
3094% The format of the GetVirtualIndexQueue() method is:
3095%
3096% const IndexPacket *GetVirtualIndexQueue(const Image *image)
3097%
3098% A description of each parameter follows:
3099%
3100% o image: the image.
3101%
3102*/
3103MagickExport const IndexPacket *GetVirtualIndexQueue(const Image *image)
3104{
3105 CacheInfo
3106 *cache_info;
3107
3108 assert(image != (const Image *) NULL);
3109 assert(image->signature == MagickSignature);
3110 if (image->debug != MagickFalse)
3111 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3112 assert(image->cache != (Cache) NULL);
3113 cache_info=(CacheInfo *) image->cache;
3114 assert(cache_info->signature == MagickSignature);
3115 if (cache_info->methods.get_virtual_indexes_from_handler ==
3116 (GetVirtualIndexesFromHandler) NULL)
3117 return((IndexPacket *) NULL);
3118 return(cache_info->methods.get_virtual_indexes_from_handler(image));
3119}
3120
3121/*
3122%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3123% %
3124% %
3125% %
3126+ 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 %
3127% %
3128% %
3129% %
3130%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3131%
3132% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3133% pixel cache as defined by the geometry parameters. A pointer to the pixels
3134% is returned if the pixels are transferred, otherwise a NULL is returned.
3135%
3136% The format of the GetVirtualPixelsFromNexus() method is:
3137%
3138% PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
3139% const VirtualPixelMethod method,const long x,const long y,
3140% const unsigned long columns,const unsigned long rows,
3141% NexusInfo *nexus_info,ExceptionInfo *exception)
3142%
3143% A description of each parameter follows:
3144%
3145% o image: the image.
3146%
3147% o virtual_pixel_method: the virtual pixel method.
3148%
3149% o x,y,columns,rows: These values define the perimeter of a region of
3150% pixels.
3151%
3152% o nexus_info: the cache nexus to acquire.
3153%
3154% o exception: return any errors or warnings in this structure.
3155%
3156*/
3157
3158static long
3159 DitherMatrix[64] =
3160 {
3161 0, 48, 12, 60, 3, 51, 15, 63,
3162 32, 16, 44, 28, 35, 19, 47, 31,
3163 8, 56, 4, 52, 11, 59, 7, 55,
3164 40, 24, 36, 20, 43, 27, 39, 23,
3165 2, 50, 14, 62, 1, 49, 13, 61,
3166 34, 18, 46, 30, 33, 17, 45, 29,
3167 10, 58, 6, 54, 9, 57, 5, 53,
3168 42, 26, 38, 22, 41, 25, 37, 21
3169 };
3170
cristy222528c2010-01-09 23:36:34 +00003171static inline long DitherX(const long x,const unsigned long columns)
cristy3ed852e2009-09-05 21:47:34 +00003172{
3173 long
3174 index;
3175
3176 index=x+DitherMatrix[x & 0x07]-32L;
3177 if (index < 0L)
3178 return(0L);
3179 if (index >= (long) columns)
3180 return((long) columns-1L);
3181 return(index);
3182}
3183
cristy222528c2010-01-09 23:36:34 +00003184static inline long DitherY(const long y,const unsigned long rows)
cristy3ed852e2009-09-05 21:47:34 +00003185{
3186 long
3187 index;
3188
3189 index=y+DitherMatrix[y & 0x07]-32L;
3190 if (index < 0L)
3191 return(0L);
3192 if (index >= (long) rows)
3193 return((long) rows-1L);
3194 return(index);
3195}
3196
cristy222528c2010-01-09 23:36:34 +00003197static inline long EdgeX(const long x,const unsigned long columns)
cristy3ed852e2009-09-05 21:47:34 +00003198{
3199 if (x < 0L)
3200 return(0L);
3201 if (x >= (long) columns)
cristy97be2b92010-01-09 23:37:55 +00003202 return((long) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003203 return(x);
3204}
3205
cristy222528c2010-01-09 23:36:34 +00003206static inline long EdgeY(const long y,const unsigned long rows)
cristy3ed852e2009-09-05 21:47:34 +00003207{
3208 if (y < 0L)
3209 return(0L);
3210 if (y >= (long) rows)
cristy97be2b92010-01-09 23:37:55 +00003211 return((long) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003212 return(y);
3213}
3214
cristy222528c2010-01-09 23:36:34 +00003215static inline long RandomX(RandomInfo *random_info,const unsigned long columns)
cristy3ed852e2009-09-05 21:47:34 +00003216{
3217 return((long) (columns*GetPseudoRandomValue(random_info)));
3218}
3219
cristy222528c2010-01-09 23:36:34 +00003220static inline long RandomY(RandomInfo *random_info,const unsigned long rows)
cristy3ed852e2009-09-05 21:47:34 +00003221{
3222 return((long) (rows*GetPseudoRandomValue(random_info)));
3223}
3224
3225/*
3226 VirtualPixelModulo() computes the remainder of dividing offset by extent. It
3227 returns not only the quotient (tile the offset falls in) but also the positive
3228 remainer within that tile such that 0 <= remainder < extent. This method is
3229 essentially a ldiv() using a floored modulo division rather than the normal
3230 default truncated modulo division.
3231*/
3232static inline MagickModulo VirtualPixelModulo(const long offset,
3233 const unsigned long extent)
3234{
3235 MagickModulo
3236 modulo;
3237
3238 modulo.quotient=offset/(long) extent;
3239 if (offset < 0L)
3240 modulo.quotient--;
3241 modulo.remainder=offset-modulo.quotient*(long) extent;
3242 return(modulo);
3243}
3244
3245MagickExport const PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
3246 const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
3247 const unsigned long columns,const unsigned long rows,NexusInfo *nexus_info,
3248 ExceptionInfo *exception)
3249{
3250 CacheInfo
3251 *cache_info;
3252
cristyc3ec0d42010-04-07 01:18:08 +00003253 IndexPacket
3254 virtual_index;
3255
cristy3ed852e2009-09-05 21:47:34 +00003256 MagickOffsetType
3257 offset;
3258
3259 MagickSizeType
3260 length,
3261 number_pixels;
3262
3263 NexusInfo
3264 **virtual_nexus;
3265
3266 PixelPacket
3267 *pixels,
3268 virtual_pixel;
3269
3270 RectangleInfo
3271 region;
3272
3273 register const IndexPacket
cristyc3ec0d42010-04-07 01:18:08 +00003274 *restrict virtual_indexes;
cristy3ed852e2009-09-05 21:47:34 +00003275
3276 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003277 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003278
3279 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003280 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003281
3282 register long
3283 u,
3284 v;
3285
3286 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003287 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003288
3289 /*
3290 Acquire pixels.
3291 */
3292 if (image->debug != MagickFalse)
3293 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3294 cache_info=(CacheInfo *) image->cache;
cristy4cfbb3f2010-03-14 20:40:23 +00003295 if (cache_info->type == UndefinedCache)
cristy3ed852e2009-09-05 21:47:34 +00003296 return((const PixelPacket *) NULL);
3297 region.x=x;
3298 region.y=y;
3299 region.width=columns;
3300 region.height=rows;
3301 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
3302 if (pixels == (PixelPacket *) NULL)
3303 return((const PixelPacket *) NULL);
cristydf415c82010-03-11 16:47:50 +00003304 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3305 nexus_info->region.x;
3306 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3307 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003308 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3309 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
3310 if ((x >= 0) && ((long) (x+columns) <= (long) cache_info->columns) &&
3311 (y >= 0) && ((long) (y+rows) <= (long) cache_info->rows))
3312 {
3313 MagickBooleanType
3314 status;
3315
3316 /*
3317 Pixel request is inside cache extents.
3318 */
3319 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
3320 return(pixels);
3321 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3322 if (status == MagickFalse)
3323 return((const PixelPacket *) NULL);
3324 if ((cache_info->storage_class == PseudoClass) ||
3325 (cache_info->colorspace == CMYKColorspace))
3326 {
3327 status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
3328 if (status == MagickFalse)
3329 return((const PixelPacket *) NULL);
3330 }
3331 return(pixels);
3332 }
3333 /*
3334 Pixel request is outside cache extents.
3335 */
3336 q=pixels;
3337 indexes=GetPixelCacheNexusIndexes(cache_info,nexus_info);
3338 virtual_nexus=AcquirePixelCacheNexus(1);
3339 if (virtual_nexus == (NexusInfo **) NULL)
3340 {
3341 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3342 "UnableToGetCacheNexus","`%s'",image->filename);
3343 return((const PixelPacket *) NULL);
3344 }
3345 switch (virtual_pixel_method)
3346 {
3347 case BlackVirtualPixelMethod:
3348 {
cristy4789f0d2010-01-10 00:01:06 +00003349 SetRedPixelComponent(&virtual_pixel,0);
3350 SetGreenPixelComponent(&virtual_pixel,0);
3351 SetBluePixelComponent(&virtual_pixel,0);
3352 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003353 break;
3354 }
3355 case GrayVirtualPixelMethod:
3356 {
cristy4789f0d2010-01-10 00:01:06 +00003357 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3358 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3359 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3360 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003361 break;
3362 }
3363 case TransparentVirtualPixelMethod:
3364 {
cristy4789f0d2010-01-10 00:01:06 +00003365 SetRedPixelComponent(&virtual_pixel,0);
3366 SetGreenPixelComponent(&virtual_pixel,0);
3367 SetBluePixelComponent(&virtual_pixel,0);
3368 SetOpacityPixelComponent(&virtual_pixel,TransparentOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003369 break;
3370 }
3371 case MaskVirtualPixelMethod:
3372 case WhiteVirtualPixelMethod:
3373 {
cristy4789f0d2010-01-10 00:01:06 +00003374 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3375 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3376 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3377 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003378 break;
3379 }
3380 default:
3381 {
3382 virtual_pixel=image->background_color;
3383 break;
3384 }
3385 }
cristyc3ec0d42010-04-07 01:18:08 +00003386 virtual_index=0;
cristy3ed852e2009-09-05 21:47:34 +00003387 for (v=0; v < (long) rows; v++)
3388 {
3389 for (u=0; u < (long) columns; u+=length)
3390 {
3391 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
3392 if ((((x+u) < 0) || ((x+u) >= (long) cache_info->columns)) ||
3393 (((y+v) < 0) || ((y+v) >= (long) cache_info->rows)) || (length == 0))
3394 {
3395 MagickModulo
3396 x_modulo,
3397 y_modulo;
3398
3399 /*
3400 Transfer a single pixel.
3401 */
3402 length=(MagickSizeType) 1;
3403 switch (virtual_pixel_method)
3404 {
3405 case BackgroundVirtualPixelMethod:
3406 case ConstantVirtualPixelMethod:
3407 case BlackVirtualPixelMethod:
3408 case GrayVirtualPixelMethod:
3409 case TransparentVirtualPixelMethod:
3410 case MaskVirtualPixelMethod:
3411 case WhiteVirtualPixelMethod:
3412 {
3413 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003414 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003415 break;
3416 }
3417 case EdgeVirtualPixelMethod:
3418 default:
3419 {
3420 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003421 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003422 1UL,1UL,virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003423 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3424 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003425 break;
3426 }
3427 case RandomVirtualPixelMethod:
3428 {
3429 if (cache_info->random_info == (RandomInfo *) NULL)
3430 cache_info->random_info=AcquireRandomInfo();
3431 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003432 RandomX(cache_info->random_info,cache_info->columns),
3433 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003434 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003435 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3436 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003437 break;
3438 }
3439 case DitherVirtualPixelMethod:
3440 {
3441 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003442 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003443 1UL,1UL,virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003444 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3445 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003446 break;
3447 }
3448 case TileVirtualPixelMethod:
3449 {
3450 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3451 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3452 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3453 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3454 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003455 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3456 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003457 break;
3458 }
3459 case MirrorVirtualPixelMethod:
3460 {
3461 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3462 if ((x_modulo.quotient & 0x01) == 1L)
3463 x_modulo.remainder=(long) cache_info->columns-
3464 x_modulo.remainder-1L;
3465 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3466 if ((y_modulo.quotient & 0x01) == 1L)
3467 y_modulo.remainder=(long) cache_info->rows-
3468 y_modulo.remainder-1L;
3469 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3470 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3471 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003472 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3473 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003474 break;
3475 }
3476 case CheckerTileVirtualPixelMethod:
3477 {
3478 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3479 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3480 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3481 {
3482 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003483 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003484 break;
3485 }
3486 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3487 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3488 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003489 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3490 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003491 break;
3492 }
3493 case HorizontalTileVirtualPixelMethod:
3494 {
3495 if (((y+v) < 0) || ((y+v) >= (long) cache_info->rows))
3496 {
3497 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003498 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003499 break;
3500 }
3501 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3502 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3503 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3504 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3505 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003506 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3507 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003508 break;
3509 }
3510 case VerticalTileVirtualPixelMethod:
3511 {
3512 if (((x+u) < 0) || ((x+u) >= (long) cache_info->columns))
3513 {
3514 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003515 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003516 break;
3517 }
3518 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3519 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3520 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3521 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3522 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003523 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3524 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003525 break;
3526 }
3527 case HorizontalTileEdgeVirtualPixelMethod:
3528 {
3529 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3530 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003531 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003532 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003533 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3534 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003535 break;
3536 }
3537 case VerticalTileEdgeVirtualPixelMethod:
3538 {
3539 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3540 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003541 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003542 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003543 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3544 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003545 break;
3546 }
3547 }
3548 if (p == (const PixelPacket *) NULL)
3549 break;
3550 *q++=(*p);
cristyc3ec0d42010-04-07 01:18:08 +00003551 if ((indexes != (IndexPacket *) NULL) &&
3552 (virtual_indexes != (const IndexPacket *) NULL))
3553 *indexes++=(*virtual_indexes);
cristy3ed852e2009-09-05 21:47:34 +00003554 continue;
3555 }
3556 /*
3557 Transfer a run of pixels.
3558 */
3559 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,
3560 (unsigned long) length,1UL,virtual_nexus[0],exception);
3561 if (p == (const PixelPacket *) NULL)
3562 break;
cristyc3ec0d42010-04-07 01:18:08 +00003563 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003564 (void) CopyMagickMemory(q,p,(size_t) length*sizeof(*p));
3565 q+=length;
cristyc3ec0d42010-04-07 01:18:08 +00003566 if ((indexes != (IndexPacket *) NULL) &&
3567 (virtual_indexes != (const IndexPacket *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003568 {
cristyc3ec0d42010-04-07 01:18:08 +00003569 (void) CopyMagickMemory(indexes,virtual_indexes,(size_t) length*
3570 sizeof(*virtual_indexes));
3571 indexes+=length;
cristy3ed852e2009-09-05 21:47:34 +00003572 }
3573 }
3574 }
3575 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3576 return(pixels);
3577}
3578
3579/*
3580%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3581% %
3582% %
3583% %
3584+ G e t V i r t u a l P i x e l C a c h e %
3585% %
3586% %
3587% %
3588%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3589%
3590% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3591% cache as defined by the geometry parameters. A pointer to the pixels
3592% is returned if the pixels are transferred, otherwise a NULL is returned.
3593%
3594% The format of the GetVirtualPixelCache() method is:
3595%
3596% const PixelPacket *GetVirtualPixelCache(const Image *image,
3597% const VirtualPixelMethod virtual_pixel_method,const long x,
3598% const long y,const unsigned long columns,const unsigned long rows,
3599% ExceptionInfo *exception)
3600%
3601% A description of each parameter follows:
3602%
3603% o image: the image.
3604%
3605% o virtual_pixel_method: the virtual pixel method.
3606%
3607% o x,y,columns,rows: These values define the perimeter of a region of
3608% pixels.
3609%
3610% o exception: return any errors or warnings in this structure.
3611%
3612*/
3613static const PixelPacket *GetVirtualPixelCache(const Image *image,
3614 const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
3615 const unsigned long columns,const unsigned long rows,ExceptionInfo *exception)
3616{
3617 CacheInfo
3618 *cache_info;
3619
3620 const PixelPacket
3621 *pixels;
3622
3623 long
3624 id;
3625
3626 if (image->debug != MagickFalse)
3627 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3628 cache_info=(CacheInfo *) image->cache;
3629 id=GetOpenMPThreadId();
3630 assert(id < (long) cache_info->number_threads);
3631 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3632 cache_info->nexus_info[id],exception);
3633 return(pixels);
3634}
3635
3636/*
3637%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3638% %
3639% %
3640% %
3641% G e t V i r t u a l P i x e l Q u e u e %
3642% %
3643% %
3644% %
3645%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3646%
3647% GetVirtualPixelQueue() returns the virtual pixels associated with the
3648% last call to QueueAuthenticPixels() or GetVirtualPixels().
3649%
3650% The format of the GetVirtualPixelQueue() method is:
3651%
3652% const PixelPacket *GetVirtualPixelQueue(const Image image)
3653%
3654% A description of each parameter follows:
3655%
3656% o image: the image.
3657%
3658*/
3659MagickExport const PixelPacket *GetVirtualPixelQueue(const Image *image)
3660{
3661 CacheInfo
3662 *cache_info;
3663
3664 assert(image != (const Image *) NULL);
3665 assert(image->signature == MagickSignature);
3666 if (image->debug != MagickFalse)
3667 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3668 assert(image->cache != (Cache) NULL);
3669 cache_info=(CacheInfo *) image->cache;
3670 assert(cache_info->signature == MagickSignature);
3671 if (cache_info->methods.get_virtual_pixels_handler ==
3672 (GetVirtualPixelsHandler) NULL)
3673 return((PixelPacket *) NULL);
3674 return(cache_info->methods.get_virtual_pixels_handler(image));
3675}
3676
3677/*
3678%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3679% %
3680% %
3681% %
3682% G e t V i r t u a l P i x e l s %
3683% %
3684% %
3685% %
3686%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3687%
3688% GetVirtualPixels() returns an immutable pixel region. If the
3689% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003690% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003691% copy of the pixels or it may point to the original pixels in memory.
3692% Performance is maximized if the selected region is part of one row, or one
3693% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003694% (without a copy) if the image is in memory, or in a memory-mapped file. The
3695% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003696%
3697% Pixels accessed via the returned pointer represent a simple array of type
3698% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
3699% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access
3700% the black color component or to obtain the colormap indexes (of type
3701% IndexPacket) corresponding to the region.
3702%
3703% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3704%
3705% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3706% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3707% GetCacheViewAuthenticPixels() instead.
3708%
3709% The format of the GetVirtualPixels() method is:
3710%
3711% const PixelPacket *GetVirtualPixels(const Image *image,const long x,
3712% const long y,const unsigned long columns,const unsigned long rows,
3713% ExceptionInfo *exception)
3714%
3715% A description of each parameter follows:
3716%
3717% o image: the image.
3718%
3719% o x,y,columns,rows: These values define the perimeter of a region of
3720% pixels.
3721%
3722% o exception: return any errors or warnings in this structure.
3723%
3724*/
3725MagickExport const PixelPacket *GetVirtualPixels(const Image *image,
3726 const long x,const long y,const unsigned long columns,
3727 const unsigned long rows,ExceptionInfo *exception)
3728{
3729 CacheInfo
3730 *cache_info;
3731
3732 const PixelPacket
3733 *pixels;
3734
3735 assert(image != (const Image *) NULL);
3736 assert(image->signature == MagickSignature);
3737 if (image->debug != MagickFalse)
3738 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3739 assert(image->cache != (Cache) NULL);
3740 cache_info=(CacheInfo *) image->cache;
3741 assert(cache_info->signature == MagickSignature);
3742 if (cache_info->methods.get_virtual_pixel_handler ==
3743 (GetVirtualPixelHandler) NULL)
3744 return((const PixelPacket *) NULL);
3745 pixels=cache_info->methods.get_virtual_pixel_handler(image,
3746 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception);
3747 return(pixels);
3748}
3749
3750/*
3751%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3752% %
3753% %
3754% %
3755+ 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 %
3756% %
3757% %
3758% %
3759%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3760%
3761% GetVirtualPixelsCache() returns the pixels associated with the last call
3762% to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3763%
3764% The format of the GetVirtualPixelsCache() method is:
3765%
3766% PixelPacket *GetVirtualPixelsCache(const Image *image)
3767%
3768% A description of each parameter follows:
3769%
3770% o image: the image.
3771%
3772*/
3773static const PixelPacket *GetVirtualPixelsCache(const Image *image)
3774{
3775 CacheInfo
3776 *cache_info;
3777
3778 const PixelPacket
3779 *pixels;
3780
3781 long
3782 id;
3783
3784 if (image->debug != MagickFalse)
3785 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3786 cache_info=(CacheInfo *) image->cache;
3787 id=GetOpenMPThreadId();
3788 assert(id < (long) cache_info->number_threads);
3789 pixels=GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]);
3790 return(pixels);
3791}
3792
3793/*
3794%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3795% %
3796% %
3797% %
3798+ G e t V i r t u a l P i x e l s N e x u s %
3799% %
3800% %
3801% %
3802%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3803%
3804% GetVirtualPixelsNexus() returns the pixels associated with the specified
3805% cache nexus.
3806%
3807% The format of the GetVirtualPixelsNexus() method is:
3808%
3809% const IndexPacket *GetVirtualPixelsNexus(const Cache cache,
3810% NexusInfo *nexus_info)
3811%
3812% A description of each parameter follows:
3813%
3814% o cache: the pixel cache.
3815%
3816% o nexus_info: the cache nexus to return the colormap pixels.
3817%
3818*/
3819MagickExport const PixelPacket *GetVirtualPixelsNexus(const Cache cache,
3820 NexusInfo *nexus_info)
3821{
3822 CacheInfo
3823 *cache_info;
3824
3825 if (cache == (Cache) NULL)
3826 return((PixelPacket *) NULL);
3827 cache_info=(CacheInfo *) cache;
3828 assert(cache_info->signature == MagickSignature);
3829 if (cache_info->storage_class == UndefinedClass)
3830 return((PixelPacket *) NULL);
3831 return((const PixelPacket *) nexus_info->pixels);
3832}
3833
3834/*
3835%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3836% %
3837% %
3838% %
3839+ M a s k P i x e l C a c h e N e x u s %
3840% %
3841% %
3842% %
3843%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3844%
3845% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3846% The method returns MagickTrue if the pixel region is masked, otherwise
3847% MagickFalse.
3848%
3849% The format of the MaskPixelCacheNexus() method is:
3850%
3851% MagickBooleanType MaskPixelCacheNexus(Image *image,
3852% NexusInfo *nexus_info,ExceptionInfo *exception)
3853%
3854% A description of each parameter follows:
3855%
3856% o image: the image.
3857%
3858% o nexus_info: the cache nexus to clip.
3859%
3860% o exception: return any errors or warnings in this structure.
3861%
3862*/
3863
3864static inline void MagickPixelCompositeMask(const MagickPixelPacket *p,
3865 const MagickRealType alpha,const MagickPixelPacket *q,
3866 const MagickRealType beta,MagickPixelPacket *composite)
3867{
3868 MagickRealType
3869 gamma;
3870
3871 if (alpha == TransparentOpacity)
3872 {
3873 *composite=(*q);
3874 return;
3875 }
3876 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3877 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3878 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3879 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3880 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3881 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3882 composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
3883}
3884
3885static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3886 ExceptionInfo *exception)
3887{
3888 CacheInfo
3889 *cache_info;
3890
3891 MagickPixelPacket
3892 alpha,
3893 beta;
3894
3895 MagickSizeType
3896 number_pixels;
3897
3898 NexusInfo
3899 **clip_nexus,
3900 **image_nexus;
3901
3902 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003903 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003904
3905 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003906 *restrict nexus_indexes,
3907 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003908
3909 register long
3910 i;
3911
3912 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003913 *restrict p,
3914 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003915
3916 /*
3917 Apply clip mask.
3918 */
3919 if (image->debug != MagickFalse)
3920 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3921 if (image->mask == (Image *) NULL)
3922 return(MagickFalse);
3923 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
3924 if (cache_info == (Cache) NULL)
3925 return(MagickFalse);
3926 image_nexus=AcquirePixelCacheNexus(1);
3927 clip_nexus=AcquirePixelCacheNexus(1);
3928 if ((image_nexus == (NexusInfo **) NULL) ||
3929 (clip_nexus == (NexusInfo **) NULL))
3930 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy09449f72010-01-23 03:08:36 +00003931 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,
3932 nexus_info->region.y,nexus_info->region.width,nexus_info->region.height,
3933 image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003934 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
3935 q=nexus_info->pixels;
3936 nexus_indexes=nexus_info->indexes;
3937 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3938 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3939 nexus_info->region.height,clip_nexus[0],&image->exception);
3940 GetMagickPixelPacket(image,&alpha);
3941 GetMagickPixelPacket(image,&beta);
3942 number_pixels=(MagickSizeType) nexus_info->region.width*
3943 nexus_info->region.height;
3944 for (i=0; i < (long) number_pixels; i++)
3945 {
3946 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
3947 break;
3948 SetMagickPixelPacket(image,p,indexes+i,&alpha);
3949 SetMagickPixelPacket(image,q,nexus_indexes+i,&beta);
3950 MagickPixelCompositeMask(&beta,(MagickRealType) PixelIntensityToQuantum(r),
3951 &alpha,alpha.opacity,&beta);
cristyce70c172010-01-07 17:15:30 +00003952 q->red=ClampToQuantum(beta.red);
3953 q->green=ClampToQuantum(beta.green);
3954 q->blue=ClampToQuantum(beta.blue);
3955 q->opacity=ClampToQuantum(beta.opacity);
cristy3ed852e2009-09-05 21:47:34 +00003956 if (cache_info->active_index_channel != MagickFalse)
3957 nexus_indexes[i]=indexes[i];
3958 p++;
3959 q++;
3960 r++;
3961 }
3962 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3963 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
3964 if (i < (long) number_pixels)
3965 return(MagickFalse);
3966 return(MagickTrue);
3967}
3968
3969/*
3970%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3971% %
3972% %
3973% %
3974+ O p e n P i x e l C a c h e %
3975% %
3976% %
3977% %
3978%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3979%
3980% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3981% dimensions, allocating space for the image pixels and optionally the
3982% colormap indexes, and memory mapping the cache if it is disk based. The
3983% cache nexus array is initialized as well.
3984%
3985% The format of the OpenPixelCache() method is:
3986%
3987% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3988% ExceptionInfo *exception)
3989%
3990% A description of each parameter follows:
3991%
3992% o image: the image.
3993%
3994% o mode: ReadMode, WriteMode, or IOMode.
3995%
3996% o exception: return any errors or warnings in this structure.
3997%
3998*/
3999
cristyd43a46b2010-01-21 02:13:41 +00004000static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00004001{
4002 cache_info->mapped=MagickFalse;
4003 cache_info->pixels=(PixelPacket *) AcquireMagickMemory((size_t)
4004 cache_info->length);
4005 if (cache_info->pixels == (PixelPacket *) NULL)
4006 {
4007 cache_info->mapped=MagickTrue;
4008 cache_info->pixels=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
4009 cache_info->length);
4010 }
4011}
4012
4013static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
4014{
4015 CacheInfo
4016 *cache_info;
4017
4018 MagickOffsetType
4019 count,
4020 extent,
4021 offset;
4022
4023 cache_info=(CacheInfo *) image->cache;
4024 if (image->debug != MagickFalse)
4025 {
4026 char
4027 format[MaxTextExtent],
4028 message[MaxTextExtent];
4029
cristyb9080c92009-12-01 20:13:26 +00004030 (void) FormatMagickSize(length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00004031 (void) FormatMagickString(message,MaxTextExtent,
cristy2ce15c92010-03-12 14:03:41 +00004032 "extend %s (%s[%d], disk, %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00004033 cache_info->cache_filename,cache_info->file,format);
4034 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4035 }
4036 if (length != (MagickSizeType) ((MagickOffsetType) length))
4037 return(MagickFalse);
4038 extent=(MagickOffsetType) MagickSeek(cache_info->file,0,SEEK_END);
4039 if (extent < 0)
4040 return(MagickFalse);
4041 if ((MagickSizeType) extent >= length)
4042 return(MagickTrue);
4043 offset=(MagickOffsetType) length-1;
4044 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
4045 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
4046}
4047
4048static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
4049 ExceptionInfo *exception)
4050{
4051 char
4052 format[MaxTextExtent],
4053 message[MaxTextExtent];
4054
4055 CacheInfo
4056 *cache_info,
4057 source_info;
4058
4059 MagickSizeType
4060 length,
4061 number_pixels;
4062
4063 MagickStatusType
4064 status;
4065
4066 size_t
4067 packet_size;
4068
4069 unsigned long
4070 columns;
4071
4072 if (image->debug != MagickFalse)
4073 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4074 if ((image->columns == 0) || (image->rows == 0))
4075 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
4076 cache_info=(CacheInfo *) image->cache;
4077 source_info=(*cache_info);
4078 source_info.file=(-1);
4079 (void) FormatMagickString(cache_info->filename,MaxTextExtent,"%s[%ld]",
4080 image->filename,GetImageIndexInList(image));
cristy87528ea2009-09-10 14:53:56 +00004081 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +00004082 cache_info->rows=image->rows;
4083 cache_info->columns=image->columns;
4084 cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
4085 (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
cristy73724512010-04-12 14:43:14 +00004086 if (image->ping != MagickFalse)
4087 {
4088 cache_info->storage_class=image->storage_class;
4089 cache_info->colorspace=image->colorspace;
4090 cache_info->type=PingCache;
4091 cache_info->pixels=(PixelPacket *) NULL;
4092 cache_info->indexes=(IndexPacket *) NULL;
4093 cache_info->length=0;
4094 return(MagickTrue);
4095 }
cristy3ed852e2009-09-05 21:47:34 +00004096 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4097 packet_size=sizeof(PixelPacket);
4098 if (cache_info->active_index_channel != MagickFalse)
4099 packet_size+=sizeof(IndexPacket);
4100 length=number_pixels*packet_size;
4101 columns=(unsigned long) (length/cache_info->rows/packet_size);
4102 if (cache_info->columns != columns)
4103 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4104 image->filename);
4105 cache_info->length=length;
4106 status=AcquireMagickResource(AreaResource,cache_info->length);
4107 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4108 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4109 {
4110 status=AcquireMagickResource(MemoryResource,cache_info->length);
4111 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4112 (cache_info->type == MemoryCache))
4113 {
cristyd43a46b2010-01-21 02:13:41 +00004114 AllocatePixelCachePixels(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004115 if (cache_info->pixels == (PixelPacket *) NULL)
4116 cache_info->pixels=source_info.pixels;
4117 else
4118 {
4119 /*
4120 Create memory pixel cache.
4121 */
4122 if (image->debug != MagickFalse)
4123 {
cristy97e7a572009-12-05 15:07:53 +00004124 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004125 format);
cristy3ed852e2009-09-05 21:47:34 +00004126 (void) FormatMagickString(message,MaxTextExtent,
cristy2ce15c92010-03-12 14:03:41 +00004127 "open %s (%s memory, %lux%lu %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00004128 cache_info->mapped != MagickFalse ? "anonymous" : "heap",
4129 cache_info->columns,cache_info->rows,format);
4130 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4131 message);
4132 }
4133 cache_info->storage_class=image->storage_class;
4134 cache_info->colorspace=image->colorspace;
4135 cache_info->type=MemoryCache;
4136 cache_info->indexes=(IndexPacket *) NULL;
4137 if (cache_info->active_index_channel != MagickFalse)
4138 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4139 number_pixels);
4140 if (source_info.storage_class != UndefinedClass)
4141 {
4142 status|=ClonePixelCachePixels(cache_info,&source_info,
4143 exception);
4144 RelinquishPixelCachePixels(&source_info);
4145 }
4146 return(MagickTrue);
4147 }
4148 }
4149 RelinquishMagickResource(MemoryResource,cache_info->length);
4150 }
4151 /*
4152 Create pixel cache on disk.
4153 */
4154 status=AcquireMagickResource(DiskResource,cache_info->length);
4155 if (status == MagickFalse)
4156 {
4157 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4158 "CacheResourcesExhausted","`%s'",image->filename);
4159 return(MagickFalse);
4160 }
4161 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4162 {
4163 RelinquishMagickResource(DiskResource,cache_info->length);
4164 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4165 image->filename);
4166 return(MagickFalse);
4167 }
4168 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4169 cache_info->length);
4170 if (status == MagickFalse)
4171 {
4172 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4173 image->filename);
4174 return(MagickFalse);
4175 }
4176 cache_info->storage_class=image->storage_class;
4177 cache_info->colorspace=image->colorspace;
4178 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4179 status=AcquireMagickResource(AreaResource,cache_info->length);
4180 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4181 cache_info->type=DiskCache;
4182 else
4183 {
4184 status=AcquireMagickResource(MapResource,cache_info->length);
4185 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4186 (cache_info->type != MemoryCache))
4187 cache_info->type=DiskCache;
4188 else
4189 {
4190 cache_info->pixels=(PixelPacket *) MapBlob(cache_info->file,mode,
4191 cache_info->offset,(size_t) cache_info->length);
4192 if (cache_info->pixels == (PixelPacket *) NULL)
4193 {
4194 cache_info->pixels=source_info.pixels;
4195 cache_info->type=DiskCache;
4196 }
4197 else
4198 {
4199 /*
4200 Create file-backed memory-mapped pixel cache.
4201 */
4202 (void) ClosePixelCacheOnDisk(cache_info);
4203 cache_info->type=MapCache;
4204 cache_info->mapped=MagickTrue;
4205 cache_info->indexes=(IndexPacket *) NULL;
4206 if (cache_info->active_index_channel != MagickFalse)
4207 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4208 number_pixels);
4209 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4210 {
4211 status=ClonePixelCachePixels(cache_info,&source_info,
4212 exception);
4213 RelinquishPixelCachePixels(&source_info);
4214 }
4215 if (image->debug != MagickFalse)
4216 {
cristy97e7a572009-12-05 15:07:53 +00004217 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004218 format);
cristy3ed852e2009-09-05 21:47:34 +00004219 (void) FormatMagickString(message,MaxTextExtent,
cristy2ce15c92010-03-12 14:03:41 +00004220 "open %s (%s[%d], memory-mapped, %lux%lu %sB)",
cristy3ed852e2009-09-05 21:47:34 +00004221 cache_info->filename,cache_info->cache_filename,
4222 cache_info->file,cache_info->columns,cache_info->rows,
4223 format);
4224 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4225 message);
4226 }
4227 return(MagickTrue);
4228 }
4229 }
4230 RelinquishMagickResource(MapResource,cache_info->length);
4231 }
4232 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4233 {
4234 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4235 RelinquishPixelCachePixels(&source_info);
4236 }
4237 if (image->debug != MagickFalse)
4238 {
cristyb9080c92009-12-01 20:13:26 +00004239 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00004240 (void) FormatMagickString(message,MaxTextExtent,
cristy2ce15c92010-03-12 14:03:41 +00004241 "open %s (%s[%d], disk, %lux%lu %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00004242 cache_info->cache_filename,cache_info->file,cache_info->columns,
4243 cache_info->rows,format);
4244 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4245 }
4246 return(MagickTrue);
4247}
4248
4249/*
4250%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4251% %
4252% %
4253% %
4254+ P e r s i s t P i x e l C a c h e %
4255% %
4256% %
4257% %
4258%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4259%
4260% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4261% persistent pixel cache is one that resides on disk and is not destroyed
4262% when the program exits.
4263%
4264% The format of the PersistPixelCache() method is:
4265%
4266% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4267% const MagickBooleanType attach,MagickOffsetType *offset,
4268% ExceptionInfo *exception)
4269%
4270% A description of each parameter follows:
4271%
4272% o image: the image.
4273%
4274% o filename: the persistent pixel cache filename.
4275%
cristy01b7eb02009-09-10 23:10:14 +00004276% o attach: A value other than zero initializes the persistent pixel
4277% cache.
4278%
cristy3ed852e2009-09-05 21:47:34 +00004279% o initialize: A value other than zero initializes the persistent pixel
4280% cache.
4281%
4282% o offset: the offset in the persistent cache to store pixels.
4283%
4284% o exception: return any errors or warnings in this structure.
4285%
4286*/
4287MagickExport MagickBooleanType PersistPixelCache(Image *image,
4288 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4289 ExceptionInfo *exception)
4290{
4291 CacheInfo
4292 *cache_info,
4293 *clone_info;
4294
4295 Image
4296 clone_image;
4297
4298 long
cristy688f07b2009-09-27 15:19:13 +00004299 page_size;
cristy3ed852e2009-09-05 21:47:34 +00004300
4301 MagickBooleanType
4302 status;
4303
4304 assert(image != (Image *) NULL);
4305 assert(image->signature == MagickSignature);
4306 if (image->debug != MagickFalse)
4307 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4308 assert(image->cache != (void *) NULL);
4309 assert(filename != (const char *) NULL);
4310 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004311 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004312 cache_info=(CacheInfo *) image->cache;
4313 assert(cache_info->signature == MagickSignature);
4314 if (attach != MagickFalse)
4315 {
4316 /*
cristy01b7eb02009-09-10 23:10:14 +00004317 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004318 */
4319 if (image->debug != MagickFalse)
4320 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4321 "attach persistent cache");
4322 (void) CopyMagickString(cache_info->cache_filename,filename,
4323 MaxTextExtent);
4324 cache_info->type=DiskCache;
4325 cache_info->offset=(*offset);
4326 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4327 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004328 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004329 return(MagickTrue);
4330 }
cristy01b7eb02009-09-10 23:10:14 +00004331 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4332 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004333 {
cristyf84a1932010-01-03 18:00:18 +00004334 LockSemaphoreInfo(cache_info->semaphore);
cristy09449f72010-01-23 03:08:36 +00004335 if ((cache_info->mode != ReadMode) &&
4336 (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004337 (cache_info->reference_count == 1))
4338 {
4339 int
4340 status;
4341
4342 /*
cristy01b7eb02009-09-10 23:10:14 +00004343 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004344 */
4345 status=rename(cache_info->cache_filename,filename);
4346 if (status == 0)
4347 {
4348 (void) CopyMagickString(cache_info->cache_filename,filename,
4349 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004350 *offset+=cache_info->length+page_size-(cache_info->length %
4351 page_size);
cristyf84a1932010-01-03 18:00:18 +00004352 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004353 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004354 if (image->debug != MagickFalse)
4355 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4356 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004357 return(MagickTrue);
4358 }
4359 }
cristyf84a1932010-01-03 18:00:18 +00004360 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004361 }
4362 /*
cristy01b7eb02009-09-10 23:10:14 +00004363 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004364 */
4365 clone_image=(*image);
4366 clone_info=(CacheInfo *) clone_image.cache;
4367 image->cache=ClonePixelCache(cache_info);
4368 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4369 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4370 cache_info->type=DiskCache;
4371 cache_info->offset=(*offset);
4372 cache_info=(CacheInfo *) image->cache;
4373 status=ClonePixelCacheNexus(cache_info,clone_info,exception);
4374 if (status != MagickFalse)
4375 {
4376 status=OpenPixelCache(image,IOMode,exception);
4377 if (status != MagickFalse)
4378 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
4379 }
cristy688f07b2009-09-27 15:19:13 +00004380 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004381 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4382 return(status);
4383}
4384
4385/*
4386%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4387% %
4388% %
4389% %
4390+ Q u e u e A u t h e n t i c N e x u s %
4391% %
4392% %
4393% %
4394%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4395%
4396% QueueAuthenticNexus() allocates an region to store image pixels as defined
4397% by the region rectangle and returns a pointer to the region. This region is
4398% subsequently transferred from the pixel cache with
4399% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4400% pixels are transferred, otherwise a NULL is returned.
4401%
4402% The format of the QueueAuthenticNexus() method is:
4403%
4404% PixelPacket *QueueAuthenticNexus(Image *image,const long x,const long y,
4405% const unsigned long columns,const unsigned long rows,
4406% NexusInfo *nexus_info,ExceptionInfo *exception)
4407%
4408% A description of each parameter follows:
4409%
4410% o image: the image.
4411%
4412% o x,y,columns,rows: These values define the perimeter of a region of
4413% pixels.
4414%
4415% o nexus_info: the cache nexus to set.
4416%
4417% o exception: return any errors or warnings in this structure.
4418%
4419*/
4420MagickExport PixelPacket *QueueAuthenticNexus(Image *image,const long x,
4421 const long y,const unsigned long columns,const unsigned long rows,
4422 NexusInfo *nexus_info,ExceptionInfo *exception)
4423{
4424 CacheInfo
4425 *cache_info;
4426
4427 MagickOffsetType
4428 offset;
4429
4430 MagickSizeType
4431 number_pixels;
4432
4433 RectangleInfo
4434 region;
4435
4436 /*
4437 Validate pixel cache geometry.
4438 */
4439 cache_info=(CacheInfo *) image->cache;
4440 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4441 {
4442 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4443 "NoPixelsDefinedInCache","`%s'",image->filename);
4444 return((PixelPacket *) NULL);
4445 }
4446 if ((x < 0) || (y < 0) || (x >= (long) cache_info->columns) ||
4447 (y >= (long) cache_info->rows))
4448 {
4449 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4450 "PixelsAreNotAuthentic","`%s'",image->filename);
4451 return((PixelPacket *) NULL);
4452 }
4453 offset=(MagickOffsetType) y*cache_info->columns+x;
4454 if (offset < 0)
4455 return((PixelPacket *) NULL);
4456 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4457 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4458 if ((MagickSizeType) offset >= number_pixels)
4459 return((PixelPacket *) NULL);
4460 /*
4461 Return pixel cache.
4462 */
4463 region.x=x;
4464 region.y=y;
4465 region.width=columns;
4466 region.height=rows;
4467 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4468}
4469
4470/*
4471%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4472% %
4473% %
4474% %
4475+ 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 %
4476% %
4477% %
4478% %
4479%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4480%
4481% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4482% defined by the region rectangle and returns a pointer to the region. This
4483% region is subsequently transferred from the pixel cache with
4484% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4485% pixels are transferred, otherwise a NULL is returned.
4486%
4487% The format of the QueueAuthenticPixelsCache() method is:
4488%
4489% PixelPacket *QueueAuthenticPixelsCache(Image *image,const long x,
4490% const long y,const unsigned long columns,const unsigned long rows,
4491% ExceptionInfo *exception)
4492%
4493% A description of each parameter follows:
4494%
4495% o image: the image.
4496%
4497% o x,y,columns,rows: These values define the perimeter of a region of
4498% pixels.
4499%
4500% o exception: return any errors or warnings in this structure.
4501%
4502*/
4503static PixelPacket *QueueAuthenticPixelsCache(Image *image,const long x,
4504 const long y,const unsigned long columns,const unsigned long rows,
4505 ExceptionInfo *exception)
4506{
4507 CacheInfo
4508 *cache_info;
4509
4510 long
4511 id;
4512
4513 PixelPacket
4514 *pixels;
4515
4516 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickFalse,exception);
4517 if (cache_info == (Cache) NULL)
4518 return((PixelPacket *) NULL);
4519 id=GetOpenMPThreadId();
4520 assert(id < (long) cache_info->number_threads);
4521 pixels=QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4522 exception);
4523 return(pixels);
4524}
4525
4526/*
4527%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4528% %
4529% %
4530% %
4531% Q u e u e A u t h e n t i c P i x e l s %
4532% %
4533% %
4534% %
4535%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4536%
4537% QueueAuthenticPixels() queues a mutable pixel region. If the region is
4538% successfully intialized a pointer to a PixelPacket array representing the
4539% region is returned, otherwise NULL is returned. The returned pointer may
4540% point to a temporary working buffer for the pixels or it may point to the
4541% final location of the pixels in memory.
4542%
4543% Write-only access means that any existing pixel values corresponding to
4544% the region are ignored. This is useful if the initial image is being
4545% created from scratch, or if the existing pixel values are to be
4546% completely replaced without need to refer to their pre-existing values.
4547% The application is free to read and write the pixel buffer returned by
4548% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4549% initialize the pixel array values. Initializing pixel array values is the
4550% application's responsibility.
4551%
4552% Performance is maximized if the selected region is part of one row, or
4553% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004554% pixels in-place (without a copy) if the image is in memory, or in a
4555% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004556% by the user.
4557%
4558% Pixels accessed via the returned pointer represent a simple array of type
4559% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
4560% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
4561% the black color component or the colormap indexes (of type IndexPacket)
4562% corresponding to the region. Once the PixelPacket (and/or IndexPacket)
4563% array has been updated, the changes must be saved back to the underlying
4564% image using SyncAuthenticPixels() or they may be lost.
4565%
4566% The format of the QueueAuthenticPixels() method is:
4567%
4568% PixelPacket *QueueAuthenticPixels(Image *image,const long x,const long y,
4569% const unsigned long columns,const unsigned long rows,
4570% ExceptionInfo *exception)
4571%
4572% A description of each parameter follows:
4573%
4574% o image: the image.
4575%
4576% o x,y,columns,rows: These values define the perimeter of a region of
4577% pixels.
4578%
4579% o exception: return any errors or warnings in this structure.
4580%
4581*/
4582MagickExport PixelPacket *QueueAuthenticPixels(Image *image,const long x,
4583 const long y,const unsigned long columns,const unsigned long rows,
4584 ExceptionInfo *exception)
4585{
4586 CacheInfo
4587 *cache_info;
4588
4589 PixelPacket
4590 *pixels;
4591
4592 assert(image != (Image *) NULL);
4593 assert(image->signature == MagickSignature);
4594 if (image->debug != MagickFalse)
4595 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4596 assert(image->cache != (Cache) NULL);
4597 cache_info=(CacheInfo *) image->cache;
4598 assert(cache_info->signature == MagickSignature);
4599 if (cache_info->methods.queue_authentic_pixels_handler ==
4600 (QueueAuthenticPixelsHandler) NULL)
4601 return((PixelPacket *) NULL);
4602 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4603 rows,exception);
4604 return(pixels);
4605}
4606
4607/*
4608%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4609% %
4610% %
4611% %
4612+ R e a d P i x e l C a c h e I n d e x e s %
4613% %
4614% %
4615% %
4616%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4617%
4618% ReadPixelCacheIndexes() reads colormap indexes from the specified region of
4619% the pixel cache.
4620%
4621% The format of the ReadPixelCacheIndexes() method is:
4622%
4623% MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4624% NexusInfo *nexus_info,ExceptionInfo *exception)
4625%
4626% A description of each parameter follows:
4627%
4628% o cache_info: the pixel cache.
4629%
4630% o nexus_info: the cache nexus to read the colormap indexes.
4631%
4632% o exception: return any errors or warnings in this structure.
4633%
4634*/
4635static MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4636 NexusInfo *nexus_info,ExceptionInfo *exception)
4637{
4638 MagickOffsetType
4639 count,
4640 offset;
4641
4642 MagickSizeType
4643 length,
4644 number_pixels;
4645
4646 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004647 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004648
4649 register long
4650 y;
4651
4652 unsigned long
4653 rows;
4654
4655 if (cache_info->debug != MagickFalse)
4656 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4657 cache_info->filename);
4658 if (cache_info->active_index_channel == MagickFalse)
4659 return(MagickFalse);
4660 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4661 return(MagickTrue);
4662 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4663 nexus_info->region.x;
4664 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
4665 rows=nexus_info->region.height;
4666 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004667 q=nexus_info->indexes;
4668 switch (cache_info->type)
4669 {
4670 case MemoryCache:
4671 case MapCache:
4672 {
4673 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004674 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004675
4676 /*
4677 Read indexes from memory.
4678 */
cristydd341db2010-03-04 19:06:38 +00004679 if ((cache_info->columns == nexus_info->region.width) &&
4680 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4681 {
4682 length=number_pixels;
4683 rows=1UL;
4684 }
cristy3ed852e2009-09-05 21:47:34 +00004685 p=cache_info->indexes+offset;
4686 for (y=0; y < (long) rows; y++)
4687 {
4688 (void) CopyMagickMemory(q,p,(size_t) length);
4689 p+=cache_info->columns;
4690 q+=nexus_info->region.width;
4691 }
4692 break;
4693 }
4694 case DiskCache:
4695 {
4696 /*
4697 Read indexes from disk.
4698 */
4699 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4700 {
4701 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4702 cache_info->cache_filename);
4703 return(MagickFalse);
4704 }
cristydd341db2010-03-04 19:06:38 +00004705 if ((cache_info->columns == nexus_info->region.width) &&
4706 (number_pixels < MagickMaxBufferExtent))
4707 {
4708 length=number_pixels;
4709 rows=1UL;
4710 }
cristy3ed852e2009-09-05 21:47:34 +00004711 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4712 for (y=0; y < (long) rows; y++)
4713 {
4714 count=ReadPixelCacheRegion(cache_info,cache_info->offset+number_pixels*
4715 sizeof(PixelPacket)+offset*sizeof(*q),length,(unsigned char *) q);
4716 if ((MagickSizeType) count < length)
4717 break;
4718 offset+=cache_info->columns;
4719 q+=nexus_info->region.width;
4720 }
4721 if (y < (long) rows)
4722 {
4723 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4724 cache_info->cache_filename);
4725 return(MagickFalse);
4726 }
4727 break;
4728 }
4729 default:
4730 break;
4731 }
4732 if ((cache_info->debug != MagickFalse) &&
4733 (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4734 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
4735 cache_info->filename,nexus_info->region.width,nexus_info->region.height,
4736 nexus_info->region.x,nexus_info->region.y);
4737 return(MagickTrue);
4738}
4739
4740/*
4741%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4742% %
4743% %
4744% %
4745+ R e a d P i x e l C a c h e P i x e l s %
4746% %
4747% %
4748% %
4749%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4750%
4751% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4752% cache.
4753%
4754% The format of the ReadPixelCachePixels() method is:
4755%
4756% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4757% NexusInfo *nexus_info,ExceptionInfo *exception)
4758%
4759% A description of each parameter follows:
4760%
4761% o cache_info: the pixel cache.
4762%
4763% o nexus_info: the cache nexus to read the pixels.
4764%
4765% o exception: return any errors or warnings in this structure.
4766%
4767*/
4768static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4769 NexusInfo *nexus_info,ExceptionInfo *exception)
4770{
4771 MagickOffsetType
4772 count,
4773 offset;
4774
4775 MagickSizeType
4776 length,
4777 number_pixels;
4778
4779 register long
4780 y;
4781
4782 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004783 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004784
4785 unsigned long
4786 rows;
4787
4788 if (cache_info->debug != MagickFalse)
4789 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4790 cache_info->filename);
4791 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4792 return(MagickTrue);
4793 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4794 nexus_info->region.x;
4795 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
4796 rows=nexus_info->region.height;
4797 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004798 q=nexus_info->pixels;
4799 switch (cache_info->type)
4800 {
4801 case MemoryCache:
4802 case MapCache:
4803 {
4804 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004805 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004806
4807 /*
4808 Read pixels from memory.
4809 */
cristydd341db2010-03-04 19:06:38 +00004810 if ((cache_info->columns == nexus_info->region.width) &&
4811 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4812 {
4813 length=number_pixels;
4814 rows=1UL;
4815 }
cristy3ed852e2009-09-05 21:47:34 +00004816 p=cache_info->pixels+offset;
4817 for (y=0; y < (long) rows; y++)
4818 {
4819 (void) CopyMagickMemory(q,p,(size_t) length);
4820 p+=cache_info->columns;
4821 q+=nexus_info->region.width;
4822 }
4823 break;
4824 }
4825 case DiskCache:
4826 {
4827 /*
4828 Read pixels from disk.
4829 */
4830 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4831 {
4832 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4833 cache_info->cache_filename);
4834 return(MagickFalse);
4835 }
cristydd341db2010-03-04 19:06:38 +00004836 if ((cache_info->columns == nexus_info->region.width) &&
4837 (number_pixels < MagickMaxBufferExtent))
4838 {
4839 length=number_pixels;
4840 rows=1UL;
4841 }
cristy3ed852e2009-09-05 21:47:34 +00004842 for (y=0; y < (long) rows; y++)
4843 {
4844 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4845 sizeof(*q),length,(unsigned char *) q);
4846 if ((MagickSizeType) count < length)
4847 break;
4848 offset+=cache_info->columns;
4849 q+=nexus_info->region.width;
4850 }
4851 if (y < (long) rows)
4852 {
4853 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4854 cache_info->cache_filename);
4855 return(MagickFalse);
4856 }
4857 break;
4858 }
4859 default:
4860 break;
4861 }
4862 if ((cache_info->debug != MagickFalse) &&
4863 (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4864 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
4865 cache_info->filename,nexus_info->region.width,nexus_info->region.height,
4866 nexus_info->region.x,nexus_info->region.y);
4867 return(MagickTrue);
4868}
4869
4870/*
4871%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4872% %
4873% %
4874% %
4875+ R e f e r e n c e P i x e l C a c h e %
4876% %
4877% %
4878% %
4879%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4880%
4881% ReferencePixelCache() increments the reference count associated with the
4882% pixel cache returning a pointer to the cache.
4883%
4884% The format of the ReferencePixelCache method is:
4885%
4886% Cache ReferencePixelCache(Cache cache_info)
4887%
4888% A description of each parameter follows:
4889%
4890% o cache_info: the pixel cache.
4891%
4892*/
4893MagickExport Cache ReferencePixelCache(Cache cache)
4894{
4895 CacheInfo
4896 *cache_info;
4897
4898 assert(cache != (Cache *) NULL);
4899 cache_info=(CacheInfo *) cache;
4900 assert(cache_info->signature == MagickSignature);
4901 if (cache_info->debug != MagickFalse)
4902 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4903 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00004904 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004905 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004906 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004907 return(cache_info);
4908}
4909
4910/*
4911%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4912% %
4913% %
4914% %
4915+ S e t P i x e l C a c h e M e t h o d s %
4916% %
4917% %
4918% %
4919%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4920%
4921% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4922%
4923% The format of the SetPixelCacheMethods() method is:
4924%
4925% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4926%
4927% A description of each parameter follows:
4928%
4929% o cache: the pixel cache.
4930%
4931% o cache_methods: Specifies a pointer to a CacheMethods structure.
4932%
4933*/
4934MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4935{
4936 CacheInfo
4937 *cache_info;
4938
4939 GetOneAuthenticPixelFromHandler
4940 get_one_authentic_pixel_from_handler;
4941
4942 GetOneVirtualPixelFromHandler
4943 get_one_virtual_pixel_from_handler;
4944
4945 /*
4946 Set cache pixel methods.
4947 */
4948 assert(cache != (Cache) NULL);
4949 assert(cache_methods != (CacheMethods *) NULL);
4950 cache_info=(CacheInfo *) cache;
4951 assert(cache_info->signature == MagickSignature);
4952 if (cache_info->debug != MagickFalse)
4953 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4954 cache_info->filename);
4955 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4956 cache_info->methods.get_virtual_pixel_handler=
4957 cache_methods->get_virtual_pixel_handler;
4958 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4959 cache_info->methods.destroy_pixel_handler=
4960 cache_methods->destroy_pixel_handler;
4961 if (cache_methods->get_virtual_indexes_from_handler !=
4962 (GetVirtualIndexesFromHandler) NULL)
4963 cache_info->methods.get_virtual_indexes_from_handler=
4964 cache_methods->get_virtual_indexes_from_handler;
4965 if (cache_methods->get_authentic_pixels_handler !=
4966 (GetAuthenticPixelsHandler) NULL)
4967 cache_info->methods.get_authentic_pixels_handler=
4968 cache_methods->get_authentic_pixels_handler;
4969 if (cache_methods->queue_authentic_pixels_handler !=
4970 (QueueAuthenticPixelsHandler) NULL)
4971 cache_info->methods.queue_authentic_pixels_handler=
4972 cache_methods->queue_authentic_pixels_handler;
4973 if (cache_methods->sync_authentic_pixels_handler !=
4974 (SyncAuthenticPixelsHandler) NULL)
4975 cache_info->methods.sync_authentic_pixels_handler=
4976 cache_methods->sync_authentic_pixels_handler;
4977 if (cache_methods->get_authentic_pixels_from_handler !=
4978 (GetAuthenticPixelsFromHandler) NULL)
4979 cache_info->methods.get_authentic_pixels_from_handler=
4980 cache_methods->get_authentic_pixels_from_handler;
4981 if (cache_methods->get_authentic_indexes_from_handler !=
4982 (GetAuthenticIndexesFromHandler) NULL)
4983 cache_info->methods.get_authentic_indexes_from_handler=
4984 cache_methods->get_authentic_indexes_from_handler;
4985 get_one_virtual_pixel_from_handler=
4986 cache_info->methods.get_one_virtual_pixel_from_handler;
4987 if (get_one_virtual_pixel_from_handler !=
4988 (GetOneVirtualPixelFromHandler) NULL)
4989 cache_info->methods.get_one_virtual_pixel_from_handler=
4990 cache_methods->get_one_virtual_pixel_from_handler;
4991 get_one_authentic_pixel_from_handler=
4992 cache_methods->get_one_authentic_pixel_from_handler;
4993 if (get_one_authentic_pixel_from_handler !=
4994 (GetOneAuthenticPixelFromHandler) NULL)
4995 cache_info->methods.get_one_authentic_pixel_from_handler=
4996 cache_methods->get_one_authentic_pixel_from_handler;
4997}
4998
4999/*
5000%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5001% %
5002% %
5003% %
5004+ S e t P i x e l C a c h e N e x u s P i x e l s %
5005% %
5006% %
5007% %
5008%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5009%
5010% SetPixelCacheNexusPixels() defines the region of the cache for the
5011% specified cache nexus.
5012%
5013% The format of the SetPixelCacheNexusPixels() method is:
5014%
5015% PixelPacket SetPixelCacheNexusPixels(const Image *image,
5016% const RectangleInfo *region,NexusInfo *nexus_info,
5017% ExceptionInfo *exception)
5018%
5019% A description of each parameter follows:
5020%
5021% o image: the image.
5022%
5023% o region: A pointer to the RectangleInfo structure that defines the
5024% region of this particular cache nexus.
5025%
5026% o nexus_info: the cache nexus to set.
5027%
5028% o exception: return any errors or warnings in this structure.
5029%
5030*/
5031static PixelPacket *SetPixelCacheNexusPixels(const Image *image,
5032 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
5033{
5034 CacheInfo
5035 *cache_info;
5036
5037 MagickBooleanType
5038 status;
5039
cristy3ed852e2009-09-05 21:47:34 +00005040 MagickSizeType
5041 length,
5042 number_pixels;
5043
5044 if (image->debug != MagickFalse)
5045 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5046 cache_info=(CacheInfo *) image->cache;
5047 assert(cache_info->signature == MagickSignature);
5048 if (cache_info->type == UndefinedCache)
5049 return((PixelPacket *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00005050 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00005051 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
5052 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00005053 {
cristybad067a2010-02-15 17:20:55 +00005054 long
5055 x,
5056 y;
cristy3ed852e2009-09-05 21:47:34 +00005057
cristybad067a2010-02-15 17:20:55 +00005058 x=nexus_info->region.x+nexus_info->region.width-1;
5059 y=nexus_info->region.y+nexus_info->region.height-1;
5060 if (((nexus_info->region.x >= 0) && (x < (long) cache_info->columns) &&
5061 (nexus_info->region.y >= 0) && (y < (long) cache_info->rows)) &&
cristy731c3532010-02-15 15:40:03 +00005062 ((nexus_info->region.height == 1UL) ||
5063 ((nexus_info->region.x == 0) &&
5064 ((nexus_info->region.width == cache_info->columns) ||
5065 ((nexus_info->region.width % cache_info->columns) == 0)))))
5066 {
5067 MagickOffsetType
5068 offset;
5069
5070 /*
5071 Pixels are accessed directly from memory.
5072 */
5073 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5074 nexus_info->region.x;
5075 nexus_info->pixels=cache_info->pixels+offset;
5076 nexus_info->indexes=(IndexPacket *) NULL;
5077 if (cache_info->active_index_channel != MagickFalse)
5078 nexus_info->indexes=cache_info->indexes+offset;
5079 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00005080 }
5081 }
5082 /*
5083 Pixels are stored in a cache region until they are synced to the cache.
5084 */
5085 number_pixels=(MagickSizeType) nexus_info->region.width*
5086 nexus_info->region.height;
5087 length=number_pixels*sizeof(PixelPacket);
5088 if (cache_info->active_index_channel != MagickFalse)
5089 length+=number_pixels*sizeof(IndexPacket);
5090 if (nexus_info->cache == (PixelPacket *) NULL)
5091 {
5092 nexus_info->length=length;
5093 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5094 if (status == MagickFalse)
5095 return((PixelPacket *) NULL);
5096 }
5097 else
5098 if (nexus_info->length != length)
5099 {
5100 RelinquishCacheNexusPixels(nexus_info);
5101 nexus_info->length=length;
5102 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5103 if (status == MagickFalse)
5104 return((PixelPacket *) NULL);
5105 }
5106 nexus_info->pixels=nexus_info->cache;
5107 nexus_info->indexes=(IndexPacket *) NULL;
5108 if (cache_info->active_index_channel != MagickFalse)
5109 nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
5110 return(nexus_info->pixels);
5111}
5112
5113/*
5114%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5115% %
5116% %
5117% %
5118% 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 %
5119% %
5120% %
5121% %
5122%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5123%
5124% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5125% pixel cache and returns the previous setting. A virtual pixel is any pixel
5126% access that is outside the boundaries of the image cache.
5127%
5128% The format of the SetPixelCacheVirtualMethod() method is:
5129%
5130% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5131% const VirtualPixelMethod virtual_pixel_method)
5132%
5133% A description of each parameter follows:
5134%
5135% o image: the image.
5136%
5137% o virtual_pixel_method: choose the type of virtual pixel.
5138%
5139*/
5140MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5141 const VirtualPixelMethod virtual_pixel_method)
5142{
5143 CacheInfo
5144 *cache_info;
5145
5146 VirtualPixelMethod
5147 method;
5148
5149 assert(image != (Image *) NULL);
5150 assert(image->signature == MagickSignature);
5151 if (image->debug != MagickFalse)
5152 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5153 assert(image->cache != (Cache) NULL);
5154 cache_info=(CacheInfo *) image->cache;
5155 assert(cache_info->signature == MagickSignature);
5156 method=cache_info->virtual_pixel_method;
5157 cache_info->virtual_pixel_method=virtual_pixel_method;
5158 return(method);
5159}
5160
5161/*
5162%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5163% %
5164% %
5165% %
5166+ 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 %
5167% %
5168% %
5169% %
5170%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5171%
5172% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5173% in-memory or disk cache. The method returns MagickTrue if the pixel region
5174% is synced, otherwise MagickFalse.
5175%
5176% The format of the SyncAuthenticPixelCacheNexus() method is:
5177%
5178% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5179% NexusInfo *nexus_info,ExceptionInfo *exception)
5180%
5181% A description of each parameter follows:
5182%
5183% o image: the image.
5184%
5185% o nexus_info: the cache nexus to sync.
5186%
5187% o exception: return any errors or warnings in this structure.
5188%
5189*/
5190MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5191 NexusInfo *nexus_info,ExceptionInfo *exception)
5192{
5193 CacheInfo
5194 *cache_info;
5195
5196 MagickBooleanType
5197 status;
5198
5199 /*
5200 Transfer pixels to the cache.
5201 */
5202 assert(image != (Image *) NULL);
5203 assert(image->signature == MagickSignature);
5204 if (image->debug != MagickFalse)
5205 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5206 if (image->cache == (Cache) NULL)
5207 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5208 cache_info=(CacheInfo *) image->cache;
5209 if (cache_info->type == UndefinedCache)
5210 return(MagickFalse);
5211 if ((image->clip_mask != (Image *) NULL) &&
5212 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5213 return(MagickFalse);
5214 if ((image->mask != (Image *) NULL) &&
5215 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5216 return(MagickFalse);
5217 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5218 return(MagickTrue);
5219 assert(cache_info->signature == MagickSignature);
5220 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5221 if ((cache_info->active_index_channel != MagickFalse) &&
5222 (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
5223 return(MagickFalse);
5224 return(status);
5225}
5226
5227/*
5228%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5229% %
5230% %
5231% %
5232+ S y n c A u t h e n t i c P i x e l C a c h e %
5233% %
5234% %
5235% %
5236%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5237%
5238% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5239% or disk cache. The method returns MagickTrue if the pixel region is synced,
5240% otherwise MagickFalse.
5241%
5242% The format of the SyncAuthenticPixelsCache() method is:
5243%
5244% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5245% ExceptionInfo *exception)
5246%
5247% A description of each parameter follows:
5248%
5249% o image: the image.
5250%
5251% o exception: return any errors or warnings in this structure.
5252%
5253*/
5254static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5255 ExceptionInfo *exception)
5256{
5257 CacheInfo
5258 *cache_info;
5259
5260 long
5261 id;
5262
5263 MagickBooleanType
5264 status;
5265
5266 cache_info=(CacheInfo *) image->cache;
5267 id=GetOpenMPThreadId();
5268 assert(id < (long) cache_info->number_threads);
5269 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5270 exception);
5271 return(status);
5272}
5273
5274/*
5275%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5276% %
5277% %
5278% %
5279% S y n c A u t h e n t i c P i x e l s %
5280% %
5281% %
5282% %
5283%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5284%
5285% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5286% The method returns MagickTrue if the pixel region is flushed, otherwise
5287% MagickFalse.
5288%
5289% The format of the SyncAuthenticPixels() method is:
5290%
5291% MagickBooleanType SyncAuthenticPixels(Image *image,
5292% ExceptionInfo *exception)
5293%
5294% A description of each parameter follows:
5295%
5296% o image: the image.
5297%
5298% o exception: return any errors or warnings in this structure.
5299%
5300*/
5301MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5302 ExceptionInfo *exception)
5303{
5304 CacheInfo
5305 *cache_info;
5306
5307 assert(image != (Image *) NULL);
5308 assert(image->signature == MagickSignature);
5309 if (image->debug != MagickFalse)
5310 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5311 assert(image->cache != (Cache) NULL);
5312 cache_info=(CacheInfo *) image->cache;
5313 assert(cache_info->signature == MagickSignature);
5314 if (cache_info->methods.sync_authentic_pixels_handler ==
5315 (SyncAuthenticPixelsHandler) NULL)
5316 return(MagickFalse);
5317 return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
5318}
5319
5320/*
5321%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5322% %
5323% %
5324% %
5325+ W r i t e P i x e l C a c h e I n d e x e s %
5326% %
5327% %
5328% %
5329%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5330%
5331% WritePixelCacheIndexes() writes the colormap indexes to the specified
5332% region of the pixel cache.
5333%
5334% The format of the WritePixelCacheIndexes() method is:
5335%
5336% MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5337% NexusInfo *nexus_info,ExceptionInfo *exception)
5338%
5339% A description of each parameter follows:
5340%
5341% o cache_info: the pixel cache.
5342%
5343% o nexus_info: the cache nexus to write the colormap indexes.
5344%
5345% o exception: return any errors or warnings in this structure.
5346%
5347*/
5348static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5349 NexusInfo *nexus_info,ExceptionInfo *exception)
5350{
5351 MagickOffsetType
5352 count,
5353 offset;
5354
5355 MagickSizeType
5356 length,
5357 number_pixels;
5358
5359 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005360 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005361
5362 register long
5363 y;
5364
5365 unsigned long
5366 rows;
5367
5368 if (cache_info->debug != MagickFalse)
5369 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
5370 cache_info->filename);
5371 if (cache_info->active_index_channel == MagickFalse)
5372 return(MagickFalse);
5373 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5374 return(MagickTrue);
5375 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5376 nexus_info->region.x;
5377 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
5378 rows=nexus_info->region.height;
5379 number_pixels=(MagickSizeType) length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005380 p=nexus_info->indexes;
5381 switch (cache_info->type)
5382 {
5383 case MemoryCache:
5384 case MapCache:
5385 {
5386 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005387 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005388
5389 /*
5390 Write indexes to memory.
5391 */
cristydd341db2010-03-04 19:06:38 +00005392 if ((cache_info->columns == nexus_info->region.width) &&
5393 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5394 {
5395 length=number_pixels;
5396 rows=1UL;
5397 }
cristy3ed852e2009-09-05 21:47:34 +00005398 q=cache_info->indexes+offset;
5399 for (y=0; y < (long) rows; y++)
5400 {
5401 (void) CopyMagickMemory(q,p,(size_t) length);
5402 p+=nexus_info->region.width;
5403 q+=cache_info->columns;
5404 }
5405 break;
5406 }
5407 case DiskCache:
5408 {
5409 /*
5410 Write indexes to disk.
5411 */
5412 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5413 {
5414 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5415 cache_info->cache_filename);
5416 return(MagickFalse);
5417 }
cristydd341db2010-03-04 19:06:38 +00005418 if ((cache_info->columns == nexus_info->region.width) &&
5419 (number_pixels < MagickMaxBufferExtent))
5420 {
5421 length=number_pixels;
5422 rows=1UL;
5423 }
cristy3ed852e2009-09-05 21:47:34 +00005424 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
5425 for (y=0; y < (long) rows; y++)
5426 {
5427 count=WritePixelCacheRegion(cache_info,cache_info->offset+number_pixels*
5428 sizeof(PixelPacket)+offset*sizeof(*p),length,
5429 (const unsigned char *) p);
5430 if ((MagickSizeType) count < length)
5431 break;
5432 p+=nexus_info->region.width;
5433 offset+=cache_info->columns;
5434 }
5435 if (y < (long) rows)
5436 {
5437 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5438 cache_info->cache_filename);
5439 return(MagickFalse);
5440 }
5441 break;
5442 }
5443 default:
5444 break;
5445 }
5446 if ((cache_info->debug != MagickFalse) &&
5447 (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5448 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
5449 cache_info->filename,nexus_info->region.width,nexus_info->region.height,
5450 nexus_info->region.x,nexus_info->region.y);
5451 return(MagickTrue);
5452}
5453
5454/*
5455%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5456% %
5457% %
5458% %
5459+ W r i t e C a c h e P i x e l s %
5460% %
5461% %
5462% %
5463%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5464%
5465% WritePixelCachePixels() writes image pixels to the specified region of the
5466% pixel cache.
5467%
5468% The format of the WritePixelCachePixels() method is:
5469%
5470% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5471% NexusInfo *nexus_info,ExceptionInfo *exception)
5472%
5473% A description of each parameter follows:
5474%
5475% o cache_info: the pixel cache.
5476%
5477% o nexus_info: the cache nexus to write the pixels.
5478%
5479% o exception: return any errors or warnings in this structure.
5480%
5481*/
5482static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5483 NexusInfo *nexus_info,ExceptionInfo *exception)
5484{
5485 MagickOffsetType
5486 count,
5487 offset;
5488
5489 MagickSizeType
5490 length,
5491 number_pixels;
5492
cristy3ed852e2009-09-05 21:47:34 +00005493 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005494 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005495
cristy25ffffb2009-12-07 17:15:07 +00005496 register long
5497 y;
5498
cristy3ed852e2009-09-05 21:47:34 +00005499 unsigned long
5500 rows;
5501
5502 if (cache_info->debug != MagickFalse)
5503 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
5504 cache_info->filename);
5505 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5506 return(MagickTrue);
5507 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5508 nexus_info->region.x;
5509 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
5510 rows=nexus_info->region.height;
5511 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005512 p=nexus_info->pixels;
5513 switch (cache_info->type)
5514 {
5515 case MemoryCache:
5516 case MapCache:
5517 {
5518 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005519 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005520
5521 /*
5522 Write pixels to memory.
5523 */
cristydd341db2010-03-04 19:06:38 +00005524 if ((cache_info->columns == nexus_info->region.width) &&
5525 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5526 {
5527 length=number_pixels;
5528 rows=1UL;
5529 }
cristy3ed852e2009-09-05 21:47:34 +00005530 q=cache_info->pixels+offset;
5531 for (y=0; y < (long) rows; y++)
5532 {
5533 (void) CopyMagickMemory(q,p,(size_t) length);
5534 p+=nexus_info->region.width;
5535 q+=cache_info->columns;
5536 }
5537 break;
5538 }
5539 case DiskCache:
5540 {
5541 /*
5542 Write pixels to disk.
5543 */
5544 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5545 {
5546 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5547 cache_info->cache_filename);
5548 return(MagickFalse);
5549 }
cristydd341db2010-03-04 19:06:38 +00005550 if ((cache_info->columns == nexus_info->region.width) &&
5551 (number_pixels < MagickMaxBufferExtent))
5552 {
5553 length=number_pixels;
5554 rows=1UL;
5555 }
cristy3ed852e2009-09-05 21:47:34 +00005556 for (y=0; y < (long) rows; y++)
5557 {
5558 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5559 sizeof(*p),length,(const unsigned char *) p);
5560 if ((MagickSizeType) count < length)
5561 break;
5562 p+=nexus_info->region.width;
5563 offset+=cache_info->columns;
5564 }
5565 if (y < (long) rows)
5566 {
5567 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5568 cache_info->cache_filename);
5569 return(MagickFalse);
5570 }
5571 break;
5572 }
5573 default:
5574 break;
5575 }
5576 if ((cache_info->debug != MagickFalse) &&
5577 (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5578 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
5579 cache_info->filename,nexus_info->region.width,nexus_info->region.height,
5580 nexus_info->region.x,nexus_info->region.y);
5581 return(MagickTrue);
5582}