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