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