blob: 8379c66b917282739df487954cea050bc967515b [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)
cristy9e116922010-02-12 20:58:13 +0000697 {
698 /*
699 Close least recently used cache.
700 */
701 (void) close(q->file);
702 q->file=(-1);
703 }
cristyf84a1932010-01-03 18:00:18 +0000704 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000705}
706
707static inline MagickSizeType MagickMax(const MagickSizeType x,
708 const MagickSizeType y)
709{
710 if (x > y)
711 return(x);
712 return(y);
713}
714
715static inline MagickSizeType MagickMin(const MagickSizeType x,
716 const MagickSizeType y)
717{
718 if (x < y)
719 return(x);
720 return(y);
721}
722
723static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
724 const MapMode mode)
725{
726 int
727 file;
728
729 /*
730 Open pixel cache on disk.
731 */
cristyf84a1932010-01-03 18:00:18 +0000732 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000733 if (cache_info->file != -1)
734 {
cristyf84a1932010-01-03 18:00:18 +0000735 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000736 return(MagickTrue); /* cache already open */
737 }
738 LimitPixelCacheDescriptors();
739 if (*cache_info->cache_filename == '\0')
740 file=AcquireUniqueFileResource(cache_info->cache_filename);
741 else
742 switch (mode)
743 {
744 case ReadMode:
745 {
746 file=open(cache_info->cache_filename,O_RDONLY | O_BINARY);
747 break;
748 }
749 case WriteMode:
750 {
751 file=open(cache_info->cache_filename,O_WRONLY | O_CREAT | O_BINARY |
752 O_EXCL,S_MODE);
753 if (file == -1)
754 file=open(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
755 break;
756 }
757 case IOMode:
758 default:
759 {
760 file=open(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
761 O_EXCL,S_MODE);
762 if (file == -1)
763 file=open(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
764 break;
765 }
766 }
767 if (file == -1)
768 {
cristyf84a1932010-01-03 18:00:18 +0000769 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000770 return(MagickFalse);
771 }
772 (void) AcquireMagickResource(FileResource,1);
773 cache_info->file=file;
774 cache_info->timestamp=time(0);
cristyf84a1932010-01-03 18:00:18 +0000775 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000776 return(MagickTrue);
777}
778
779static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
780 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000781 unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000782{
783 register MagickOffsetType
784 i;
785
786 ssize_t
787 count;
788
789#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000790 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000791 cache_info->timestamp=time(0);
792 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
793 {
cristyf84a1932010-01-03 18:00:18 +0000794 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000795 return((MagickOffsetType) -1);
796 }
797#endif
798 count=0;
799 for (i=0; i < (MagickOffsetType) length; i+=count)
800 {
801#if !defined(MAGICKCORE_HAVE_PREAD)
802 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
803 (MagickSizeType) SSIZE_MAX));
804#else
805 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
806 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
807#endif
808 if (count > 0)
809 continue;
810 count=0;
811 if (errno != EINTR)
812 {
813 i=(-1);
814 break;
815 }
816 }
817#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000818 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000819#endif
820 return(i);
821}
822
823static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
824 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000825 const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000826{
827 register MagickOffsetType
828 i;
829
830 ssize_t
831 count;
832
833#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000834 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000835 cache_info->timestamp=time(0);
836 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
837 {
cristyf84a1932010-01-03 18:00:18 +0000838 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000839 return((MagickOffsetType) -1);
840 }
841#endif
842 count=0;
843 for (i=0; i < (MagickOffsetType) length; i+=count)
844 {
845#if !defined(MAGICKCORE_HAVE_PWRITE)
846 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
847 (MagickSizeType) SSIZE_MAX));
848#else
849 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
850 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
851#endif
852 if (count > 0)
853 continue;
854 count=0;
855 if (errno != EINTR)
856 {
857 i=(-1);
858 break;
859 }
860 }
861#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000862 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000863#endif
864 return(i);
865}
866
867static MagickBooleanType CloneDiskToDiskPixelCache(CacheInfo *clone_info,
868 CacheInfo *cache_info,ExceptionInfo *exception)
869{
870 MagickOffsetType
871 count,
872 offset,
873 source_offset;
874
875 MagickSizeType
876 length;
877
878 register long
879 y;
880
881 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000882 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +0000883
884 unsigned long
885 columns,
886 rows;
887
888 if (cache_info->debug != MagickFalse)
889 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
890 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
891 {
892 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
893 clone_info->cache_filename);
894 return(MagickFalse);
895 }
896 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
897 {
898 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
899 cache_info->cache_filename);
900 return(MagickFalse);
901 }
902 columns=(unsigned long) MagickMin(clone_info->columns,cache_info->columns);
903 rows=(unsigned long) MagickMin(clone_info->rows,cache_info->rows);
904 if ((clone_info->active_index_channel != MagickFalse) &&
905 (cache_info->active_index_channel != MagickFalse))
906 {
907 register IndexPacket
908 *indexes;
909
910 /*
911 Clone cache indexes.
912 */
913 length=MagickMax(clone_info->columns,cache_info->columns)*
914 sizeof(*indexes);
915 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
916 if (indexes == (IndexPacket *) NULL)
917 {
918 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
919 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
920 return(MagickFalse);
921 }
922 (void) ResetMagickMemory(indexes,0,(size_t) length);
923 length=columns*sizeof(*indexes);
924 source_offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
925 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
926 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
927 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
928 for (y=0; y < (long) rows; y++)
929 {
930 source_offset-=cache_info->columns*sizeof(*indexes);
931 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
932 length,(unsigned char *) indexes);
933 if ((MagickSizeType) count != length)
934 break;
935 offset-=clone_info->columns*sizeof(*indexes);
936 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
937 (unsigned char *) indexes);
938 if ((MagickSizeType) count != length)
939 break;
940 }
941 if (y < (long) rows)
942 {
943 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
944 ThrowFileException(exception,CacheError,"UnableToCloneCache",
945 cache_info->cache_filename);
946 return(MagickFalse);
947 }
948 if (clone_info->columns > cache_info->columns)
949 {
950 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
951 (void) ResetMagickMemory(indexes,0,(size_t) length);
952 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
953 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
954 for (y=0; y < (long) rows; y++)
955 {
956 offset-=clone_info->columns*sizeof(*indexes);
957 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
958 length,(unsigned char *) indexes);
959 if ((MagickSizeType) count != length)
960 break;
961 }
962 if (y < (long) rows)
963 {
964 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
965 ThrowFileException(exception,CacheError,"UnableToCloneCache",
966 cache_info->cache_filename);
967 return(MagickFalse);
968 }
969 }
970 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
971 }
972 /*
973 Clone cache pixels.
974 */
975 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
976 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
977 if (pixels == (PixelPacket *) NULL)
978 {
979 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
980 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
981 return(MagickFalse);
982 }
983 (void) ResetMagickMemory(pixels,0,(size_t) length);
984 length=columns*sizeof(*pixels);
985 source_offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
986 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
987 for (y=0; y < (long) rows; y++)
988 {
989 source_offset-=cache_info->columns*sizeof(*pixels);
990 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
991 length,(unsigned char *) pixels);
992 if ((MagickSizeType) count != length)
993 break;
994 offset-=clone_info->columns*sizeof(*pixels);
995 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
996 (unsigned char *) pixels);
997 if ((MagickSizeType) count != length)
998 break;
999 }
1000 if (y < (long) rows)
1001 {
1002 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1003 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1004 cache_info->cache_filename);
1005 return(MagickFalse);
1006 }
1007 if (clone_info->columns > cache_info->columns)
1008 {
1009 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
1010 sizeof(*pixels);
1011 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1012 (void) ResetMagickMemory(pixels,0,(size_t) length);
1013 for (y=0; y < (long) rows; y++)
1014 {
1015 offset-=clone_info->columns*sizeof(*pixels);
1016 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1017 (unsigned char *) pixels);
1018 if ((MagickSizeType) count != length)
1019 break;
1020 }
1021 if (y < (long) rows)
1022 {
1023 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1024 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1025 cache_info->cache_filename);
1026 return(MagickFalse);
1027 }
1028 }
1029 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1030 return(MagickTrue);
1031}
1032
1033static MagickBooleanType CloneDiskToMemoryPixelCache(CacheInfo *clone_info,
1034 CacheInfo *cache_info,ExceptionInfo *exception)
1035{
1036 MagickOffsetType
1037 count,
1038 offset;
1039
1040 MagickSizeType
1041 length;
1042
1043 register long
1044 y;
1045
1046 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001047 *restrict pixels,
1048 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00001049
1050 unsigned long
1051 columns,
1052 rows;
1053
1054 if (cache_info->debug != MagickFalse)
1055 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
1056 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
1057 {
1058 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1059 cache_info->cache_filename);
1060 return(MagickFalse);
1061 }
1062 columns=(unsigned long) MagickMin(clone_info->columns,cache_info->columns);
1063 rows=(unsigned long) MagickMin(clone_info->rows,cache_info->rows);
1064 if ((clone_info->active_index_channel != MagickFalse) &&
1065 (cache_info->active_index_channel != MagickFalse))
1066 {
1067 register IndexPacket
1068 *indexes,
1069 *q;
1070
1071 /*
1072 Clone cache indexes.
1073 */
1074 length=MagickMax(clone_info->columns,cache_info->columns)*
1075 sizeof(*indexes);
1076 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1077 if (indexes == (IndexPacket *) NULL)
1078 {
1079 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1080 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1081 return(MagickFalse);
1082 }
1083 (void) ResetMagickMemory(indexes,0,(size_t) length);
1084 length=columns*sizeof(IndexPacket);
1085 offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
1086 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
1087 q=clone_info->indexes+clone_info->columns*rows;
1088 for (y=0; y < (long) rows; y++)
1089 {
1090 offset-=cache_info->columns*sizeof(IndexPacket);
1091 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,
1092 length,(unsigned char *) indexes);
1093 if ((MagickSizeType) count != length)
1094 break;
1095 q-=clone_info->columns;
1096 (void) CopyMagickMemory(q,indexes,(size_t) length);
1097 if ((MagickSizeType) count != length)
1098 break;
1099 }
1100 if (y < (long) rows)
1101 {
1102 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1103 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1104 cache_info->cache_filename);
1105 return(MagickFalse);
1106 }
1107 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1108 }
1109 /*
1110 Clone cache pixels.
1111 */
1112 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1113 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1114 if (pixels == (PixelPacket *) NULL)
1115 {
1116 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1117 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1118 return(MagickFalse);
1119 }
1120 (void) ResetMagickMemory(pixels,0,(size_t) length);
1121 length=columns*sizeof(*pixels);
1122 offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
1123 q=clone_info->pixels+clone_info->columns*rows;
1124 for (y=0; y < (long) rows; y++)
1125 {
1126 offset-=cache_info->columns*sizeof(*pixels);
1127 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,length,
1128 (unsigned char *) pixels);
1129 if ((MagickSizeType) count != length)
1130 break;
1131 q-=clone_info->columns;
1132 (void) CopyMagickMemory(q,pixels,(size_t) length);
1133 }
1134 if (y < (long) rows)
1135 {
1136 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1137 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1138 cache_info->cache_filename);
1139 return(MagickFalse);
1140 }
1141 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1142 return(MagickTrue);
1143}
1144
1145static MagickBooleanType CloneMemoryToDiskPixelCache(CacheInfo *clone_info,
1146 CacheInfo *cache_info,ExceptionInfo *exception)
1147{
1148 MagickOffsetType
1149 count,
1150 offset;
1151
1152 MagickSizeType
1153 length;
1154
1155 register long
1156 y;
1157
1158 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001159 *restrict p,
1160 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +00001161
1162 unsigned long
1163 columns,
1164 rows;
1165
1166 if (cache_info->debug != MagickFalse)
1167 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
1168 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
1169 {
1170 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1171 clone_info->cache_filename);
1172 return(MagickFalse);
1173 }
1174 columns=(unsigned long) MagickMin(clone_info->columns,cache_info->columns);
1175 rows=(unsigned long) MagickMin(clone_info->rows,cache_info->rows);
1176 if ((clone_info->active_index_channel != MagickFalse) &&
1177 (cache_info->active_index_channel != MagickFalse))
1178 {
1179 register IndexPacket
1180 *p,
1181 *indexes;
1182
1183 /*
1184 Clone cache indexes.
1185 */
1186 length=MagickMax(clone_info->columns,cache_info->columns)*
1187 sizeof(*indexes);
1188 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1189 if (indexes == (IndexPacket *) NULL)
1190 {
1191 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1192 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1193 return(MagickFalse);
1194 }
1195 (void) ResetMagickMemory(indexes,0,(size_t) length);
1196 length=columns*sizeof(*indexes);
1197 p=cache_info->indexes+cache_info->columns*rows;
1198 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1199 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
1200 for (y=0; y < (long) rows; y++)
1201 {
1202 p-=cache_info->columns;
1203 (void) CopyMagickMemory(indexes,p,(size_t) length);
1204 offset-=clone_info->columns*sizeof(*indexes);
1205 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1206 (unsigned char *) indexes);
1207 if ((MagickSizeType) count != length)
1208 break;
1209 }
1210 if (y < (long) rows)
1211 {
1212 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1213 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1214 cache_info->cache_filename);
1215 return(MagickFalse);
1216 }
1217 if (clone_info->columns > cache_info->columns)
1218 {
1219 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
1220 (void) ResetMagickMemory(indexes,0,(size_t) length);
1221 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1222 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
1223 for (y=0; y < (long) rows; y++)
1224 {
1225 offset-=clone_info->columns*sizeof(*indexes);
1226 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
1227 length,(unsigned char *) indexes);
1228 if ((MagickSizeType) count != length)
1229 break;
1230 }
1231 if (y < (long) rows)
1232 {
1233 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1234 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1235 cache_info->cache_filename);
1236 return(MagickFalse);
1237 }
1238 }
1239 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1240 }
1241 /*
1242 Clone cache pixels.
1243 */
1244 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1245 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1246 if (pixels == (PixelPacket *) NULL)
1247 {
1248 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1249 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1250 return(MagickFalse);
1251 }
1252 (void) ResetMagickMemory(pixels,0,(size_t) length);
1253 length=columns*sizeof(*pixels);
1254 p=cache_info->pixels+cache_info->columns*rows;
1255 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
1256 for (y=0; y < (long) rows; y++)
1257 {
1258 p-=cache_info->columns;
1259 (void) CopyMagickMemory(pixels,p,(size_t) length);
1260 offset-=clone_info->columns*sizeof(*pixels);
1261 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1262 (unsigned char *) pixels);
1263 if ((MagickSizeType) count != length)
1264 break;
1265 }
1266 if (y < (long) rows)
1267 {
1268 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1269 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1270 cache_info->cache_filename);
1271 return(MagickFalse);
1272 }
1273 if (clone_info->columns > cache_info->columns)
1274 {
1275 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
1276 sizeof(*pixels);
1277 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1278 (void) ResetMagickMemory(pixels,0,(size_t) length);
1279 for (y=0; y < (long) rows; y++)
1280 {
1281 offset-=clone_info->columns*sizeof(*pixels);
1282 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1283 (unsigned char *) pixels);
1284 if ((MagickSizeType) count != length)
1285 break;
1286 }
1287 if (y < (long) rows)
1288 {
1289 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1290 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1291 cache_info->cache_filename);
1292 return(MagickFalse);
1293 }
1294 }
1295 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1296 return(MagickTrue);
1297}
1298
1299static MagickBooleanType CloneMemoryToMemoryPixelCache(CacheInfo *clone_info,
1300 CacheInfo *cache_info,ExceptionInfo *magick_unused(exception))
1301{
1302 register long
1303 y;
1304
1305 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001306 *restrict pixels,
1307 *restrict source_pixels;
cristy3ed852e2009-09-05 21:47:34 +00001308
1309 size_t
1310 length;
1311
1312 unsigned long
1313 columns,
1314 rows;
1315
1316 if (cache_info->debug != MagickFalse)
1317 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
1318 columns=(unsigned long) MagickMin(clone_info->columns,cache_info->columns);
1319 rows=(unsigned long) MagickMin(clone_info->rows,cache_info->rows);
1320 if ((clone_info->active_index_channel != MagickFalse) &&
1321 (cache_info->active_index_channel != MagickFalse))
1322 {
1323 register IndexPacket
1324 *indexes,
1325 *source_indexes;
1326
1327 /*
1328 Clone cache indexes.
1329 */
1330 length=columns*sizeof(*indexes);
1331 if (clone_info->columns == cache_info->columns)
1332 (void) CopyMagickMemory(clone_info->indexes,cache_info->indexes,
1333 length*rows);
1334 else
1335 {
1336 source_indexes=cache_info->indexes+cache_info->columns*rows;
1337 indexes=clone_info->indexes+clone_info->columns*rows;
1338 for (y=0; y < (long) rows; y++)
1339 {
1340 source_indexes-=cache_info->columns;
1341 indexes-=clone_info->columns;
1342 (void) CopyMagickMemory(indexes,source_indexes,length);
1343 }
1344 if (clone_info->columns > cache_info->columns)
1345 {
1346 length=(clone_info->columns-cache_info->columns)*
1347 sizeof(*indexes);
1348 indexes=clone_info->indexes+clone_info->columns*rows+
1349 cache_info->columns;
1350 for (y=0; y < (long) rows; y++)
1351 {
1352 indexes-=clone_info->columns;
1353 (void) ResetMagickMemory(indexes,0,length);
1354 }
1355 }
1356 }
1357 }
1358 /*
1359 Clone cache pixels.
1360 */
1361 length=columns*sizeof(*pixels);
1362 if (clone_info->columns == cache_info->columns)
1363 (void) CopyMagickMemory(clone_info->pixels,cache_info->pixels,length*rows);
1364 else
1365 {
1366 source_pixels=cache_info->pixels+cache_info->columns*rows;
1367 pixels=clone_info->pixels+clone_info->columns*rows;
1368 for (y=0; y < (long) rows; y++)
1369 {
1370 source_pixels-=cache_info->columns;
1371 pixels-=clone_info->columns;
1372 (void) CopyMagickMemory(pixels,source_pixels,length);
1373 }
1374 if (clone_info->columns > cache_info->columns)
1375 {
1376 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1377 pixels=clone_info->pixels+clone_info->columns*rows+
1378 cache_info->columns;
1379 for (y=0; y < (long) rows; y++)
1380 {
1381 pixels-=clone_info->columns;
1382 (void) ResetMagickMemory(pixels,0,length);
1383 }
1384 }
1385 }
1386 return(MagickTrue);
1387}
1388
1389static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1390 CacheInfo *cache_info,ExceptionInfo *exception)
1391{
1392 if ((clone_info->type != DiskCache) && (cache_info->type != DiskCache))
1393 return(CloneMemoryToMemoryPixelCache(clone_info,cache_info,exception));
1394 if ((clone_info->type == DiskCache) && (cache_info->type == DiskCache))
1395 return(CloneDiskToDiskPixelCache(clone_info,cache_info,exception));
1396 if (cache_info->type == DiskCache)
1397 return(CloneDiskToMemoryPixelCache(clone_info,cache_info,exception));
1398 return(CloneMemoryToDiskPixelCache(clone_info,cache_info,exception));
1399}
1400
1401/*
1402%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1403% %
1404% %
1405% %
1406+ C l o n e P i x e l C a c h e M e t h o d s %
1407% %
1408% %
1409% %
1410%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1411%
1412% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1413% another.
1414%
1415% The format of the ClonePixelCacheMethods() method is:
1416%
1417% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1418%
1419% A description of each parameter follows:
1420%
1421% o clone: Specifies a pointer to a Cache structure.
1422%
1423% o cache: the pixel cache.
1424%
1425*/
1426MagickExport void ClonePixelCacheMethods(Cache clone,const Cache cache)
1427{
1428 CacheInfo
1429 *cache_info,
1430 *source_info;
1431
1432 assert(clone != (Cache) NULL);
1433 source_info=(CacheInfo *) clone;
1434 assert(source_info->signature == MagickSignature);
1435 if (source_info->debug != MagickFalse)
1436 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1437 source_info->filename);
1438 assert(cache != (Cache) NULL);
1439 cache_info=(CacheInfo *) cache;
1440 assert(cache_info->signature == MagickSignature);
1441 source_info->methods=cache_info->methods;
1442}
1443
1444/*
1445%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1446% %
1447% %
1448% %
1449+ D e s t r o y I m a g e P i x e l C a c h e %
1450% %
1451% %
1452% %
1453%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1454%
1455% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1456%
1457% The format of the DestroyImagePixelCache() method is:
1458%
1459% void DestroyImagePixelCache(Image *image)
1460%
1461% A description of each parameter follows:
1462%
1463% o image: the image.
1464%
1465*/
1466static void DestroyImagePixelCache(Image *image)
1467{
1468 assert(image != (Image *) NULL);
1469 assert(image->signature == MagickSignature);
1470 if (image->debug != MagickFalse)
1471 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1472 if (image->cache == (void *) NULL)
1473 return;
1474 image->cache=DestroyPixelCache(image->cache);
1475}
1476
1477/*
1478%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1479% %
1480% %
1481% %
1482+ D e s t r o y I m a g e P i x e l s %
1483% %
1484% %
1485% %
1486%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1487%
1488% DestroyImagePixels() deallocates memory associated with the pixel cache.
1489%
1490% The format of the DestroyImagePixels() method is:
1491%
1492% void DestroyImagePixels(Image *image)
1493%
1494% A description of each parameter follows:
1495%
1496% o image: the image.
1497%
1498*/
1499MagickExport void DestroyImagePixels(Image *image)
1500{
1501 CacheInfo
1502 *cache_info;
1503
1504 assert(image != (const Image *) NULL);
1505 assert(image->signature == MagickSignature);
1506 if (image->debug != MagickFalse)
1507 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1508 assert(image->cache != (Cache) NULL);
1509 cache_info=(CacheInfo *) image->cache;
1510 assert(cache_info->signature == MagickSignature);
1511 if (cache_info->methods.destroy_pixel_handler == (DestroyPixelHandler) NULL)
1512 return;
1513 cache_info->methods.destroy_pixel_handler(image);
1514}
1515
1516/*
1517%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1518% %
1519% %
1520% %
1521+ D e s t r o y P i x e l C a c h e %
1522% %
1523% %
1524% %
1525%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1526%
1527% DestroyPixelCache() deallocates memory associated with the pixel cache.
1528%
1529% The format of the DestroyPixelCache() method is:
1530%
1531% Cache DestroyPixelCache(Cache cache)
1532%
1533% A description of each parameter follows:
1534%
1535% o cache: the pixel cache.
1536%
1537*/
1538
1539static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1540{
1541 switch (cache_info->type)
1542 {
1543 case MemoryCache:
1544 {
1545 if (cache_info->mapped == MagickFalse)
1546 cache_info->pixels=(PixelPacket *) RelinquishMagickMemory(
1547 cache_info->pixels);
1548 else
1549 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,
1550 (size_t) cache_info->length);
1551 RelinquishMagickResource(MemoryResource,cache_info->length);
1552 break;
1553 }
1554 case MapCache:
1555 {
1556 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,(size_t)
1557 cache_info->length);
1558 RelinquishMagickResource(MapResource,cache_info->length);
1559 }
1560 case DiskCache:
1561 {
1562 if (cache_info->file != -1)
1563 (void) ClosePixelCacheOnDisk(cache_info);
1564 RelinquishMagickResource(DiskResource,cache_info->length);
1565 break;
1566 }
1567 default:
1568 break;
1569 }
1570 cache_info->type=UndefinedCache;
1571 cache_info->mapped=MagickFalse;
1572 cache_info->indexes=(IndexPacket *) NULL;
1573}
1574
1575MagickExport Cache DestroyPixelCache(Cache cache)
1576{
1577 CacheInfo
1578 *cache_info;
1579
cristy3ed852e2009-09-05 21:47:34 +00001580 assert(cache != (Cache) NULL);
1581 cache_info=(CacheInfo *) cache;
1582 assert(cache_info->signature == MagickSignature);
1583 if (cache_info->debug != MagickFalse)
1584 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1585 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001586 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001587 cache_info->reference_count--;
1588 if (cache_info->reference_count != 0)
1589 {
cristyf84a1932010-01-03 18:00:18 +00001590 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001591 return((Cache) NULL);
1592 }
cristyf84a1932010-01-03 18:00:18 +00001593 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001594 if (cache_resources != (SplayTreeInfo *) NULL)
1595 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
cristy5b8de732009-09-10 23:50:40 +00001596 if (cache_info->debug != MagickFalse)
1597 {
1598 char
1599 message[MaxTextExtent];
1600
1601 (void) FormatMagickString(message,MaxTextExtent,"destroy %s",
1602 cache_info->filename);
1603 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1604 }
cristyc2e1bdd2009-09-10 23:43:34 +00001605 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1606 (cache_info->type != DiskCache)))
1607 RelinquishPixelCachePixels(cache_info);
1608 else
1609 {
1610 RelinquishPixelCachePixels(cache_info);
1611 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1612 }
cristy3ed852e2009-09-05 21:47:34 +00001613 *cache_info->cache_filename='\0';
1614 if (cache_info->nexus_info != (NexusInfo **) NULL)
1615 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1616 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001617 if (cache_info->random_info != (RandomInfo *) NULL)
1618 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001619 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1620 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1621 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1622 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001623 cache_info->signature=(~MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001624 cache_info=(CacheInfo *) RelinquishAlignedMemory(cache_info);
1625 cache=(Cache) NULL;
1626 return(cache);
1627}
1628
1629/*
1630%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1631% %
1632% %
1633% %
1634+ D e s t r o y P i x e l C a c h e N e x u s %
1635% %
1636% %
1637% %
1638%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1639%
1640% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1641%
1642% The format of the DestroyPixelCacheNexus() method is:
1643%
1644% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
1645% const unsigned long number_threads)
1646%
1647% A description of each parameter follows:
1648%
1649% o nexus_info: the nexus to destroy.
1650%
1651% o number_threads: the number of nexus threads.
1652%
1653*/
1654
1655static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1656{
1657 if (nexus_info->mapped == MagickFalse)
1658 (void) RelinquishMagickMemory(nexus_info->cache);
1659 else
1660 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1661 nexus_info->cache=(PixelPacket *) NULL;
1662 nexus_info->pixels=(PixelPacket *) NULL;
1663 nexus_info->indexes=(IndexPacket *) NULL;
1664 nexus_info->length=0;
1665 nexus_info->mapped=MagickFalse;
1666}
1667
1668MagickExport NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
1669 const unsigned long number_threads)
1670{
1671 register long
1672 i;
1673
1674 assert(nexus_info != (NexusInfo **) NULL);
1675 for (i=0; i < (long) number_threads; i++)
1676 {
1677 if (nexus_info[i]->cache != (PixelPacket *) NULL)
1678 RelinquishCacheNexusPixels(nexus_info[i]);
1679 nexus_info[i]->signature=(~MagickSignature);
1680 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
1681 }
1682 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
1683 return(nexus_info);
1684}
1685
1686/*
1687%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1688% %
1689% %
1690% %
cristy3ed852e2009-09-05 21:47:34 +00001691+ 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 %
1692% %
1693% %
1694% %
1695%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1696%
1697% GetAuthenticIndexesFromCache() returns the indexes associated with the last
1698% call to QueueAuthenticPixelsCache() or GetAuthenticPixelsCache().
1699%
1700% The format of the GetAuthenticIndexesFromCache() method is:
1701%
1702% IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1703%
1704% A description of each parameter follows:
1705%
1706% o image: the image.
1707%
1708*/
1709static IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1710{
1711 CacheInfo
1712 *cache_info;
1713
1714 IndexPacket
1715 *indexes;
1716
1717 long
1718 id;
1719
1720 if (image->debug != MagickFalse)
1721 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1722 cache_info=(CacheInfo *) image->cache;
1723 id=GetOpenMPThreadId();
1724 assert(id < (long) cache_info->number_threads);
1725 indexes=GetPixelCacheNexusIndexes(image->cache,cache_info->nexus_info[id]);
1726 return(indexes);
1727}
1728
1729/*
1730%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1731% %
1732% %
1733% %
1734% G e t A u t h e n t i c I n d e x Q u e u e %
1735% %
1736% %
1737% %
1738%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1739%
1740% GetAuthenticIndexQueue() returns the authentic black channel or the colormap
1741% indexes associated with the last call to QueueAuthenticPixels() or
1742% GetVirtualPixels(). NULL is returned if the black channel or colormap
1743% indexes are not available.
1744%
1745% The format of the GetAuthenticIndexQueue() method is:
1746%
1747% IndexPacket *GetAuthenticIndexQueue(const Image *image)
1748%
1749% A description of each parameter follows:
1750%
1751% o image: the image.
1752%
1753*/
1754MagickExport IndexPacket *GetAuthenticIndexQueue(const Image *image)
1755{
1756 CacheInfo
1757 *cache_info;
1758
1759 assert(image != (const Image *) NULL);
1760 assert(image->signature == MagickSignature);
1761 if (image->debug != MagickFalse)
1762 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1763 assert(image->cache != (Cache) NULL);
1764 cache_info=(CacheInfo *) image->cache;
1765 assert(cache_info->signature == MagickSignature);
1766 if (cache_info->methods.get_authentic_indexes_from_handler ==
1767 (GetAuthenticIndexesFromHandler) NULL)
1768 return((IndexPacket *) NULL);
1769 return(cache_info->methods.get_authentic_indexes_from_handler(image));
1770}
1771
1772/*
1773%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1774% %
1775% %
1776% %
1777+ 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 %
1778% %
1779% %
1780% %
1781%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1782%
1783% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1784% disk pixel cache as defined by the geometry parameters. A pointer to the
1785% pixels is returned if the pixels are transferred, otherwise a NULL is
1786% returned.
1787%
1788% The format of the GetAuthenticPixelCacheNexus() method is:
1789%
1790% PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const long x,
1791% const long y,const unsigned long columns,const unsigned long rows,
1792% NexusInfo *nexus_info,ExceptionInfo *exception)
1793%
1794% A description of each parameter follows:
1795%
1796% o image: the image.
1797%
1798% o x,y,columns,rows: These values define the perimeter of a region of
1799% pixels.
1800%
1801% o nexus_info: the cache nexus to return.
1802%
1803% o exception: return any errors or warnings in this structure.
1804%
1805*/
1806
1807static inline MagickBooleanType IsNexusInCore(const CacheInfo *cache_info,
1808 NexusInfo *nexus_info)
1809{
1810 MagickOffsetType
1811 offset;
1812
1813 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1814 nexus_info->region.x;
1815 if (nexus_info->pixels != (cache_info->pixels+offset))
1816 return(MagickFalse);
1817 return(MagickTrue);
1818}
1819
1820MagickExport PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const long x,
1821 const long y,const unsigned long columns,const unsigned long rows,
1822 NexusInfo *nexus_info,ExceptionInfo *exception)
1823{
1824 CacheInfo
1825 *cache_info;
1826
1827 PixelPacket
1828 *pixels;
1829
1830 /*
1831 Transfer pixels from the cache.
1832 */
1833 assert(image != (Image *) NULL);
1834 assert(image->signature == MagickSignature);
1835 if (image->debug != MagickFalse)
1836 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1837 pixels=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
1838 if (pixels == (PixelPacket *) NULL)
1839 return((PixelPacket *) NULL);
1840 cache_info=(CacheInfo *) image->cache;
1841 assert(cache_info->signature == MagickSignature);
1842 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
1843 return(pixels);
1844 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1845 return((PixelPacket *) NULL);
1846 if (cache_info->active_index_channel != MagickFalse)
1847 if (ReadPixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse)
1848 return((PixelPacket *) NULL);
1849 return(pixels);
1850}
1851
1852/*
1853%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1854% %
1855% %
1856% %
1857+ G e t A u t h e n t i c P i x e l s F r o m C a c h e %
1858% %
1859% %
1860% %
1861%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1862%
1863% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1864% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1865%
1866% The format of the GetAuthenticPixelsFromCache() method is:
1867%
1868% PixelPacket *GetAuthenticPixelsFromCache(const Image image)
1869%
1870% A description of each parameter follows:
1871%
1872% o image: the image.
1873%
1874*/
1875static PixelPacket *GetAuthenticPixelsFromCache(const Image *image)
1876{
1877 CacheInfo
1878 *cache_info;
1879
1880 long
1881 id;
1882
1883 PixelPacket
1884 *pixels;
1885
1886 if (image->debug != MagickFalse)
1887 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1888 cache_info=(CacheInfo *) image->cache;
1889 id=GetOpenMPThreadId();
1890 assert(id < (long) cache_info->number_threads);
1891 pixels=GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]);
1892 return(pixels);
1893}
1894
1895/*
1896%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1897% %
1898% %
1899% %
1900% G e t A u t h e n t i c P i x e l Q u e u e %
1901% %
1902% %
1903% %
1904%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1905%
1906% GetAuthenticPixelQueue() returns the authentic pixels associated with the
1907% last call to QueueAuthenticPixels() or GetAuthenticPixels().
1908%
1909% The format of the GetAuthenticPixelQueue() method is:
1910%
1911% PixelPacket *GetAuthenticPixelQueue(const Image image)
1912%
1913% A description of each parameter follows:
1914%
1915% o image: the image.
1916%
1917*/
1918MagickExport PixelPacket *GetAuthenticPixelQueue(const Image *image)
1919{
1920 CacheInfo
1921 *cache_info;
1922
1923 assert(image != (const Image *) NULL);
1924 assert(image->signature == MagickSignature);
1925 if (image->debug != MagickFalse)
1926 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1927 assert(image->cache != (Cache) NULL);
1928 cache_info=(CacheInfo *) image->cache;
1929 assert(cache_info->signature == MagickSignature);
1930 if (cache_info->methods.get_authentic_pixels_from_handler ==
1931 (GetAuthenticPixelsFromHandler) NULL)
1932 return((PixelPacket *) NULL);
1933 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1934}
1935
1936/*
1937%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1938% %
1939% %
1940% %
1941% G e t A u t h e n t i c P i x e l s %
1942% %
1943% %
1944% %
1945%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1946%
1947% GetAuthenticPixels() obtains a pixel region for read/write access. If the
1948% region is successfully accessed, a pointer to a PixelPacket array
1949% representing the region is returned, otherwise NULL is returned.
1950%
1951% The returned pointer may point to a temporary working copy of the pixels
1952% or it may point to the original pixels in memory. Performance is maximized
1953% if the selected region is part of one row, or one or more full rows, since
1954% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001955% if the image is in memory, or in a memory-mapped file. The returned pointer
1956% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001957%
1958% Pixels accessed via the returned pointer represent a simple array of type
1959% PixelPacket. If the image type is CMYK or if the storage class is
1960% PseduoClass, call GetAuthenticIndexQueue() after invoking
1961% GetAuthenticPixels() to obtain the black color component or colormap indexes
1962% (of type IndexPacket) corresponding to the region. Once the PixelPacket
1963% (and/or IndexPacket) array has been updated, the changes must be saved back
1964% to the underlying image using SyncAuthenticPixels() or they may be lost.
1965%
1966% The format of the GetAuthenticPixels() method is:
1967%
1968% PixelPacket *GetAuthenticPixels(Image *image,const long x,const long y,
1969% const unsigned long columns,const unsigned long rows,
1970% ExceptionInfo *exception)
1971%
1972% A description of each parameter follows:
1973%
1974% o image: the image.
1975%
1976% o x,y,columns,rows: These values define the perimeter of a region of
1977% pixels.
1978%
1979% o exception: return any errors or warnings in this structure.
1980%
1981*/
1982MagickExport PixelPacket *GetAuthenticPixels(Image *image,const long x,
1983 const long y,const unsigned long columns,const unsigned long rows,
1984 ExceptionInfo *exception)
1985{
1986 CacheInfo
1987 *cache_info;
1988
1989 PixelPacket
1990 *pixels;
1991
1992 assert(image != (Image *) NULL);
1993 assert(image->signature == MagickSignature);
1994 if (image->debug != MagickFalse)
1995 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1996 assert(image->cache != (Cache) NULL);
1997 cache_info=(CacheInfo *) image->cache;
1998 assert(cache_info->signature == MagickSignature);
1999 if (cache_info->methods.get_authentic_pixels_handler ==
2000 (GetAuthenticPixelsHandler) NULL)
2001 return((PixelPacket *) NULL);
2002 pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
2003 rows,exception);
2004 return(pixels);
2005}
2006
2007/*
2008%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2009% %
2010% %
2011% %
2012+ G e t A u t h e n t i c P i x e l s C a c h e %
2013% %
2014% %
2015% %
2016%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2017%
2018% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
2019% as defined by the geometry parameters. A pointer to the pixels is returned
2020% if the pixels are transferred, otherwise a NULL is returned.
2021%
2022% The format of the GetAuthenticPixelsCache() method is:
2023%
2024% PixelPacket *GetAuthenticPixelsCache(Image *image,const long x,
2025% const long y,const unsigned long columns,const unsigned long rows,
2026% ExceptionInfo *exception)
2027%
2028% A description of each parameter follows:
2029%
2030% o image: the image.
2031%
2032% o x,y,columns,rows: These values define the perimeter of a region of
2033% pixels.
2034%
2035% o exception: return any errors or warnings in this structure.
2036%
2037*/
2038static PixelPacket *GetAuthenticPixelsCache(Image *image,const long x,
2039 const long y,const unsigned long columns,const unsigned long rows,
2040 ExceptionInfo *exception)
2041{
2042 CacheInfo
2043 *cache_info;
2044
2045 long
2046 id;
2047
2048 PixelPacket
2049 *pixels;
2050
2051 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
2052 if (cache_info == (Cache) NULL)
2053 return((PixelPacket *) NULL);
2054 id=GetOpenMPThreadId();
2055 assert(id < (long) cache_info->number_threads);
2056 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
2057 cache_info->nexus_info[id],exception);
2058 return(pixels);
2059}
2060
2061/*
2062%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2063% %
2064% %
2065% %
2066+ G e t I m a g e E x t e n t %
2067% %
2068% %
2069% %
2070%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2071%
2072% GetImageExtent() returns the extent of the pixels associated with the
2073% last call to QueueAuthenticPixels() or GetAuthenticPixels().
2074%
2075% The format of the GetImageExtent() method is:
2076%
2077% MagickSizeType GetImageExtent(const Image *image)
2078%
2079% A description of each parameter follows:
2080%
2081% o image: the image.
2082%
2083*/
2084MagickExport MagickSizeType GetImageExtent(const Image *image)
2085{
2086 CacheInfo
2087 *cache_info;
2088
2089 long
2090 id;
2091
2092 MagickSizeType
2093 extent;
2094
2095 assert(image != (Image *) NULL);
2096 assert(image->signature == MagickSignature);
2097 if (image->debug != MagickFalse)
2098 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2099 assert(image->cache != (Cache) NULL);
2100 cache_info=(CacheInfo *) image->cache;
2101 assert(cache_info->signature == MagickSignature);
2102 id=GetOpenMPThreadId();
2103 assert(id < (long) cache_info->number_threads);
2104 extent=GetPixelCacheNexusExtent(image->cache,cache_info->nexus_info[id]);
2105 return(extent);
2106}
2107
2108/*
2109%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2110% %
2111% %
2112% %
2113+ G e t I m a g e P i x e l C a c h e %
2114% %
2115% %
2116% %
2117%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2118%
2119% GetImagePixelCache() ensures that there is only a single reference to the
2120% pixel cache to be modified, updating the provided cache pointer to point to
2121% a clone of the original pixel cache if necessary.
2122%
2123% The format of the GetImagePixelCache method is:
2124%
2125% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2126% ExceptionInfo *exception)
2127%
2128% A description of each parameter follows:
2129%
2130% o image: the image.
2131%
2132% o clone: any value other than MagickFalse clones the cache pixels.
2133%
2134% o exception: return any errors or warnings in this structure.
2135%
2136*/
2137
2138static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
2139{
2140 CacheInfo
2141 *cache_info;
2142
2143 /*
2144 Does the image match the pixel cache morphology?
2145 */
2146 cache_info=(CacheInfo *) image->cache;
2147 if ((image->storage_class != cache_info->storage_class) ||
2148 (image->colorspace != cache_info->colorspace) ||
2149 (image->columns != cache_info->columns) ||
2150 (image->rows != cache_info->rows) ||
2151 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2152 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2153 return(MagickFalse);
2154 return(MagickTrue);
2155}
2156
2157MagickExport Cache GetImagePixelCache(Image *image,
2158 const MagickBooleanType clone,ExceptionInfo *exception)
2159{
2160 CacheInfo
2161 *cache_info;
2162
2163 MagickSizeType
2164 time_limit;
2165
2166 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00002167 destroy,
cristy3ed852e2009-09-05 21:47:34 +00002168 status;
2169
2170 if (image->debug != MagickFalse)
2171 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2172 status=MagickTrue;
cristyf84a1932010-01-03 18:00:18 +00002173 LockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002174 time_limit=GetMagickResourceLimit(TimeResource);
2175 if (cache_timer == 0)
2176 cache_timer=time((time_t *) NULL);
2177 if ((time_limit != MagickResourceInfinity) &&
2178 ((MagickSizeType) (time((time_t *) NULL)-cache_timer) >= time_limit))
2179 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
2180 assert(image->cache != (Cache) NULL);
2181 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002182 destroy=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +00002183 LockSemaphoreInfo(cache_info->semaphore);
cristy01b7eb02009-09-10 23:10:14 +00002184 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002185 {
2186 Image
2187 clone_image;
2188
2189 CacheInfo
2190 *clone_info;
2191
2192 /*
2193 Clone pixel cache.
2194 */
2195 clone_image=(*image);
2196 clone_image.cache=ClonePixelCache(cache_info);
2197 clone_info=(CacheInfo *) clone_image.cache;
2198 status=ClonePixelCacheNexus(cache_info,clone_info,exception);
2199 if (status != MagickFalse)
2200 {
2201 status=OpenPixelCache(&clone_image,IOMode,exception);
2202 if (status != MagickFalse)
2203 {
2204 if (clone != MagickFalse)
2205 status=ClonePixelCachePixels(clone_info,cache_info,exception);
2206 if (status != MagickFalse)
2207 {
cristy4320e0e2009-09-10 15:00:08 +00002208 destroy=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00002209 image->cache=clone_image.cache;
2210 }
2211 }
2212 }
2213 }
cristyf84a1932010-01-03 18:00:18 +00002214 UnlockSemaphoreInfo(cache_info->semaphore);
cristy4320e0e2009-09-10 15:00:08 +00002215 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002216 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002217 if (status != MagickFalse)
2218 {
2219 /*
2220 Ensure the image matches the pixel cache morphology.
2221 */
2222 image->taint=MagickTrue;
2223 image->type=UndefinedType;
2224 if (image->colorspace == GRAYColorspace)
2225 image->colorspace=RGBColorspace;
2226 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2227 status=OpenPixelCache(image,IOMode,exception);
2228 }
cristyf84a1932010-01-03 18:00:18 +00002229 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002230 if (status == MagickFalse)
2231 return((Cache) NULL);
2232 return(image->cache);
2233}
2234
2235/*
2236%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2237% %
2238% %
2239% %
2240% G e t O n e A u t h e n t i c P i x e l %
2241% %
2242% %
2243% %
2244%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2245%
2246% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2247% location. The image background color is returned if an error occurs.
2248%
2249% The format of the GetOneAuthenticPixel() method is:
2250%
2251% MagickBooleanType GetOneAuthenticPixel(const Image image,const long x,
2252% const long y,PixelPacket *pixel,ExceptionInfo *exception)
2253%
2254% A description of each parameter follows:
2255%
2256% o image: the image.
2257%
2258% o x,y: These values define the location of the pixel to return.
2259%
2260% o pixel: return a pixel at the specified (x,y) location.
2261%
2262% o exception: return any errors or warnings in this structure.
2263%
2264*/
2265MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,const long x,
2266 const long y,PixelPacket *pixel,ExceptionInfo *exception)
2267{
2268 CacheInfo
2269 *cache_info;
2270
2271 GetOneAuthenticPixelFromHandler
2272 get_one_authentic_pixel_from_handler;
2273
2274 MagickBooleanType
2275 status;
2276
2277 assert(image != (Image *) NULL);
2278 assert(image->signature == MagickSignature);
2279 if (image->debug != MagickFalse)
2280 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2281 assert(image->cache != (Cache) NULL);
2282 cache_info=(CacheInfo *) image->cache;
2283 assert(cache_info->signature == MagickSignature);
2284 *pixel=image->background_color;
2285 get_one_authentic_pixel_from_handler=
2286 cache_info->methods.get_one_authentic_pixel_from_handler;
2287 if (get_one_authentic_pixel_from_handler ==
2288 (GetOneAuthenticPixelFromHandler) NULL)
2289 return(MagickFalse);
2290 status=cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2291 pixel,exception);
2292 return(status);
2293}
2294
2295/*
2296%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2297% %
2298% %
2299% %
2300+ 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 %
2301% %
2302% %
2303% %
2304%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2305%
2306% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2307% location. The image background color is returned if an error occurs.
2308%
2309% The format of the GetOneAuthenticPixelFromCache() method is:
2310%
2311% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
2312% const long x,const long y,PixelPacket *pixel,ExceptionInfo *exception)
2313%
2314% A description of each parameter follows:
2315%
2316% o image: the image.
2317%
2318% o x,y: These values define the location of the pixel to return.
2319%
2320% o pixel: return a pixel at the specified (x,y) location.
2321%
2322% o exception: return any errors or warnings in this structure.
2323%
2324*/
2325static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
2326 const long x,const long y,PixelPacket *pixel,ExceptionInfo *exception)
2327{
2328 PixelPacket
2329 *pixels;
2330
2331 if (image->debug != MagickFalse)
2332 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2333 *pixel=image->background_color;
2334 pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2335 if (pixels == (PixelPacket *) NULL)
2336 return(MagickFalse);
2337 *pixel=(*pixels);
2338 return(MagickTrue);
2339}
2340
2341/*
2342%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2343% %
2344% %
2345% %
2346% G e t O n e V i r t u a l M a g i c k P i x e l %
2347% %
2348% %
2349% %
2350%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2351%
2352% GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2353% location. The image background color is returned if an error occurs. If
2354% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2355%
2356% The format of the GetOneVirtualMagickPixel() method is:
2357%
2358% MagickBooleanType GetOneVirtualMagickPixel(const Image image,
2359% const long x,const long y,MagickPixelPacket *pixel,
2360% ExceptionInfo exception)
2361%
2362% A description of each parameter follows:
2363%
2364% o image: the image.
2365%
2366% o x,y: these values define the location of the pixel to return.
2367%
2368% o pixel: return a pixel at the specified (x,y) location.
2369%
2370% o exception: return any errors or warnings in this structure.
2371%
2372*/
2373MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
2374 const long x,const long y,MagickPixelPacket *pixel,ExceptionInfo *exception)
2375{
2376 CacheInfo
2377 *cache_info;
2378
2379 register const IndexPacket
2380 *indexes;
2381
2382 register const PixelPacket
2383 *p;
2384
2385 assert(image != (const Image *) NULL);
2386 assert(image->signature == MagickSignature);
2387 assert(image->cache != (Cache) NULL);
2388 cache_info=(CacheInfo *) image->cache;
2389 assert(cache_info->signature == MagickSignature);
2390 GetMagickPixelPacket(image,pixel);
2391 p=GetVirtualPixelCache(image,GetPixelCacheVirtualMethod(image),x,y,1,1,
2392 exception);
2393 if (p == (const PixelPacket *) NULL)
2394 return(MagickFalse);
2395 indexes=GetVirtualIndexQueue(image);
2396 SetMagickPixelPacket(image,p,indexes,pixel);
2397 return(MagickTrue);
2398}
2399
2400/*
2401%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2402% %
2403% %
2404% %
2405% G e t O n e V i r t u a l M e t h o d P i x e l %
2406% %
2407% %
2408% %
2409%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2410%
2411% GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2412% location as defined by specified pixel method. The image background color
2413% is returned if an error occurs. If you plan to modify the pixel, use
2414% GetOneAuthenticPixel() instead.
2415%
2416% The format of the GetOneVirtualMethodPixel() method is:
2417%
2418% MagickBooleanType GetOneVirtualMethodPixel(const Image image,
2419% const VirtualPixelMethod virtual_pixel_method,const long x,
2420% const long y,Pixelpacket *pixel,ExceptionInfo exception)
2421%
2422% A description of each parameter follows:
2423%
2424% o image: the image.
2425%
2426% o virtual_pixel_method: the virtual pixel method.
2427%
2428% o x,y: These values define the location of the pixel to return.
2429%
2430% o pixel: return a pixel at the specified (x,y) location.
2431%
2432% o exception: return any errors or warnings in this structure.
2433%
2434*/
2435MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
2436 const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
2437 PixelPacket *pixel,ExceptionInfo *exception)
2438{
2439 GetOneVirtualPixelFromHandler
2440 get_one_virtual_pixel_from_handler;
2441
2442 CacheInfo
2443 *cache_info;
2444
2445 MagickBooleanType
2446 status;
2447
2448 assert(image != (const Image *) NULL);
2449 assert(image->signature == MagickSignature);
2450 assert(image->cache != (Cache) NULL);
2451 cache_info=(CacheInfo *) image->cache;
2452 assert(cache_info->signature == MagickSignature);
2453 *pixel=image->background_color;
2454 get_one_virtual_pixel_from_handler=
2455 cache_info->methods.get_one_virtual_pixel_from_handler;
2456 if (get_one_virtual_pixel_from_handler ==
2457 (GetOneVirtualPixelFromHandler) NULL)
2458 return(MagickFalse);
2459 status=get_one_virtual_pixel_from_handler(image,virtual_pixel_method,x,y,
2460 pixel,exception);
2461 return(status);
2462}
2463
2464/*
2465%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2466% %
2467% %
2468% %
2469% G e t O n e V i r t u a l P i x e l %
2470% %
2471% %
2472% %
2473%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2474%
2475% GetOneVirtualPixel() returns a single virtual pixel at the specified
2476% (x,y) location. The image background color is returned if an error occurs.
2477% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2478%
2479% The format of the GetOneVirtualPixel() method is:
2480%
2481% MagickBooleanType GetOneVirtualPixel(const Image image,const long x,
2482% const long y,PixelPacket *pixel,ExceptionInfo exception)
2483%
2484% A description of each parameter follows:
2485%
2486% o image: the image.
2487%
2488% o x,y: These values define the location of the pixel to return.
2489%
2490% o pixel: return a pixel at the specified (x,y) location.
2491%
2492% o exception: return any errors or warnings in this structure.
2493%
2494*/
2495MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
2496 const long x,const long y,PixelPacket *pixel,ExceptionInfo *exception)
2497{
2498 GetOneVirtualPixelFromHandler
2499 get_one_virtual_pixel_from_handler;
2500
2501 CacheInfo
2502 *cache_info;
2503
2504 MagickBooleanType
2505 status;
2506
2507 assert(image != (const Image *) NULL);
2508 assert(image->signature == MagickSignature);
2509 assert(image->cache != (Cache) NULL);
2510 cache_info=(CacheInfo *) image->cache;
2511 assert(cache_info->signature == MagickSignature);
2512 *pixel=image->background_color;
2513 get_one_virtual_pixel_from_handler=
2514 cache_info->methods.get_one_virtual_pixel_from_handler;
2515 if (get_one_virtual_pixel_from_handler ==
2516 (GetOneVirtualPixelFromHandler) NULL)
2517 return(MagickFalse);
2518 status=get_one_virtual_pixel_from_handler(image,GetPixelCacheVirtualMethod(
2519 image),x,y,pixel,exception);
2520 return(status);
2521}
2522
2523/*
2524%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2525% %
2526% %
2527% %
2528+ 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 %
2529% %
2530% %
2531% %
2532%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2533%
2534% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2535% specified (x,y) location. The image background color is returned if an
2536% error occurs.
2537%
2538% The format of the GetOneVirtualPixelFromCache() method is:
2539%
2540% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
2541% const VirtualPixelPacket method,const long x,const long y,
2542% PixelPacket *pixel,ExceptionInfo *exception)
2543%
2544% A description of each parameter follows:
2545%
2546% o image: the image.
2547%
2548% o virtual_pixel_method: the virtual pixel method.
2549%
2550% o x,y: These values define the location of the pixel to return.
2551%
2552% o pixel: return a pixel at the specified (x,y) location.
2553%
2554% o exception: return any errors or warnings in this structure.
2555%
2556*/
2557static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
2558 const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
2559 PixelPacket *pixel,ExceptionInfo *exception)
2560{
2561 const PixelPacket
2562 *pixels;
2563
2564 *pixel=image->background_color;
2565 pixels=GetVirtualPixelCache(image,virtual_pixel_method,x,y,1UL,1UL,exception);
2566 if (pixels == (const PixelPacket *) NULL)
2567 return(MagickFalse);
2568 *pixel=(*pixels);
2569 return(MagickTrue);
2570}
2571
2572/*
2573%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2574% %
2575% %
2576% %
2577+ G e t P i x e l C a c h e C o l o r s p a c e %
2578% %
2579% %
2580% %
2581%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2582%
2583% GetPixelCacheColorspace() returns the class type of the pixel cache.
2584%
2585% The format of the GetPixelCacheColorspace() method is:
2586%
2587% Colorspace GetPixelCacheColorspace(Cache cache)
2588%
2589% A description of each parameter follows:
2590%
2591% o cache: the pixel cache.
2592%
2593*/
2594MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
2595{
2596 CacheInfo
2597 *cache_info;
2598
2599 assert(cache != (Cache) NULL);
2600 cache_info=(CacheInfo *) cache;
2601 assert(cache_info->signature == MagickSignature);
2602 if (cache_info->debug != MagickFalse)
2603 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2604 cache_info->filename);
2605 return(cache_info->colorspace);
2606}
2607
2608/*
2609%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2610% %
2611% %
2612% %
2613+ G e t P i x e l C a c h e M e t h o d s %
2614% %
2615% %
2616% %
2617%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2618%
2619% GetPixelCacheMethods() initializes the CacheMethods structure.
2620%
2621% The format of the GetPixelCacheMethods() method is:
2622%
2623% void GetPixelCacheMethods(CacheMethods *cache_methods)
2624%
2625% A description of each parameter follows:
2626%
2627% o cache_methods: Specifies a pointer to a CacheMethods structure.
2628%
2629*/
2630MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
2631{
2632 assert(cache_methods != (CacheMethods *) NULL);
2633 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2634 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2635 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2636 cache_methods->get_virtual_indexes_from_handler=GetVirtualIndexesFromCache;
2637 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2638 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2639 cache_methods->get_authentic_indexes_from_handler=
2640 GetAuthenticIndexesFromCache;
2641 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2642 cache_methods->get_one_authentic_pixel_from_handler=
2643 GetOneAuthenticPixelFromCache;
2644 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2645 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2646 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2647}
2648
2649/*
2650%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2651% %
2652% %
2653% %
2654+ G e t P i x e l C a c h e N e x u s E x t e n t %
2655% %
2656% %
2657% %
2658%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2659%
2660% GetPixelCacheNexusExtent() returns the extent of the pixels associated with
2661% the last call to SetPixelCacheNexusPixels() or GetPixelCacheNexusPixels().
2662%
2663% The format of the GetPixelCacheNexusExtent() method is:
2664%
2665% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2666% NexusInfo *nexus_info)
2667%
2668% A description of each parameter follows:
2669%
2670% o nexus_info: the nexus info.
2671%
2672*/
2673MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2674 NexusInfo *nexus_info)
2675{
2676 CacheInfo
2677 *cache_info;
2678
2679 MagickSizeType
2680 extent;
2681
2682 if (cache == (Cache) NULL)
2683 return(0);
2684 cache_info=(CacheInfo *) cache;
2685 assert(cache_info->signature == MagickSignature);
2686 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2687 if (extent == 0)
2688 return((MagickSizeType) cache_info->columns*cache_info->rows);
2689 return(extent);
2690}
2691
2692/*
2693%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2694% %
2695% %
2696% %
2697+ 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 %
2698% %
2699% %
2700% %
2701%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2702%
2703% GetPixelCacheNexusIndexes() returns the indexes associated with the
2704% specified cache nexus.
2705%
2706% The format of the GetPixelCacheNexusIndexes() method is:
2707%
2708% IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2709% NexusInfo *nexus_info)
2710%
2711% A description of each parameter follows:
2712%
2713% o cache: the pixel cache.
2714%
2715% o nexus_info: the cache nexus to return the colormap indexes.
2716%
2717*/
2718MagickExport IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2719 NexusInfo *nexus_info)
2720{
2721 CacheInfo
2722 *cache_info;
2723
2724 if (cache == (Cache) NULL)
2725 return((IndexPacket *) NULL);
2726 cache_info=(CacheInfo *) cache;
2727 assert(cache_info->signature == MagickSignature);
2728 if (cache_info->storage_class == UndefinedClass)
2729 return((IndexPacket *) NULL);
2730 return(nexus_info->indexes);
2731}
2732
2733/*
2734%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2735% %
2736% %
2737% %
2738+ G e t P i x e l C a c h e N e x u s P i x e l s %
2739% %
2740% %
2741% %
2742%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2743%
2744% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2745% cache nexus.
2746%
2747% The format of the GetPixelCacheNexusPixels() method is:
2748%
2749% PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2750% NexusInfo *nexus_info)
2751%
2752% A description of each parameter follows:
2753%
2754% o cache: the pixel cache.
2755%
2756% o nexus_info: the cache nexus to return the pixels.
2757%
2758*/
2759MagickExport PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2760 NexusInfo *nexus_info)
2761{
2762 CacheInfo
2763 *cache_info;
2764
2765 if (cache == (Cache) NULL)
2766 return((PixelPacket *) NULL);
2767 cache_info=(CacheInfo *) cache;
2768 assert(cache_info->signature == MagickSignature);
2769 if (cache_info->debug != MagickFalse)
2770 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2771 cache_info->filename);
2772 if (cache_info->storage_class == UndefinedClass)
2773 return((PixelPacket *) NULL);
2774 return(nexus_info->pixels);
2775}
2776
2777/*
2778%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2779% %
2780% %
2781% %
cristy056ba772010-01-02 23:33:54 +00002782+ G e t P i x e l C a c h e P i x e l s %
2783% %
2784% %
2785% %
2786%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2787%
2788% GetPixelCachePixels() returns the pixels associated with the specified image.
2789%
2790% The format of the GetPixelCachePixels() method is:
2791%
cristyf84a1932010-01-03 18:00:18 +00002792% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2793% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002794%
2795% A description of each parameter follows:
2796%
2797% o image: the image.
2798%
2799% o length: the pixel cache length.
2800%
cristyf84a1932010-01-03 18:00:18 +00002801% o exception: return any errors or warnings in this structure.
2802%
cristy056ba772010-01-02 23:33:54 +00002803*/
cristyf84a1932010-01-03 18:00:18 +00002804MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2805 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002806{
2807 CacheInfo
2808 *cache_info;
2809
2810 assert(image != (const Image *) NULL);
2811 assert(image->signature == MagickSignature);
2812 if (image->debug != MagickFalse)
2813 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2814 assert(image->cache != (Cache) NULL);
cristyc4c8d132010-01-07 01:58:38 +00002815 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
cristy056ba772010-01-02 23:33:54 +00002816 assert(cache_info->signature == MagickSignature);
2817 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002818 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002819 return((void *) NULL);
2820 *length=cache_info->length;
2821 return((void *) cache_info->pixels);
2822}
2823
2824/*
2825%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2826% %
2827% %
2828% %
cristyb32b90a2009-09-07 21:45:48 +00002829+ 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 +00002830% %
2831% %
2832% %
2833%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2834%
2835% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2836%
2837% The format of the GetPixelCacheStorageClass() method is:
2838%
2839% ClassType GetPixelCacheStorageClass(Cache cache)
2840%
2841% A description of each parameter follows:
2842%
2843% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2844%
2845% o cache: the pixel cache.
2846%
2847*/
2848MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
2849{
2850 CacheInfo
2851 *cache_info;
2852
2853 assert(cache != (Cache) NULL);
2854 cache_info=(CacheInfo *) cache;
2855 assert(cache_info->signature == MagickSignature);
2856 if (cache_info->debug != MagickFalse)
2857 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2858 cache_info->filename);
2859 return(cache_info->storage_class);
2860}
2861
2862/*
2863%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2864% %
2865% %
2866% %
cristyb32b90a2009-09-07 21:45:48 +00002867+ G e t P i x e l C a c h e T i l e S i z e %
2868% %
2869% %
2870% %
2871%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2872%
2873% GetPixelCacheTileSize() returns the pixel cache tile size.
2874%
2875% The format of the GetPixelCacheTileSize() method is:
2876%
2877% void GetPixelCacheTileSize(const Image *image,unsigned long *width,
2878% unsigned long *height)
2879%
2880% A description of each parameter follows:
2881%
2882% o image: the image.
2883%
2884% o width: the optimize cache tile width in pixels.
2885%
2886% o height: the optimize cache tile height in pixels.
2887%
2888*/
2889MagickExport void GetPixelCacheTileSize(const Image *image,unsigned long *width,
2890 unsigned long *height)
2891{
2892 CacheInfo
2893 *cache_info;
2894
2895 assert(image != (Image *) NULL);
2896 assert(image->signature == MagickSignature);
2897 if (image->debug != MagickFalse)
2898 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2899 assert(image->cache != (Cache) NULL);
2900 cache_info=(CacheInfo *) image->cache;
2901 assert(cache_info->signature == MagickSignature);
2902 *width=2048UL/sizeof(PixelPacket);
2903 if (GetPixelCacheType(image) == DiskCache)
cristydaa97692009-09-13 02:10:35 +00002904 *width=8192UL/sizeof(PixelPacket);
cristyb32b90a2009-09-07 21:45:48 +00002905 *height=(*width);
2906}
2907
2908/*
2909%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2910% %
2911% %
2912% %
2913+ G e t P i x e l C a c h e T y p e %
2914% %
2915% %
2916% %
2917%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2918%
2919% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2920%
2921% The format of the GetPixelCacheType() method is:
2922%
2923% CacheType GetPixelCacheType(const Image *image)
2924%
2925% A description of each parameter follows:
2926%
2927% o image: the image.
2928%
2929*/
2930MagickExport CacheType GetPixelCacheType(const Image *image)
2931{
2932 CacheInfo
2933 *cache_info;
2934
2935 assert(image != (Image *) NULL);
2936 assert(image->signature == MagickSignature);
2937 if (image->debug != MagickFalse)
2938 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2939 assert(image->cache != (Cache) NULL);
2940 cache_info=(CacheInfo *) image->cache;
2941 assert(cache_info->signature == MagickSignature);
2942 return(cache_info->type);
2943}
2944
2945/*
2946%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2947% %
2948% %
2949% %
cristy3ed852e2009-09-05 21:47:34 +00002950+ 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 %
2951% %
2952% %
2953% %
2954%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2955%
2956% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2957% pixel cache. A virtual pixel is any pixel access that is outside the
2958% boundaries of the image cache.
2959%
2960% The format of the GetPixelCacheVirtualMethod() method is:
2961%
2962% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2963%
2964% A description of each parameter follows:
2965%
2966% o image: the image.
2967%
2968*/
2969MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2970{
2971 CacheInfo
2972 *cache_info;
2973
2974 assert(image != (Image *) NULL);
2975 assert(image->signature == MagickSignature);
2976 if (image->debug != MagickFalse)
2977 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2978 assert(image->cache != (Cache) NULL);
2979 cache_info=(CacheInfo *) image->cache;
2980 assert(cache_info->signature == MagickSignature);
2981 return(cache_info->virtual_pixel_method);
2982}
2983
2984/*
2985%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2986% %
2987% %
2988% %
2989+ 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 %
2990% %
2991% %
2992% %
2993%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2994%
2995% GetVirtualIndexesFromCache() returns the indexes associated with the last
2996% call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2997%
2998% The format of the GetVirtualIndexesFromCache() method is:
2999%
3000% IndexPacket *GetVirtualIndexesFromCache(const Image *image)
3001%
3002% A description of each parameter follows:
3003%
3004% o image: the image.
3005%
3006*/
3007static const IndexPacket *GetVirtualIndexesFromCache(const Image *image)
3008{
3009 CacheInfo
3010 *cache_info;
3011
3012 const IndexPacket
3013 *indexes;
3014
3015 long
3016 id;
3017
3018 if (image->debug != MagickFalse)
3019 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3020 cache_info=(CacheInfo *) image->cache;
3021 id=GetOpenMPThreadId();
3022 assert(id < (long) cache_info->number_threads);
3023 indexes=GetVirtualIndexesFromNexus(image->cache,cache_info->nexus_info[id]);
3024 return(indexes);
3025}
3026
3027/*
3028%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3029% %
3030% %
3031% %
3032+ 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 %
3033% %
3034% %
3035% %
3036%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3037%
3038% GetVirtualIndexesFromNexus() returns the indexes associated with the
3039% specified cache nexus.
3040%
3041% The format of the GetVirtualIndexesFromNexus() method is:
3042%
3043% const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
3044% NexusInfo *nexus_info)
3045%
3046% A description of each parameter follows:
3047%
3048% o cache: the pixel cache.
3049%
3050% o nexus_info: the cache nexus to return the colormap indexes.
3051%
3052*/
3053MagickExport const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
3054 NexusInfo *nexus_info)
3055{
3056 CacheInfo
3057 *cache_info;
3058
3059 if (cache == (Cache) NULL)
3060 return((IndexPacket *) NULL);
3061 cache_info=(CacheInfo *) cache;
3062 assert(cache_info->signature == MagickSignature);
3063 if (cache_info->storage_class == UndefinedClass)
3064 return((IndexPacket *) NULL);
3065 return(nexus_info->indexes);
3066}
3067
3068/*
3069%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3070% %
3071% %
3072% %
3073% G e t V i r t u a l I n d e x Q u e u e %
3074% %
3075% %
3076% %
3077%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3078%
3079% GetVirtualIndexQueue() returns the virtual black channel or the
3080% colormap indexes associated with the last call to QueueAuthenticPixels() or
3081% GetVirtualPixels(). NULL is returned if the black channel or colormap
3082% indexes are not available.
3083%
3084% The format of the GetVirtualIndexQueue() method is:
3085%
3086% const IndexPacket *GetVirtualIndexQueue(const Image *image)
3087%
3088% A description of each parameter follows:
3089%
3090% o image: the image.
3091%
3092*/
3093MagickExport const IndexPacket *GetVirtualIndexQueue(const Image *image)
3094{
3095 CacheInfo
3096 *cache_info;
3097
3098 assert(image != (const Image *) NULL);
3099 assert(image->signature == MagickSignature);
3100 if (image->debug != MagickFalse)
3101 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3102 assert(image->cache != (Cache) NULL);
3103 cache_info=(CacheInfo *) image->cache;
3104 assert(cache_info->signature == MagickSignature);
3105 if (cache_info->methods.get_virtual_indexes_from_handler ==
3106 (GetVirtualIndexesFromHandler) NULL)
3107 return((IndexPacket *) NULL);
3108 return(cache_info->methods.get_virtual_indexes_from_handler(image));
3109}
3110
3111/*
3112%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3113% %
3114% %
3115% %
3116+ 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 %
3117% %
3118% %
3119% %
3120%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3121%
3122% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3123% pixel cache as defined by the geometry parameters. A pointer to the pixels
3124% is returned if the pixels are transferred, otherwise a NULL is returned.
3125%
3126% The format of the GetVirtualPixelsFromNexus() method is:
3127%
3128% PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
3129% const VirtualPixelMethod method,const long x,const long y,
3130% const unsigned long columns,const unsigned long rows,
3131% NexusInfo *nexus_info,ExceptionInfo *exception)
3132%
3133% A description of each parameter follows:
3134%
3135% o image: the image.
3136%
3137% o virtual_pixel_method: the virtual pixel method.
3138%
3139% o x,y,columns,rows: These values define the perimeter of a region of
3140% pixels.
3141%
3142% o nexus_info: the cache nexus to acquire.
3143%
3144% o exception: return any errors or warnings in this structure.
3145%
3146*/
3147
3148static long
3149 DitherMatrix[64] =
3150 {
3151 0, 48, 12, 60, 3, 51, 15, 63,
3152 32, 16, 44, 28, 35, 19, 47, 31,
3153 8, 56, 4, 52, 11, 59, 7, 55,
3154 40, 24, 36, 20, 43, 27, 39, 23,
3155 2, 50, 14, 62, 1, 49, 13, 61,
3156 34, 18, 46, 30, 33, 17, 45, 29,
3157 10, 58, 6, 54, 9, 57, 5, 53,
3158 42, 26, 38, 22, 41, 25, 37, 21
3159 };
3160
cristy222528c2010-01-09 23:36:34 +00003161static inline long DitherX(const long x,const unsigned long columns)
cristy3ed852e2009-09-05 21:47:34 +00003162{
3163 long
3164 index;
3165
3166 index=x+DitherMatrix[x & 0x07]-32L;
3167 if (index < 0L)
3168 return(0L);
3169 if (index >= (long) columns)
3170 return((long) columns-1L);
3171 return(index);
3172}
3173
cristy222528c2010-01-09 23:36:34 +00003174static inline long DitherY(const long y,const unsigned long rows)
cristy3ed852e2009-09-05 21:47:34 +00003175{
3176 long
3177 index;
3178
3179 index=y+DitherMatrix[y & 0x07]-32L;
3180 if (index < 0L)
3181 return(0L);
3182 if (index >= (long) rows)
3183 return((long) rows-1L);
3184 return(index);
3185}
3186
cristy222528c2010-01-09 23:36:34 +00003187static inline long EdgeX(const long x,const unsigned long columns)
cristy3ed852e2009-09-05 21:47:34 +00003188{
3189 if (x < 0L)
3190 return(0L);
3191 if (x >= (long) columns)
cristy97be2b92010-01-09 23:37:55 +00003192 return((long) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003193 return(x);
3194}
3195
cristy222528c2010-01-09 23:36:34 +00003196static inline long EdgeY(const long y,const unsigned long rows)
cristy3ed852e2009-09-05 21:47:34 +00003197{
3198 if (y < 0L)
3199 return(0L);
3200 if (y >= (long) rows)
cristy97be2b92010-01-09 23:37:55 +00003201 return((long) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003202 return(y);
3203}
3204
cristy222528c2010-01-09 23:36:34 +00003205static inline long RandomX(RandomInfo *random_info,const unsigned long columns)
cristy3ed852e2009-09-05 21:47:34 +00003206{
3207 return((long) (columns*GetPseudoRandomValue(random_info)));
3208}
3209
cristy222528c2010-01-09 23:36:34 +00003210static inline long RandomY(RandomInfo *random_info,const unsigned long rows)
cristy3ed852e2009-09-05 21:47:34 +00003211{
3212 return((long) (rows*GetPseudoRandomValue(random_info)));
3213}
3214
3215/*
3216 VirtualPixelModulo() computes the remainder of dividing offset by extent. It
3217 returns not only the quotient (tile the offset falls in) but also the positive
3218 remainer within that tile such that 0 <= remainder < extent. This method is
3219 essentially a ldiv() using a floored modulo division rather than the normal
3220 default truncated modulo division.
3221*/
3222static inline MagickModulo VirtualPixelModulo(const long offset,
3223 const unsigned long extent)
3224{
3225 MagickModulo
3226 modulo;
3227
3228 modulo.quotient=offset/(long) extent;
3229 if (offset < 0L)
3230 modulo.quotient--;
3231 modulo.remainder=offset-modulo.quotient*(long) extent;
3232 return(modulo);
3233}
3234
3235MagickExport const PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
3236 const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
3237 const unsigned long columns,const unsigned long rows,NexusInfo *nexus_info,
3238 ExceptionInfo *exception)
3239{
3240 CacheInfo
3241 *cache_info;
3242
3243 MagickOffsetType
3244 offset;
3245
3246 MagickSizeType
3247 length,
3248 number_pixels;
3249
3250 NexusInfo
3251 **virtual_nexus;
3252
3253 PixelPacket
3254 *pixels,
3255 virtual_pixel;
3256
3257 RectangleInfo
3258 region;
3259
3260 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003261 *restrict nexus_indexes;
cristy3ed852e2009-09-05 21:47:34 +00003262
3263 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003264 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003265
3266 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003267 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003268
3269 register long
3270 u,
3271 v;
3272
3273 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003274 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003275
3276 /*
3277 Acquire pixels.
3278 */
3279 if (image->debug != MagickFalse)
3280 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3281 cache_info=(CacheInfo *) image->cache;
3282 if (cache_info->type == UndefinedCache)
3283 return((const PixelPacket *) NULL);
3284 region.x=x;
3285 region.y=y;
3286 region.width=columns;
3287 region.height=rows;
3288 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
3289 if (pixels == (PixelPacket *) NULL)
3290 return((const PixelPacket *) NULL);
3291 offset=(MagickOffsetType) region.y*cache_info->columns+region.x;
cristy4789f0d2010-01-10 00:01:06 +00003292 length=(MagickSizeType) (region.height-1L)*cache_info->columns+
3293 region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003294 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3295 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
3296 if ((x >= 0) && ((long) (x+columns) <= (long) cache_info->columns) &&
3297 (y >= 0) && ((long) (y+rows) <= (long) cache_info->rows))
3298 {
3299 MagickBooleanType
3300 status;
3301
3302 /*
3303 Pixel request is inside cache extents.
3304 */
3305 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
3306 return(pixels);
3307 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3308 if (status == MagickFalse)
3309 return((const PixelPacket *) NULL);
3310 if ((cache_info->storage_class == PseudoClass) ||
3311 (cache_info->colorspace == CMYKColorspace))
3312 {
3313 status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
3314 if (status == MagickFalse)
3315 return((const PixelPacket *) NULL);
3316 }
3317 return(pixels);
3318 }
3319 /*
3320 Pixel request is outside cache extents.
3321 */
3322 q=pixels;
3323 indexes=GetPixelCacheNexusIndexes(cache_info,nexus_info);
3324 virtual_nexus=AcquirePixelCacheNexus(1);
3325 if (virtual_nexus == (NexusInfo **) NULL)
3326 {
3327 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3328 "UnableToGetCacheNexus","`%s'",image->filename);
3329 return((const PixelPacket *) NULL);
3330 }
3331 switch (virtual_pixel_method)
3332 {
3333 case BlackVirtualPixelMethod:
3334 {
cristy4789f0d2010-01-10 00:01:06 +00003335 SetRedPixelComponent(&virtual_pixel,0);
3336 SetGreenPixelComponent(&virtual_pixel,0);
3337 SetBluePixelComponent(&virtual_pixel,0);
3338 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003339 break;
3340 }
3341 case GrayVirtualPixelMethod:
3342 {
cristy4789f0d2010-01-10 00:01:06 +00003343 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3344 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3345 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3346 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003347 break;
3348 }
3349 case TransparentVirtualPixelMethod:
3350 {
cristy4789f0d2010-01-10 00:01:06 +00003351 SetRedPixelComponent(&virtual_pixel,0);
3352 SetGreenPixelComponent(&virtual_pixel,0);
3353 SetBluePixelComponent(&virtual_pixel,0);
3354 SetOpacityPixelComponent(&virtual_pixel,TransparentOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003355 break;
3356 }
3357 case MaskVirtualPixelMethod:
3358 case WhiteVirtualPixelMethod:
3359 {
cristy4789f0d2010-01-10 00:01:06 +00003360 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3361 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3362 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3363 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003364 break;
3365 }
3366 default:
3367 {
3368 virtual_pixel=image->background_color;
3369 break;
3370 }
3371 }
3372 for (v=0; v < (long) rows; v++)
3373 {
3374 for (u=0; u < (long) columns; u+=length)
3375 {
3376 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
3377 if ((((x+u) < 0) || ((x+u) >= (long) cache_info->columns)) ||
3378 (((y+v) < 0) || ((y+v) >= (long) cache_info->rows)) || (length == 0))
3379 {
3380 MagickModulo
3381 x_modulo,
3382 y_modulo;
3383
3384 /*
3385 Transfer a single pixel.
3386 */
3387 length=(MagickSizeType) 1;
3388 switch (virtual_pixel_method)
3389 {
3390 case BackgroundVirtualPixelMethod:
3391 case ConstantVirtualPixelMethod:
3392 case BlackVirtualPixelMethod:
3393 case GrayVirtualPixelMethod:
3394 case TransparentVirtualPixelMethod:
3395 case MaskVirtualPixelMethod:
3396 case WhiteVirtualPixelMethod:
3397 {
3398 p=(&virtual_pixel);
3399 break;
3400 }
3401 case EdgeVirtualPixelMethod:
3402 default:
3403 {
3404 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003405 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003406 1UL,1UL,virtual_nexus[0],exception);
3407 break;
3408 }
3409 case RandomVirtualPixelMethod:
3410 {
3411 if (cache_info->random_info == (RandomInfo *) NULL)
3412 cache_info->random_info=AcquireRandomInfo();
3413 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003414 RandomX(cache_info->random_info,cache_info->columns),
3415 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003416 virtual_nexus[0],exception);
3417 break;
3418 }
3419 case DitherVirtualPixelMethod:
3420 {
3421 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003422 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003423 1UL,1UL,virtual_nexus[0],exception);
3424 break;
3425 }
3426 case TileVirtualPixelMethod:
3427 {
3428 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3429 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3430 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3431 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3432 exception);
3433 break;
3434 }
3435 case MirrorVirtualPixelMethod:
3436 {
3437 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3438 if ((x_modulo.quotient & 0x01) == 1L)
3439 x_modulo.remainder=(long) cache_info->columns-
3440 x_modulo.remainder-1L;
3441 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3442 if ((y_modulo.quotient & 0x01) == 1L)
3443 y_modulo.remainder=(long) cache_info->rows-
3444 y_modulo.remainder-1L;
3445 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3446 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3447 exception);
3448 break;
3449 }
3450 case CheckerTileVirtualPixelMethod:
3451 {
3452 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3453 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3454 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3455 {
3456 p=(&virtual_pixel);
3457 break;
3458 }
3459 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3460 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3461 exception);
3462 break;
3463 }
3464 case HorizontalTileVirtualPixelMethod:
3465 {
3466 if (((y+v) < 0) || ((y+v) >= (long) cache_info->rows))
3467 {
3468 p=(&virtual_pixel);
3469 break;
3470 }
3471 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3472 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3473 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3474 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3475 exception);
3476 break;
3477 }
3478 case VerticalTileVirtualPixelMethod:
3479 {
3480 if (((x+u) < 0) || ((x+u) >= (long) cache_info->columns))
3481 {
3482 p=(&virtual_pixel);
3483 break;
3484 }
3485 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3486 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3487 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3488 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3489 exception);
3490 break;
3491 }
3492 case HorizontalTileEdgeVirtualPixelMethod:
3493 {
3494 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3495 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003496 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003497 virtual_nexus[0],exception);
3498 break;
3499 }
3500 case VerticalTileEdgeVirtualPixelMethod:
3501 {
3502 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3503 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003504 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003505 virtual_nexus[0],exception);
3506 break;
3507 }
3508 }
3509 if (p == (const PixelPacket *) NULL)
3510 break;
3511 *q++=(*p);
3512 if (indexes != (IndexPacket *) NULL)
3513 {
3514 nexus_indexes=GetVirtualIndexesFromNexus(cache_info,
3515 virtual_nexus[0]);
3516 if (nexus_indexes != (const IndexPacket *) NULL)
3517 *indexes++=(*nexus_indexes);
3518 }
3519 continue;
3520 }
3521 /*
3522 Transfer a run of pixels.
3523 */
3524 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,
3525 (unsigned long) length,1UL,virtual_nexus[0],exception);
3526 if (p == (const PixelPacket *) NULL)
3527 break;
3528 (void) CopyMagickMemory(q,p,(size_t) length*sizeof(*p));
3529 q+=length;
3530 if (indexes != (IndexPacket *) NULL)
3531 {
3532 nexus_indexes=GetVirtualIndexesFromNexus(cache_info,virtual_nexus[0]);
3533 if (nexus_indexes != (const IndexPacket *) NULL)
3534 {
3535 (void) CopyMagickMemory(indexes,nexus_indexes,(size_t) length*
3536 sizeof(*nexus_indexes));
3537 indexes+=length;
3538 }
3539 }
3540 }
3541 }
3542 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3543 return(pixels);
3544}
3545
3546/*
3547%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3548% %
3549% %
3550% %
3551+ G e t V i r t u a l P i x e l C a c h e %
3552% %
3553% %
3554% %
3555%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3556%
3557% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3558% cache as defined by the geometry parameters. A pointer to the pixels
3559% is returned if the pixels are transferred, otherwise a NULL is returned.
3560%
3561% The format of the GetVirtualPixelCache() method is:
3562%
3563% const PixelPacket *GetVirtualPixelCache(const Image *image,
3564% const VirtualPixelMethod virtual_pixel_method,const long x,
3565% const long y,const unsigned long columns,const unsigned long rows,
3566% ExceptionInfo *exception)
3567%
3568% A description of each parameter follows:
3569%
3570% o image: the image.
3571%
3572% o virtual_pixel_method: the virtual pixel method.
3573%
3574% o x,y,columns,rows: These values define the perimeter of a region of
3575% pixels.
3576%
3577% o exception: return any errors or warnings in this structure.
3578%
3579*/
3580static const PixelPacket *GetVirtualPixelCache(const Image *image,
3581 const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
3582 const unsigned long columns,const unsigned long rows,ExceptionInfo *exception)
3583{
3584 CacheInfo
3585 *cache_info;
3586
3587 const PixelPacket
3588 *pixels;
3589
3590 long
3591 id;
3592
3593 if (image->debug != MagickFalse)
3594 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3595 cache_info=(CacheInfo *) image->cache;
3596 id=GetOpenMPThreadId();
3597 assert(id < (long) cache_info->number_threads);
3598 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3599 cache_info->nexus_info[id],exception);
3600 return(pixels);
3601}
3602
3603/*
3604%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3605% %
3606% %
3607% %
3608% G e t V i r t u a l P i x e l Q u e u e %
3609% %
3610% %
3611% %
3612%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3613%
3614% GetVirtualPixelQueue() returns the virtual pixels associated with the
3615% last call to QueueAuthenticPixels() or GetVirtualPixels().
3616%
3617% The format of the GetVirtualPixelQueue() method is:
3618%
3619% const PixelPacket *GetVirtualPixelQueue(const Image image)
3620%
3621% A description of each parameter follows:
3622%
3623% o image: the image.
3624%
3625*/
3626MagickExport const PixelPacket *GetVirtualPixelQueue(const Image *image)
3627{
3628 CacheInfo
3629 *cache_info;
3630
3631 assert(image != (const Image *) NULL);
3632 assert(image->signature == MagickSignature);
3633 if (image->debug != MagickFalse)
3634 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3635 assert(image->cache != (Cache) NULL);
3636 cache_info=(CacheInfo *) image->cache;
3637 assert(cache_info->signature == MagickSignature);
3638 if (cache_info->methods.get_virtual_pixels_handler ==
3639 (GetVirtualPixelsHandler) NULL)
3640 return((PixelPacket *) NULL);
3641 return(cache_info->methods.get_virtual_pixels_handler(image));
3642}
3643
3644/*
3645%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3646% %
3647% %
3648% %
3649% G e t V i r t u a l P i x e l s %
3650% %
3651% %
3652% %
3653%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3654%
3655% GetVirtualPixels() returns an immutable pixel region. If the
3656% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003657% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003658% copy of the pixels or it may point to the original pixels in memory.
3659% Performance is maximized if the selected region is part of one row, or one
3660% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003661% (without a copy) if the image is in memory, or in a memory-mapped file. The
3662% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003663%
3664% Pixels accessed via the returned pointer represent a simple array of type
3665% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
3666% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access
3667% the black color component or to obtain the colormap indexes (of type
3668% IndexPacket) corresponding to the region.
3669%
3670% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3671%
3672% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3673% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3674% GetCacheViewAuthenticPixels() instead.
3675%
3676% The format of the GetVirtualPixels() method is:
3677%
3678% const PixelPacket *GetVirtualPixels(const Image *image,const long x,
3679% const long y,const unsigned long columns,const unsigned long rows,
3680% ExceptionInfo *exception)
3681%
3682% A description of each parameter follows:
3683%
3684% o image: the image.
3685%
3686% o x,y,columns,rows: These values define the perimeter of a region of
3687% pixels.
3688%
3689% o exception: return any errors or warnings in this structure.
3690%
3691*/
3692MagickExport const PixelPacket *GetVirtualPixels(const Image *image,
3693 const long x,const long y,const unsigned long columns,
3694 const unsigned long rows,ExceptionInfo *exception)
3695{
3696 CacheInfo
3697 *cache_info;
3698
3699 const PixelPacket
3700 *pixels;
3701
3702 assert(image != (const Image *) NULL);
3703 assert(image->signature == MagickSignature);
3704 if (image->debug != MagickFalse)
3705 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3706 assert(image->cache != (Cache) NULL);
3707 cache_info=(CacheInfo *) image->cache;
3708 assert(cache_info->signature == MagickSignature);
3709 if (cache_info->methods.get_virtual_pixel_handler ==
3710 (GetVirtualPixelHandler) NULL)
3711 return((const PixelPacket *) NULL);
3712 pixels=cache_info->methods.get_virtual_pixel_handler(image,
3713 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception);
3714 return(pixels);
3715}
3716
3717/*
3718%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3719% %
3720% %
3721% %
3722+ 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 %
3723% %
3724% %
3725% %
3726%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3727%
3728% GetVirtualPixelsCache() returns the pixels associated with the last call
3729% to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3730%
3731% The format of the GetVirtualPixelsCache() method is:
3732%
3733% PixelPacket *GetVirtualPixelsCache(const Image *image)
3734%
3735% A description of each parameter follows:
3736%
3737% o image: the image.
3738%
3739*/
3740static const PixelPacket *GetVirtualPixelsCache(const Image *image)
3741{
3742 CacheInfo
3743 *cache_info;
3744
3745 const PixelPacket
3746 *pixels;
3747
3748 long
3749 id;
3750
3751 if (image->debug != MagickFalse)
3752 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3753 cache_info=(CacheInfo *) image->cache;
3754 id=GetOpenMPThreadId();
3755 assert(id < (long) cache_info->number_threads);
3756 pixels=GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]);
3757 return(pixels);
3758}
3759
3760/*
3761%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3762% %
3763% %
3764% %
3765+ G e t V i r t u a l P i x e l s N e x u s %
3766% %
3767% %
3768% %
3769%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3770%
3771% GetVirtualPixelsNexus() returns the pixels associated with the specified
3772% cache nexus.
3773%
3774% The format of the GetVirtualPixelsNexus() method is:
3775%
3776% const IndexPacket *GetVirtualPixelsNexus(const Cache cache,
3777% NexusInfo *nexus_info)
3778%
3779% A description of each parameter follows:
3780%
3781% o cache: the pixel cache.
3782%
3783% o nexus_info: the cache nexus to return the colormap pixels.
3784%
3785*/
3786MagickExport const PixelPacket *GetVirtualPixelsNexus(const Cache cache,
3787 NexusInfo *nexus_info)
3788{
3789 CacheInfo
3790 *cache_info;
3791
3792 if (cache == (Cache) NULL)
3793 return((PixelPacket *) NULL);
3794 cache_info=(CacheInfo *) cache;
3795 assert(cache_info->signature == MagickSignature);
3796 if (cache_info->storage_class == UndefinedClass)
3797 return((PixelPacket *) NULL);
3798 return((const PixelPacket *) nexus_info->pixels);
3799}
3800
3801/*
3802%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3803% %
3804% %
3805% %
3806+ M a s k P i x e l C a c h e N e x u s %
3807% %
3808% %
3809% %
3810%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3811%
3812% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3813% The method returns MagickTrue if the pixel region is masked, otherwise
3814% MagickFalse.
3815%
3816% The format of the MaskPixelCacheNexus() method is:
3817%
3818% MagickBooleanType MaskPixelCacheNexus(Image *image,
3819% NexusInfo *nexus_info,ExceptionInfo *exception)
3820%
3821% A description of each parameter follows:
3822%
3823% o image: the image.
3824%
3825% o nexus_info: the cache nexus to clip.
3826%
3827% o exception: return any errors or warnings in this structure.
3828%
3829*/
3830
3831static inline void MagickPixelCompositeMask(const MagickPixelPacket *p,
3832 const MagickRealType alpha,const MagickPixelPacket *q,
3833 const MagickRealType beta,MagickPixelPacket *composite)
3834{
3835 MagickRealType
3836 gamma;
3837
3838 if (alpha == TransparentOpacity)
3839 {
3840 *composite=(*q);
3841 return;
3842 }
3843 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3844 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3845 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3846 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3847 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3848 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3849 composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
3850}
3851
3852static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3853 ExceptionInfo *exception)
3854{
3855 CacheInfo
3856 *cache_info;
3857
3858 MagickPixelPacket
3859 alpha,
3860 beta;
3861
3862 MagickSizeType
3863 number_pixels;
3864
3865 NexusInfo
3866 **clip_nexus,
3867 **image_nexus;
3868
3869 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003870 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003871
3872 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003873 *restrict nexus_indexes,
3874 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003875
3876 register long
3877 i;
3878
3879 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003880 *restrict p,
3881 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003882
3883 /*
3884 Apply clip mask.
3885 */
3886 if (image->debug != MagickFalse)
3887 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3888 if (image->mask == (Image *) NULL)
3889 return(MagickFalse);
3890 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
3891 if (cache_info == (Cache) NULL)
3892 return(MagickFalse);
3893 image_nexus=AcquirePixelCacheNexus(1);
3894 clip_nexus=AcquirePixelCacheNexus(1);
3895 if ((image_nexus == (NexusInfo **) NULL) ||
3896 (clip_nexus == (NexusInfo **) NULL))
3897 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy09449f72010-01-23 03:08:36 +00003898 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,
3899 nexus_info->region.y,nexus_info->region.width,nexus_info->region.height,
3900 image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003901 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
3902 q=nexus_info->pixels;
3903 nexus_indexes=nexus_info->indexes;
3904 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3905 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3906 nexus_info->region.height,clip_nexus[0],&image->exception);
3907 GetMagickPixelPacket(image,&alpha);
3908 GetMagickPixelPacket(image,&beta);
3909 number_pixels=(MagickSizeType) nexus_info->region.width*
3910 nexus_info->region.height;
3911 for (i=0; i < (long) number_pixels; i++)
3912 {
3913 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
3914 break;
3915 SetMagickPixelPacket(image,p,indexes+i,&alpha);
3916 SetMagickPixelPacket(image,q,nexus_indexes+i,&beta);
3917 MagickPixelCompositeMask(&beta,(MagickRealType) PixelIntensityToQuantum(r),
3918 &alpha,alpha.opacity,&beta);
cristyce70c172010-01-07 17:15:30 +00003919 q->red=ClampToQuantum(beta.red);
3920 q->green=ClampToQuantum(beta.green);
3921 q->blue=ClampToQuantum(beta.blue);
3922 q->opacity=ClampToQuantum(beta.opacity);
cristy3ed852e2009-09-05 21:47:34 +00003923 if (cache_info->active_index_channel != MagickFalse)
3924 nexus_indexes[i]=indexes[i];
3925 p++;
3926 q++;
3927 r++;
3928 }
3929 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3930 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
3931 if (i < (long) number_pixels)
3932 return(MagickFalse);
3933 return(MagickTrue);
3934}
3935
3936/*
3937%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3938% %
3939% %
3940% %
3941+ O p e n P i x e l C a c h e %
3942% %
3943% %
3944% %
3945%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3946%
3947% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3948% dimensions, allocating space for the image pixels and optionally the
3949% colormap indexes, and memory mapping the cache if it is disk based. The
3950% cache nexus array is initialized as well.
3951%
3952% The format of the OpenPixelCache() method is:
3953%
3954% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3955% ExceptionInfo *exception)
3956%
3957% A description of each parameter follows:
3958%
3959% o image: the image.
3960%
3961% o mode: ReadMode, WriteMode, or IOMode.
3962%
3963% o exception: return any errors or warnings in this structure.
3964%
3965*/
3966
cristyd43a46b2010-01-21 02:13:41 +00003967static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003968{
3969 cache_info->mapped=MagickFalse;
3970 cache_info->pixels=(PixelPacket *) AcquireMagickMemory((size_t)
3971 cache_info->length);
3972 if (cache_info->pixels == (PixelPacket *) NULL)
3973 {
3974 cache_info->mapped=MagickTrue;
3975 cache_info->pixels=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
3976 cache_info->length);
3977 }
3978}
3979
3980static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3981{
3982 CacheInfo
3983 *cache_info;
3984
3985 MagickOffsetType
3986 count,
3987 extent,
3988 offset;
3989
3990 cache_info=(CacheInfo *) image->cache;
3991 if (image->debug != MagickFalse)
3992 {
3993 char
3994 format[MaxTextExtent],
3995 message[MaxTextExtent];
3996
cristyb9080c92009-12-01 20:13:26 +00003997 (void) FormatMagickSize(length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00003998 (void) FormatMagickString(message,MaxTextExtent,
3999 "extend %s (%s[%d], disk, %s)",cache_info->filename,
4000 cache_info->cache_filename,cache_info->file,format);
4001 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4002 }
4003 if (length != (MagickSizeType) ((MagickOffsetType) length))
4004 return(MagickFalse);
4005 extent=(MagickOffsetType) MagickSeek(cache_info->file,0,SEEK_END);
4006 if (extent < 0)
4007 return(MagickFalse);
4008 if ((MagickSizeType) extent >= length)
4009 return(MagickTrue);
4010 offset=(MagickOffsetType) length-1;
4011 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
4012 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
4013}
4014
4015static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
4016 ExceptionInfo *exception)
4017{
4018 char
4019 format[MaxTextExtent],
4020 message[MaxTextExtent];
4021
4022 CacheInfo
4023 *cache_info,
4024 source_info;
4025
4026 MagickSizeType
4027 length,
4028 number_pixels;
4029
4030 MagickStatusType
4031 status;
4032
4033 size_t
4034 packet_size;
4035
4036 unsigned long
4037 columns;
4038
4039 if (image->debug != MagickFalse)
4040 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4041 if ((image->columns == 0) || (image->rows == 0))
4042 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
4043 cache_info=(CacheInfo *) image->cache;
4044 source_info=(*cache_info);
4045 source_info.file=(-1);
4046 (void) FormatMagickString(cache_info->filename,MaxTextExtent,"%s[%ld]",
4047 image->filename,GetImageIndexInList(image));
cristy87528ea2009-09-10 14:53:56 +00004048 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +00004049 cache_info->rows=image->rows;
4050 cache_info->columns=image->columns;
4051 cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
4052 (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
4053 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4054 packet_size=sizeof(PixelPacket);
4055 if (cache_info->active_index_channel != MagickFalse)
4056 packet_size+=sizeof(IndexPacket);
4057 length=number_pixels*packet_size;
4058 columns=(unsigned long) (length/cache_info->rows/packet_size);
4059 if (cache_info->columns != columns)
4060 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4061 image->filename);
4062 cache_info->length=length;
4063 status=AcquireMagickResource(AreaResource,cache_info->length);
4064 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4065 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4066 {
4067 status=AcquireMagickResource(MemoryResource,cache_info->length);
4068 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4069 (cache_info->type == MemoryCache))
4070 {
cristyd43a46b2010-01-21 02:13:41 +00004071 AllocatePixelCachePixels(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004072 if (cache_info->pixels == (PixelPacket *) NULL)
4073 cache_info->pixels=source_info.pixels;
4074 else
4075 {
4076 /*
4077 Create memory pixel cache.
4078 */
4079 if (image->debug != MagickFalse)
4080 {
cristy97e7a572009-12-05 15:07:53 +00004081 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004082 format);
cristy3ed852e2009-09-05 21:47:34 +00004083 (void) FormatMagickString(message,MaxTextExtent,
4084 "open %s (%s memory, %lux%lu %s)",cache_info->filename,
4085 cache_info->mapped != MagickFalse ? "anonymous" : "heap",
4086 cache_info->columns,cache_info->rows,format);
4087 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4088 message);
4089 }
4090 cache_info->storage_class=image->storage_class;
4091 cache_info->colorspace=image->colorspace;
4092 cache_info->type=MemoryCache;
4093 cache_info->indexes=(IndexPacket *) NULL;
4094 if (cache_info->active_index_channel != MagickFalse)
4095 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4096 number_pixels);
4097 if (source_info.storage_class != UndefinedClass)
4098 {
4099 status|=ClonePixelCachePixels(cache_info,&source_info,
4100 exception);
4101 RelinquishPixelCachePixels(&source_info);
4102 }
4103 return(MagickTrue);
4104 }
4105 }
4106 RelinquishMagickResource(MemoryResource,cache_info->length);
4107 }
4108 /*
4109 Create pixel cache on disk.
4110 */
4111 status=AcquireMagickResource(DiskResource,cache_info->length);
4112 if (status == MagickFalse)
4113 {
4114 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4115 "CacheResourcesExhausted","`%s'",image->filename);
4116 return(MagickFalse);
4117 }
4118 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4119 {
4120 RelinquishMagickResource(DiskResource,cache_info->length);
4121 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4122 image->filename);
4123 return(MagickFalse);
4124 }
4125 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4126 cache_info->length);
4127 if (status == MagickFalse)
4128 {
4129 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4130 image->filename);
4131 return(MagickFalse);
4132 }
4133 cache_info->storage_class=image->storage_class;
4134 cache_info->colorspace=image->colorspace;
4135 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4136 status=AcquireMagickResource(AreaResource,cache_info->length);
4137 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4138 cache_info->type=DiskCache;
4139 else
4140 {
4141 status=AcquireMagickResource(MapResource,cache_info->length);
4142 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4143 (cache_info->type != MemoryCache))
4144 cache_info->type=DiskCache;
4145 else
4146 {
4147 cache_info->pixels=(PixelPacket *) MapBlob(cache_info->file,mode,
4148 cache_info->offset,(size_t) cache_info->length);
4149 if (cache_info->pixels == (PixelPacket *) NULL)
4150 {
4151 cache_info->pixels=source_info.pixels;
4152 cache_info->type=DiskCache;
4153 }
4154 else
4155 {
4156 /*
4157 Create file-backed memory-mapped pixel cache.
4158 */
4159 (void) ClosePixelCacheOnDisk(cache_info);
4160 cache_info->type=MapCache;
4161 cache_info->mapped=MagickTrue;
4162 cache_info->indexes=(IndexPacket *) NULL;
4163 if (cache_info->active_index_channel != MagickFalse)
4164 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4165 number_pixels);
4166 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4167 {
4168 status=ClonePixelCachePixels(cache_info,&source_info,
4169 exception);
4170 RelinquishPixelCachePixels(&source_info);
4171 }
4172 if (image->debug != MagickFalse)
4173 {
cristy97e7a572009-12-05 15:07:53 +00004174 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004175 format);
cristy3ed852e2009-09-05 21:47:34 +00004176 (void) FormatMagickString(message,MaxTextExtent,
4177 "open %s (%s[%d], memory-mapped, %lux%lu %s)",
4178 cache_info->filename,cache_info->cache_filename,
4179 cache_info->file,cache_info->columns,cache_info->rows,
4180 format);
4181 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4182 message);
4183 }
4184 return(MagickTrue);
4185 }
4186 }
4187 RelinquishMagickResource(MapResource,cache_info->length);
4188 }
4189 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4190 {
4191 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4192 RelinquishPixelCachePixels(&source_info);
4193 }
4194 if (image->debug != MagickFalse)
4195 {
cristyb9080c92009-12-01 20:13:26 +00004196 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00004197 (void) FormatMagickString(message,MaxTextExtent,
4198 "open %s (%s[%d], disk, %lux%lu %s)",cache_info->filename,
4199 cache_info->cache_filename,cache_info->file,cache_info->columns,
4200 cache_info->rows,format);
4201 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4202 }
4203 return(MagickTrue);
4204}
4205
4206/*
4207%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4208% %
4209% %
4210% %
4211+ P e r s i s t P i x e l C a c h e %
4212% %
4213% %
4214% %
4215%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4216%
4217% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4218% persistent pixel cache is one that resides on disk and is not destroyed
4219% when the program exits.
4220%
4221% The format of the PersistPixelCache() method is:
4222%
4223% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4224% const MagickBooleanType attach,MagickOffsetType *offset,
4225% ExceptionInfo *exception)
4226%
4227% A description of each parameter follows:
4228%
4229% o image: the image.
4230%
4231% o filename: the persistent pixel cache filename.
4232%
cristy01b7eb02009-09-10 23:10:14 +00004233% o attach: A value other than zero initializes the persistent pixel
4234% cache.
4235%
cristy3ed852e2009-09-05 21:47:34 +00004236% o initialize: A value other than zero initializes the persistent pixel
4237% cache.
4238%
4239% o offset: the offset in the persistent cache to store pixels.
4240%
4241% o exception: return any errors or warnings in this structure.
4242%
4243*/
4244MagickExport MagickBooleanType PersistPixelCache(Image *image,
4245 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4246 ExceptionInfo *exception)
4247{
4248 CacheInfo
4249 *cache_info,
4250 *clone_info;
4251
4252 Image
4253 clone_image;
4254
4255 long
cristy688f07b2009-09-27 15:19:13 +00004256 page_size;
cristy3ed852e2009-09-05 21:47:34 +00004257
4258 MagickBooleanType
4259 status;
4260
4261 assert(image != (Image *) NULL);
4262 assert(image->signature == MagickSignature);
4263 if (image->debug != MagickFalse)
4264 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4265 assert(image->cache != (void *) NULL);
4266 assert(filename != (const char *) NULL);
4267 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004268 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004269 cache_info=(CacheInfo *) image->cache;
4270 assert(cache_info->signature == MagickSignature);
4271 if (attach != MagickFalse)
4272 {
4273 /*
cristy01b7eb02009-09-10 23:10:14 +00004274 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004275 */
4276 if (image->debug != MagickFalse)
4277 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4278 "attach persistent cache");
4279 (void) CopyMagickString(cache_info->cache_filename,filename,
4280 MaxTextExtent);
4281 cache_info->type=DiskCache;
4282 cache_info->offset=(*offset);
4283 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4284 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004285 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004286 return(MagickTrue);
4287 }
cristy01b7eb02009-09-10 23:10:14 +00004288 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4289 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004290 {
cristyf84a1932010-01-03 18:00:18 +00004291 LockSemaphoreInfo(cache_info->semaphore);
cristy09449f72010-01-23 03:08:36 +00004292 if ((cache_info->mode != ReadMode) &&
4293 (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004294 (cache_info->reference_count == 1))
4295 {
4296 int
4297 status;
4298
4299 /*
cristy01b7eb02009-09-10 23:10:14 +00004300 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004301 */
4302 status=rename(cache_info->cache_filename,filename);
4303 if (status == 0)
4304 {
4305 (void) CopyMagickString(cache_info->cache_filename,filename,
4306 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004307 *offset+=cache_info->length+page_size-(cache_info->length %
4308 page_size);
cristyf84a1932010-01-03 18:00:18 +00004309 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004310 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004311 if (image->debug != MagickFalse)
4312 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4313 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004314 return(MagickTrue);
4315 }
4316 }
cristyf84a1932010-01-03 18:00:18 +00004317 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004318 }
4319 /*
cristy01b7eb02009-09-10 23:10:14 +00004320 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004321 */
4322 clone_image=(*image);
4323 clone_info=(CacheInfo *) clone_image.cache;
4324 image->cache=ClonePixelCache(cache_info);
4325 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4326 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4327 cache_info->type=DiskCache;
4328 cache_info->offset=(*offset);
4329 cache_info=(CacheInfo *) image->cache;
4330 status=ClonePixelCacheNexus(cache_info,clone_info,exception);
4331 if (status != MagickFalse)
4332 {
4333 status=OpenPixelCache(image,IOMode,exception);
4334 if (status != MagickFalse)
4335 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
4336 }
cristy688f07b2009-09-27 15:19:13 +00004337 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004338 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4339 return(status);
4340}
4341
4342/*
4343%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4344% %
4345% %
4346% %
4347+ Q u e u e A u t h e n t i c N e x u s %
4348% %
4349% %
4350% %
4351%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4352%
4353% QueueAuthenticNexus() allocates an region to store image pixels as defined
4354% by the region rectangle and returns a pointer to the region. This region is
4355% subsequently transferred from the pixel cache with
4356% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4357% pixels are transferred, otherwise a NULL is returned.
4358%
4359% The format of the QueueAuthenticNexus() method is:
4360%
4361% PixelPacket *QueueAuthenticNexus(Image *image,const long x,const long y,
4362% const unsigned long columns,const unsigned long rows,
4363% NexusInfo *nexus_info,ExceptionInfo *exception)
4364%
4365% A description of each parameter follows:
4366%
4367% o image: the image.
4368%
4369% o x,y,columns,rows: These values define the perimeter of a region of
4370% pixels.
4371%
4372% o nexus_info: the cache nexus to set.
4373%
4374% o exception: return any errors or warnings in this structure.
4375%
4376*/
4377MagickExport PixelPacket *QueueAuthenticNexus(Image *image,const long x,
4378 const long y,const unsigned long columns,const unsigned long rows,
4379 NexusInfo *nexus_info,ExceptionInfo *exception)
4380{
4381 CacheInfo
4382 *cache_info;
4383
4384 MagickOffsetType
4385 offset;
4386
4387 MagickSizeType
4388 number_pixels;
4389
4390 RectangleInfo
4391 region;
4392
4393 /*
4394 Validate pixel cache geometry.
4395 */
4396 cache_info=(CacheInfo *) image->cache;
4397 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4398 {
4399 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4400 "NoPixelsDefinedInCache","`%s'",image->filename);
4401 return((PixelPacket *) NULL);
4402 }
4403 if ((x < 0) || (y < 0) || (x >= (long) cache_info->columns) ||
4404 (y >= (long) cache_info->rows))
4405 {
4406 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4407 "PixelsAreNotAuthentic","`%s'",image->filename);
4408 return((PixelPacket *) NULL);
4409 }
4410 offset=(MagickOffsetType) y*cache_info->columns+x;
4411 if (offset < 0)
4412 return((PixelPacket *) NULL);
4413 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4414 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4415 if ((MagickSizeType) offset >= number_pixels)
4416 return((PixelPacket *) NULL);
4417 /*
4418 Return pixel cache.
4419 */
4420 region.x=x;
4421 region.y=y;
4422 region.width=columns;
4423 region.height=rows;
4424 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4425}
4426
4427/*
4428%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4429% %
4430% %
4431% %
4432+ 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 %
4433% %
4434% %
4435% %
4436%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4437%
4438% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4439% defined by the region rectangle and returns a pointer to the region. This
4440% region is subsequently transferred from the pixel cache with
4441% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4442% pixels are transferred, otherwise a NULL is returned.
4443%
4444% The format of the QueueAuthenticPixelsCache() method is:
4445%
4446% PixelPacket *QueueAuthenticPixelsCache(Image *image,const long x,
4447% const long y,const unsigned long columns,const unsigned long rows,
4448% ExceptionInfo *exception)
4449%
4450% A description of each parameter follows:
4451%
4452% o image: the image.
4453%
4454% o x,y,columns,rows: These values define the perimeter of a region of
4455% pixels.
4456%
4457% o exception: return any errors or warnings in this structure.
4458%
4459*/
4460static PixelPacket *QueueAuthenticPixelsCache(Image *image,const long x,
4461 const long y,const unsigned long columns,const unsigned long rows,
4462 ExceptionInfo *exception)
4463{
4464 CacheInfo
4465 *cache_info;
4466
4467 long
4468 id;
4469
4470 PixelPacket
4471 *pixels;
4472
4473 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickFalse,exception);
4474 if (cache_info == (Cache) NULL)
4475 return((PixelPacket *) NULL);
4476 id=GetOpenMPThreadId();
4477 assert(id < (long) cache_info->number_threads);
4478 pixels=QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4479 exception);
4480 return(pixels);
4481}
4482
4483/*
4484%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4485% %
4486% %
4487% %
4488% Q u e u e A u t h e n t i c P i x e l s %
4489% %
4490% %
4491% %
4492%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4493%
4494% QueueAuthenticPixels() queues a mutable pixel region. If the region is
4495% successfully intialized a pointer to a PixelPacket array representing the
4496% region is returned, otherwise NULL is returned. The returned pointer may
4497% point to a temporary working buffer for the pixels or it may point to the
4498% final location of the pixels in memory.
4499%
4500% Write-only access means that any existing pixel values corresponding to
4501% the region are ignored. This is useful if the initial image is being
4502% created from scratch, or if the existing pixel values are to be
4503% completely replaced without need to refer to their pre-existing values.
4504% The application is free to read and write the pixel buffer returned by
4505% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4506% initialize the pixel array values. Initializing pixel array values is the
4507% application's responsibility.
4508%
4509% Performance is maximized if the selected region is part of one row, or
4510% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004511% pixels in-place (without a copy) if the image is in memory, or in a
4512% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004513% by the user.
4514%
4515% Pixels accessed via the returned pointer represent a simple array of type
4516% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
4517% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
4518% the black color component or the colormap indexes (of type IndexPacket)
4519% corresponding to the region. Once the PixelPacket (and/or IndexPacket)
4520% array has been updated, the changes must be saved back to the underlying
4521% image using SyncAuthenticPixels() or they may be lost.
4522%
4523% The format of the QueueAuthenticPixels() method is:
4524%
4525% PixelPacket *QueueAuthenticPixels(Image *image,const long x,const long y,
4526% const unsigned long columns,const unsigned long rows,
4527% ExceptionInfo *exception)
4528%
4529% A description of each parameter follows:
4530%
4531% o image: the image.
4532%
4533% o x,y,columns,rows: These values define the perimeter of a region of
4534% pixels.
4535%
4536% o exception: return any errors or warnings in this structure.
4537%
4538*/
4539MagickExport PixelPacket *QueueAuthenticPixels(Image *image,const long x,
4540 const long y,const unsigned long columns,const unsigned long rows,
4541 ExceptionInfo *exception)
4542{
4543 CacheInfo
4544 *cache_info;
4545
4546 PixelPacket
4547 *pixels;
4548
4549 assert(image != (Image *) NULL);
4550 assert(image->signature == MagickSignature);
4551 if (image->debug != MagickFalse)
4552 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4553 assert(image->cache != (Cache) NULL);
4554 cache_info=(CacheInfo *) image->cache;
4555 assert(cache_info->signature == MagickSignature);
4556 if (cache_info->methods.queue_authentic_pixels_handler ==
4557 (QueueAuthenticPixelsHandler) NULL)
4558 return((PixelPacket *) NULL);
4559 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4560 rows,exception);
4561 return(pixels);
4562}
4563
4564/*
4565%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4566% %
4567% %
4568% %
4569+ R e a d P i x e l C a c h e I n d e x e s %
4570% %
4571% %
4572% %
4573%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4574%
4575% ReadPixelCacheIndexes() reads colormap indexes from the specified region of
4576% the pixel cache.
4577%
4578% The format of the ReadPixelCacheIndexes() method is:
4579%
4580% MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4581% NexusInfo *nexus_info,ExceptionInfo *exception)
4582%
4583% A description of each parameter follows:
4584%
4585% o cache_info: the pixel cache.
4586%
4587% o nexus_info: the cache nexus to read the colormap indexes.
4588%
4589% o exception: return any errors or warnings in this structure.
4590%
4591*/
4592static MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4593 NexusInfo *nexus_info,ExceptionInfo *exception)
4594{
4595 MagickOffsetType
4596 count,
4597 offset;
4598
4599 MagickSizeType
4600 length,
4601 number_pixels;
4602
4603 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004604 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004605
4606 register long
4607 y;
4608
4609 unsigned long
4610 rows;
4611
4612 if (cache_info->debug != MagickFalse)
4613 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4614 cache_info->filename);
4615 if (cache_info->active_index_channel == MagickFalse)
4616 return(MagickFalse);
4617 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4618 return(MagickTrue);
4619 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4620 nexus_info->region.x;
4621 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
4622 rows=nexus_info->region.height;
4623 number_pixels=length*rows;
4624 if ((cache_info->columns == nexus_info->region.width) &&
4625 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4626 {
4627 length=number_pixels;
4628 rows=1UL;
4629 }
4630 q=nexus_info->indexes;
4631 switch (cache_info->type)
4632 {
4633 case MemoryCache:
4634 case MapCache:
4635 {
4636 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004637 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004638
4639 /*
4640 Read indexes from memory.
4641 */
4642 p=cache_info->indexes+offset;
4643 for (y=0; y < (long) rows; y++)
4644 {
4645 (void) CopyMagickMemory(q,p,(size_t) length);
4646 p+=cache_info->columns;
4647 q+=nexus_info->region.width;
4648 }
4649 break;
4650 }
4651 case DiskCache:
4652 {
4653 /*
4654 Read indexes from disk.
4655 */
4656 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4657 {
4658 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4659 cache_info->cache_filename);
4660 return(MagickFalse);
4661 }
4662 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4663 for (y=0; y < (long) rows; y++)
4664 {
4665 count=ReadPixelCacheRegion(cache_info,cache_info->offset+number_pixels*
4666 sizeof(PixelPacket)+offset*sizeof(*q),length,(unsigned char *) q);
4667 if ((MagickSizeType) count < length)
4668 break;
4669 offset+=cache_info->columns;
4670 q+=nexus_info->region.width;
4671 }
4672 if (y < (long) rows)
4673 {
4674 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4675 cache_info->cache_filename);
4676 return(MagickFalse);
4677 }
4678 break;
4679 }
4680 default:
4681 break;
4682 }
4683 if ((cache_info->debug != MagickFalse) &&
4684 (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4685 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
4686 cache_info->filename,nexus_info->region.width,nexus_info->region.height,
4687 nexus_info->region.x,nexus_info->region.y);
4688 return(MagickTrue);
4689}
4690
4691/*
4692%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4693% %
4694% %
4695% %
4696+ R e a d P i x e l C a c h e P i x e l s %
4697% %
4698% %
4699% %
4700%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4701%
4702% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4703% cache.
4704%
4705% The format of the ReadPixelCachePixels() method is:
4706%
4707% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4708% NexusInfo *nexus_info,ExceptionInfo *exception)
4709%
4710% A description of each parameter follows:
4711%
4712% o cache_info: the pixel cache.
4713%
4714% o nexus_info: the cache nexus to read the pixels.
4715%
4716% o exception: return any errors or warnings in this structure.
4717%
4718*/
4719static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4720 NexusInfo *nexus_info,ExceptionInfo *exception)
4721{
4722 MagickOffsetType
4723 count,
4724 offset;
4725
4726 MagickSizeType
4727 length,
4728 number_pixels;
4729
4730 register long
4731 y;
4732
4733 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004734 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004735
4736 unsigned long
4737 rows;
4738
4739 if (cache_info->debug != MagickFalse)
4740 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4741 cache_info->filename);
4742 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4743 return(MagickTrue);
4744 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4745 nexus_info->region.x;
4746 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
4747 rows=nexus_info->region.height;
4748 number_pixels=length*rows;
4749 if ((cache_info->columns == nexus_info->region.width) &&
4750 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4751 {
4752 length=number_pixels;
4753 rows=1UL;
4754 }
4755 q=nexus_info->pixels;
4756 switch (cache_info->type)
4757 {
4758 case MemoryCache:
4759 case MapCache:
4760 {
4761 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004762 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004763
4764 /*
4765 Read pixels from memory.
4766 */
4767 p=cache_info->pixels+offset;
4768 for (y=0; y < (long) rows; y++)
4769 {
4770 (void) CopyMagickMemory(q,p,(size_t) length);
4771 p+=cache_info->columns;
4772 q+=nexus_info->region.width;
4773 }
4774 break;
4775 }
4776 case DiskCache:
4777 {
4778 /*
4779 Read pixels from disk.
4780 */
4781 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4782 {
4783 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4784 cache_info->cache_filename);
4785 return(MagickFalse);
4786 }
4787 for (y=0; y < (long) rows; y++)
4788 {
4789 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4790 sizeof(*q),length,(unsigned char *) q);
4791 if ((MagickSizeType) count < length)
4792 break;
4793 offset+=cache_info->columns;
4794 q+=nexus_info->region.width;
4795 }
4796 if (y < (long) rows)
4797 {
4798 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4799 cache_info->cache_filename);
4800 return(MagickFalse);
4801 }
4802 break;
4803 }
4804 default:
4805 break;
4806 }
4807 if ((cache_info->debug != MagickFalse) &&
4808 (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4809 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
4810 cache_info->filename,nexus_info->region.width,nexus_info->region.height,
4811 nexus_info->region.x,nexus_info->region.y);
4812 return(MagickTrue);
4813}
4814
4815/*
4816%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4817% %
4818% %
4819% %
4820+ R e f e r e n c e P i x e l C a c h e %
4821% %
4822% %
4823% %
4824%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4825%
4826% ReferencePixelCache() increments the reference count associated with the
4827% pixel cache returning a pointer to the cache.
4828%
4829% The format of the ReferencePixelCache method is:
4830%
4831% Cache ReferencePixelCache(Cache cache_info)
4832%
4833% A description of each parameter follows:
4834%
4835% o cache_info: the pixel cache.
4836%
4837*/
4838MagickExport Cache ReferencePixelCache(Cache cache)
4839{
4840 CacheInfo
4841 *cache_info;
4842
4843 assert(cache != (Cache *) NULL);
4844 cache_info=(CacheInfo *) cache;
4845 assert(cache_info->signature == MagickSignature);
4846 if (cache_info->debug != MagickFalse)
4847 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4848 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00004849 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004850 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004851 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004852 return(cache_info);
4853}
4854
4855/*
4856%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4857% %
4858% %
4859% %
4860+ S e t P i x e l C a c h e M e t h o d s %
4861% %
4862% %
4863% %
4864%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4865%
4866% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4867%
4868% The format of the SetPixelCacheMethods() method is:
4869%
4870% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4871%
4872% A description of each parameter follows:
4873%
4874% o cache: the pixel cache.
4875%
4876% o cache_methods: Specifies a pointer to a CacheMethods structure.
4877%
4878*/
4879MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4880{
4881 CacheInfo
4882 *cache_info;
4883
4884 GetOneAuthenticPixelFromHandler
4885 get_one_authentic_pixel_from_handler;
4886
4887 GetOneVirtualPixelFromHandler
4888 get_one_virtual_pixel_from_handler;
4889
4890 /*
4891 Set cache pixel methods.
4892 */
4893 assert(cache != (Cache) NULL);
4894 assert(cache_methods != (CacheMethods *) NULL);
4895 cache_info=(CacheInfo *) cache;
4896 assert(cache_info->signature == MagickSignature);
4897 if (cache_info->debug != MagickFalse)
4898 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4899 cache_info->filename);
4900 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4901 cache_info->methods.get_virtual_pixel_handler=
4902 cache_methods->get_virtual_pixel_handler;
4903 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4904 cache_info->methods.destroy_pixel_handler=
4905 cache_methods->destroy_pixel_handler;
4906 if (cache_methods->get_virtual_indexes_from_handler !=
4907 (GetVirtualIndexesFromHandler) NULL)
4908 cache_info->methods.get_virtual_indexes_from_handler=
4909 cache_methods->get_virtual_indexes_from_handler;
4910 if (cache_methods->get_authentic_pixels_handler !=
4911 (GetAuthenticPixelsHandler) NULL)
4912 cache_info->methods.get_authentic_pixels_handler=
4913 cache_methods->get_authentic_pixels_handler;
4914 if (cache_methods->queue_authentic_pixels_handler !=
4915 (QueueAuthenticPixelsHandler) NULL)
4916 cache_info->methods.queue_authentic_pixels_handler=
4917 cache_methods->queue_authentic_pixels_handler;
4918 if (cache_methods->sync_authentic_pixels_handler !=
4919 (SyncAuthenticPixelsHandler) NULL)
4920 cache_info->methods.sync_authentic_pixels_handler=
4921 cache_methods->sync_authentic_pixels_handler;
4922 if (cache_methods->get_authentic_pixels_from_handler !=
4923 (GetAuthenticPixelsFromHandler) NULL)
4924 cache_info->methods.get_authentic_pixels_from_handler=
4925 cache_methods->get_authentic_pixels_from_handler;
4926 if (cache_methods->get_authentic_indexes_from_handler !=
4927 (GetAuthenticIndexesFromHandler) NULL)
4928 cache_info->methods.get_authentic_indexes_from_handler=
4929 cache_methods->get_authentic_indexes_from_handler;
4930 get_one_virtual_pixel_from_handler=
4931 cache_info->methods.get_one_virtual_pixel_from_handler;
4932 if (get_one_virtual_pixel_from_handler !=
4933 (GetOneVirtualPixelFromHandler) NULL)
4934 cache_info->methods.get_one_virtual_pixel_from_handler=
4935 cache_methods->get_one_virtual_pixel_from_handler;
4936 get_one_authentic_pixel_from_handler=
4937 cache_methods->get_one_authentic_pixel_from_handler;
4938 if (get_one_authentic_pixel_from_handler !=
4939 (GetOneAuthenticPixelFromHandler) NULL)
4940 cache_info->methods.get_one_authentic_pixel_from_handler=
4941 cache_methods->get_one_authentic_pixel_from_handler;
4942}
4943
4944/*
4945%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4946% %
4947% %
4948% %
4949+ S e t P i x e l C a c h e N e x u s P i x e l s %
4950% %
4951% %
4952% %
4953%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4954%
4955% SetPixelCacheNexusPixels() defines the region of the cache for the
4956% specified cache nexus.
4957%
4958% The format of the SetPixelCacheNexusPixels() method is:
4959%
4960% PixelPacket SetPixelCacheNexusPixels(const Image *image,
4961% const RectangleInfo *region,NexusInfo *nexus_info,
4962% ExceptionInfo *exception)
4963%
4964% A description of each parameter follows:
4965%
4966% o image: the image.
4967%
4968% o region: A pointer to the RectangleInfo structure that defines the
4969% region of this particular cache nexus.
4970%
4971% o nexus_info: the cache nexus to set.
4972%
4973% o exception: return any errors or warnings in this structure.
4974%
4975*/
4976static PixelPacket *SetPixelCacheNexusPixels(const Image *image,
4977 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4978{
4979 CacheInfo
4980 *cache_info;
4981
4982 MagickBooleanType
4983 status;
4984
4985 MagickOffsetType
4986 offset;
4987
4988 MagickSizeType
4989 length,
4990 number_pixels;
4991
4992 if (image->debug != MagickFalse)
4993 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4994 cache_info=(CacheInfo *) image->cache;
4995 assert(cache_info->signature == MagickSignature);
4996 if (cache_info->type == UndefinedCache)
4997 return((PixelPacket *) NULL);
4998 nexus_info->region.width=region->width == 0UL ? 1UL : region->width;
4999 nexus_info->region.height=region->height == 0UL ? 1UL : region->height;
5000 nexus_info->region.x=region->x;
5001 nexus_info->region.y=region->y;
5002 if ((cache_info->type != DiskCache) && (image->clip_mask == (Image *) NULL) &&
5003 (image->mask == (Image *) NULL))
5004 {
5005 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5006 nexus_info->region.x;
5007 length=(MagickSizeType) (nexus_info->region.height-1)*cache_info->columns+
5008 nexus_info->region.width-1;
5009 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
5010 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
5011 {
5012 long
5013 x,
5014 y;
5015
5016 x=nexus_info->region.x+nexus_info->region.width;
5017 y=nexus_info->region.y+nexus_info->region.height;
5018 if ((nexus_info->region.x >= 0) &&
5019 (x <= (long) cache_info->columns) &&
5020 (nexus_info->region.y >= 0) && (y <= (long) cache_info->rows))
5021 if ((nexus_info->region.height == 1UL) ||
5022 ((nexus_info->region.x == 0) &&
5023 ((nexus_info->region.width % cache_info->columns) == 0)))
5024 {
5025 /*
5026 Pixels are accessed directly from memory.
5027 */
5028 nexus_info->pixels=cache_info->pixels+offset;
5029 nexus_info->indexes=(IndexPacket *) NULL;
5030 if (cache_info->active_index_channel != MagickFalse)
5031 nexus_info->indexes=cache_info->indexes+offset;
5032 return(nexus_info->pixels);
5033 }
5034 }
5035 }
5036 /*
5037 Pixels are stored in a cache region until they are synced to the cache.
5038 */
5039 number_pixels=(MagickSizeType) nexus_info->region.width*
5040 nexus_info->region.height;
5041 length=number_pixels*sizeof(PixelPacket);
5042 if (cache_info->active_index_channel != MagickFalse)
5043 length+=number_pixels*sizeof(IndexPacket);
5044 if (nexus_info->cache == (PixelPacket *) NULL)
5045 {
5046 nexus_info->length=length;
5047 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5048 if (status == MagickFalse)
5049 return((PixelPacket *) NULL);
5050 }
5051 else
5052 if (nexus_info->length != length)
5053 {
5054 RelinquishCacheNexusPixels(nexus_info);
5055 nexus_info->length=length;
5056 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5057 if (status == MagickFalse)
5058 return((PixelPacket *) NULL);
5059 }
5060 nexus_info->pixels=nexus_info->cache;
5061 nexus_info->indexes=(IndexPacket *) NULL;
5062 if (cache_info->active_index_channel != MagickFalse)
5063 nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
5064 return(nexus_info->pixels);
5065}
5066
5067/*
5068%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5069% %
5070% %
5071% %
5072% 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 %
5073% %
5074% %
5075% %
5076%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5077%
5078% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5079% pixel cache and returns the previous setting. A virtual pixel is any pixel
5080% access that is outside the boundaries of the image cache.
5081%
5082% The format of the SetPixelCacheVirtualMethod() method is:
5083%
5084% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5085% const VirtualPixelMethod virtual_pixel_method)
5086%
5087% A description of each parameter follows:
5088%
5089% o image: the image.
5090%
5091% o virtual_pixel_method: choose the type of virtual pixel.
5092%
5093*/
5094MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5095 const VirtualPixelMethod virtual_pixel_method)
5096{
5097 CacheInfo
5098 *cache_info;
5099
5100 VirtualPixelMethod
5101 method;
5102
5103 assert(image != (Image *) NULL);
5104 assert(image->signature == MagickSignature);
5105 if (image->debug != MagickFalse)
5106 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5107 assert(image->cache != (Cache) NULL);
5108 cache_info=(CacheInfo *) image->cache;
5109 assert(cache_info->signature == MagickSignature);
5110 method=cache_info->virtual_pixel_method;
5111 cache_info->virtual_pixel_method=virtual_pixel_method;
5112 return(method);
5113}
5114
5115/*
5116%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5117% %
5118% %
5119% %
5120+ 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 %
5121% %
5122% %
5123% %
5124%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5125%
5126% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5127% in-memory or disk cache. The method returns MagickTrue if the pixel region
5128% is synced, otherwise MagickFalse.
5129%
5130% The format of the SyncAuthenticPixelCacheNexus() method is:
5131%
5132% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5133% NexusInfo *nexus_info,ExceptionInfo *exception)
5134%
5135% A description of each parameter follows:
5136%
5137% o image: the image.
5138%
5139% o nexus_info: the cache nexus to sync.
5140%
5141% o exception: return any errors or warnings in this structure.
5142%
5143*/
5144MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5145 NexusInfo *nexus_info,ExceptionInfo *exception)
5146{
5147 CacheInfo
5148 *cache_info;
5149
5150 MagickBooleanType
5151 status;
5152
5153 /*
5154 Transfer pixels to the cache.
5155 */
5156 assert(image != (Image *) NULL);
5157 assert(image->signature == MagickSignature);
5158 if (image->debug != MagickFalse)
5159 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5160 if (image->cache == (Cache) NULL)
5161 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5162 cache_info=(CacheInfo *) image->cache;
5163 if (cache_info->type == UndefinedCache)
5164 return(MagickFalse);
5165 if ((image->clip_mask != (Image *) NULL) &&
5166 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5167 return(MagickFalse);
5168 if ((image->mask != (Image *) NULL) &&
5169 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5170 return(MagickFalse);
5171 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5172 return(MagickTrue);
5173 assert(cache_info->signature == MagickSignature);
5174 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5175 if ((cache_info->active_index_channel != MagickFalse) &&
5176 (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
5177 return(MagickFalse);
5178 return(status);
5179}
5180
5181/*
5182%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5183% %
5184% %
5185% %
5186+ S y n c A u t h e n t i c P i x e l C a c h e %
5187% %
5188% %
5189% %
5190%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5191%
5192% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5193% or disk cache. The method returns MagickTrue if the pixel region is synced,
5194% otherwise MagickFalse.
5195%
5196% The format of the SyncAuthenticPixelsCache() method is:
5197%
5198% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5199% ExceptionInfo *exception)
5200%
5201% A description of each parameter follows:
5202%
5203% o image: the image.
5204%
5205% o exception: return any errors or warnings in this structure.
5206%
5207*/
5208static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5209 ExceptionInfo *exception)
5210{
5211 CacheInfo
5212 *cache_info;
5213
5214 long
5215 id;
5216
5217 MagickBooleanType
5218 status;
5219
5220 cache_info=(CacheInfo *) image->cache;
5221 id=GetOpenMPThreadId();
5222 assert(id < (long) cache_info->number_threads);
5223 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5224 exception);
5225 return(status);
5226}
5227
5228/*
5229%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5230% %
5231% %
5232% %
5233% S y n c A u t h e n t i c P i x e l s %
5234% %
5235% %
5236% %
5237%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5238%
5239% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5240% The method returns MagickTrue if the pixel region is flushed, otherwise
5241% MagickFalse.
5242%
5243% The format of the SyncAuthenticPixels() method is:
5244%
5245% MagickBooleanType SyncAuthenticPixels(Image *image,
5246% ExceptionInfo *exception)
5247%
5248% A description of each parameter follows:
5249%
5250% o image: the image.
5251%
5252% o exception: return any errors or warnings in this structure.
5253%
5254*/
5255MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5256 ExceptionInfo *exception)
5257{
5258 CacheInfo
5259 *cache_info;
5260
5261 assert(image != (Image *) NULL);
5262 assert(image->signature == MagickSignature);
5263 if (image->debug != MagickFalse)
5264 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5265 assert(image->cache != (Cache) NULL);
5266 cache_info=(CacheInfo *) image->cache;
5267 assert(cache_info->signature == MagickSignature);
5268 if (cache_info->methods.sync_authentic_pixels_handler ==
5269 (SyncAuthenticPixelsHandler) NULL)
5270 return(MagickFalse);
5271 return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
5272}
5273
5274/*
5275%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5276% %
5277% %
5278% %
5279+ W r i t e P i x e l C a c h e I n d e x e s %
5280% %
5281% %
5282% %
5283%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5284%
5285% WritePixelCacheIndexes() writes the colormap indexes to the specified
5286% region of the pixel cache.
5287%
5288% The format of the WritePixelCacheIndexes() method is:
5289%
5290% MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5291% NexusInfo *nexus_info,ExceptionInfo *exception)
5292%
5293% A description of each parameter follows:
5294%
5295% o cache_info: the pixel cache.
5296%
5297% o nexus_info: the cache nexus to write the colormap indexes.
5298%
5299% o exception: return any errors or warnings in this structure.
5300%
5301*/
5302static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5303 NexusInfo *nexus_info,ExceptionInfo *exception)
5304{
5305 MagickOffsetType
5306 count,
5307 offset;
5308
5309 MagickSizeType
5310 length,
5311 number_pixels;
5312
5313 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005314 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005315
5316 register long
5317 y;
5318
5319 unsigned long
5320 rows;
5321
5322 if (cache_info->debug != MagickFalse)
5323 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
5324 cache_info->filename);
5325 if (cache_info->active_index_channel == MagickFalse)
5326 return(MagickFalse);
5327 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5328 return(MagickTrue);
5329 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5330 nexus_info->region.x;
5331 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
5332 rows=nexus_info->region.height;
5333 number_pixels=(MagickSizeType) length*rows;
5334 if ((cache_info->columns == nexus_info->region.width) &&
5335 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5336 {
5337 length=number_pixels;
5338 rows=1UL;
5339 }
5340 p=nexus_info->indexes;
5341 switch (cache_info->type)
5342 {
5343 case MemoryCache:
5344 case MapCache:
5345 {
5346 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005347 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005348
5349 /*
5350 Write indexes to memory.
5351 */
5352 q=cache_info->indexes+offset;
5353 for (y=0; y < (long) rows; y++)
5354 {
5355 (void) CopyMagickMemory(q,p,(size_t) length);
5356 p+=nexus_info->region.width;
5357 q+=cache_info->columns;
5358 }
5359 break;
5360 }
5361 case DiskCache:
5362 {
5363 /*
5364 Write indexes to disk.
5365 */
5366 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5367 {
5368 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5369 cache_info->cache_filename);
5370 return(MagickFalse);
5371 }
5372 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
5373 for (y=0; y < (long) rows; y++)
5374 {
5375 count=WritePixelCacheRegion(cache_info,cache_info->offset+number_pixels*
5376 sizeof(PixelPacket)+offset*sizeof(*p),length,
5377 (const unsigned char *) p);
5378 if ((MagickSizeType) count < length)
5379 break;
5380 p+=nexus_info->region.width;
5381 offset+=cache_info->columns;
5382 }
5383 if (y < (long) rows)
5384 {
5385 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5386 cache_info->cache_filename);
5387 return(MagickFalse);
5388 }
5389 break;
5390 }
5391 default:
5392 break;
5393 }
5394 if ((cache_info->debug != MagickFalse) &&
5395 (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5396 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
5397 cache_info->filename,nexus_info->region.width,nexus_info->region.height,
5398 nexus_info->region.x,nexus_info->region.y);
5399 return(MagickTrue);
5400}
5401
5402/*
5403%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5404% %
5405% %
5406% %
5407+ W r i t e C a c h e P i x e l s %
5408% %
5409% %
5410% %
5411%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5412%
5413% WritePixelCachePixels() writes image pixels to the specified region of the
5414% pixel cache.
5415%
5416% The format of the WritePixelCachePixels() method is:
5417%
5418% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5419% NexusInfo *nexus_info,ExceptionInfo *exception)
5420%
5421% A description of each parameter follows:
5422%
5423% o cache_info: the pixel cache.
5424%
5425% o nexus_info: the cache nexus to write the pixels.
5426%
5427% o exception: return any errors or warnings in this structure.
5428%
5429*/
5430static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5431 NexusInfo *nexus_info,ExceptionInfo *exception)
5432{
5433 MagickOffsetType
5434 count,
5435 offset;
5436
5437 MagickSizeType
5438 length,
5439 number_pixels;
5440
cristy3ed852e2009-09-05 21:47:34 +00005441 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005442 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005443
cristy25ffffb2009-12-07 17:15:07 +00005444 register long
5445 y;
5446
cristy3ed852e2009-09-05 21:47:34 +00005447 unsigned long
5448 rows;
5449
5450 if (cache_info->debug != MagickFalse)
5451 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
5452 cache_info->filename);
5453 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5454 return(MagickTrue);
5455 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5456 nexus_info->region.x;
5457 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
5458 rows=nexus_info->region.height;
5459 number_pixels=length*rows;
5460 if ((cache_info->columns == nexus_info->region.width) &&
5461 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5462 {
5463 length=number_pixels;
5464 rows=1UL;
5465 }
5466 p=nexus_info->pixels;
5467 switch (cache_info->type)
5468 {
5469 case MemoryCache:
5470 case MapCache:
5471 {
5472 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005473 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005474
5475 /*
5476 Write pixels to memory.
5477 */
5478 q=cache_info->pixels+offset;
5479 for (y=0; y < (long) rows; y++)
5480 {
5481 (void) CopyMagickMemory(q,p,(size_t) length);
5482 p+=nexus_info->region.width;
5483 q+=cache_info->columns;
5484 }
5485 break;
5486 }
5487 case DiskCache:
5488 {
5489 /*
5490 Write pixels to disk.
5491 */
5492 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5493 {
5494 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5495 cache_info->cache_filename);
5496 return(MagickFalse);
5497 }
5498 for (y=0; y < (long) rows; y++)
5499 {
5500 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5501 sizeof(*p),length,(const unsigned char *) p);
5502 if ((MagickSizeType) count < length)
5503 break;
5504 p+=nexus_info->region.width;
5505 offset+=cache_info->columns;
5506 }
5507 if (y < (long) rows)
5508 {
5509 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5510 cache_info->cache_filename);
5511 return(MagickFalse);
5512 }
5513 break;
5514 }
5515 default:
5516 break;
5517 }
5518 if ((cache_info->debug != MagickFalse) &&
5519 (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5520 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
5521 cache_info->filename,nexus_info->region.width,nexus_info->region.height,
5522 nexus_info->region.x,nexus_info->region.y);
5523 return(MagickTrue);
5524}