blob: 78d61225c8061693db979f0b6b87233a5924a38e [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% CCCC AAA CCCC H H EEEEE %
7% C A A C H H E %
8% C AAAAA C HHHHH EEE %
9% C A A C H H E %
10% CCCC A A CCCC H H EEEEE %
11% %
12% %
13% MagickCore Pixel Cache Methods %
14% %
15% Software Design %
16% John Cristy %
17% July 1999 %
18% %
19% %
cristy16af1cb2009-12-11 21:38:29 +000020% Copyright 1999-2010 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% http://www.imagemagick.org/script/license.php %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37%
38*/
39
40/*
41 Include declarations.
42*/
43#include "magick/studio.h"
44#include "magick/blob.h"
45#include "magick/blob-private.h"
46#include "magick/cache.h"
47#include "magick/cache-private.h"
48#include "magick/color-private.h"
49#include "magick/composite-private.h"
50#include "magick/exception.h"
51#include "magick/exception-private.h"
cristy365e58f2010-02-15 02:00:01 +000052#include "magick/geometry.h"
cristy3ed852e2009-09-05 21:47:34 +000053#include "magick/list.h"
54#include "magick/log.h"
55#include "magick/magick.h"
56#include "magick/memory_.h"
cristy4789f0d2010-01-10 00:01:06 +000057#include "magick/pixel.h"
cristy3ed852e2009-09-05 21:47:34 +000058#include "magick/pixel-private.h"
59#include "magick/quantum.h"
60#include "magick/random_.h"
61#include "magick/resource_.h"
62#include "magick/semaphore.h"
63#include "magick/splay-tree.h"
64#include "magick/string_.h"
65#include "magick/thread-private.h"
66#include "magick/utility.h"
67#if defined(MAGICKCORE_ZLIB_DELEGATE)
68#include "zlib.h"
69#endif
70
71/*
cristy30097232010-07-01 02:16:30 +000072 Define declarations.
73*/
74#define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
75
76/*
cristy3ed852e2009-09-05 21:47:34 +000077 Typedef declarations.
78*/
79typedef struct _MagickModulo
80{
cristybb503372010-05-27 20:51:26 +000081 ssize_t
cristy3ed852e2009-09-05 21:47:34 +000082 quotient,
83 remainder;
84} MagickModulo;
85
86struct _NexusInfo
87{
88 MagickBooleanType
89 mapped;
90
91 RectangleInfo
92 region;
93
94 MagickSizeType
95 length;
96
97 PixelPacket
98 *cache,
99 *pixels;
100
101 IndexPacket
102 *indexes;
103
cristybb503372010-05-27 20:51:26 +0000104 size_t
cristy3ed852e2009-09-05 21:47:34 +0000105 signature;
106};
107
108/*
109 Forward declarations.
110*/
111#if defined(__cplusplus) || defined(c_plusplus)
112extern "C" {
113#endif
114
115static const IndexPacket
116 *GetVirtualIndexesFromCache(const Image *);
117
118static const PixelPacket
cristybb503372010-05-27 20:51:26 +0000119 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
120 const ssize_t,const size_t,const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000121 *GetVirtualPixelsCache(const Image *);
122
123static MagickBooleanType
cristy09c1c4d2010-06-30 18:23:16 +0000124 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,
125 PixelPacket *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000126 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
cristybb503372010-05-27 20:51:26 +0000127 const ssize_t,const ssize_t,PixelPacket *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000128 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
129 ReadPixelCacheIndexes(CacheInfo *,NexusInfo *,ExceptionInfo *),
130 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
131 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
132 WritePixelCacheIndexes(CacheInfo *,NexusInfo *,ExceptionInfo *),
133 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
134
135static PixelPacket
cristybb503372010-05-27 20:51:26 +0000136 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
137 const size_t,ExceptionInfo *),
138 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
139 const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000140 *SetPixelCacheNexusPixels(const Image *,const RectangleInfo *,NexusInfo *,
cristya4af2e32010-03-08 00:51:56 +0000141 ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +0000142
143#if defined(__cplusplus) || defined(c_plusplus)
144}
145#endif
146
147/*
148 Global declarations.
149*/
150static volatile MagickBooleanType
151 instantiate_cache = MagickFalse;
152
153static SemaphoreInfo
154 *cache_semaphore = (SemaphoreInfo *) NULL;
155
156static SplayTreeInfo
157 *cache_resources = (SplayTreeInfo *) NULL;
cristy3ed852e2009-09-05 21:47:34 +0000158
159/*
160%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
161% %
162% %
163% %
164+ A c q u i r e P i x e l C a c h e %
165% %
166% %
167% %
168%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
169%
170% AcquirePixelCache() acquires a pixel cache.
171%
172% The format of the AcquirePixelCache() method is:
173%
cristybb503372010-05-27 20:51:26 +0000174% Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000175%
176% A description of each parameter follows:
177%
178% o number_threads: the number of nexus threads.
179%
180*/
cristybb503372010-05-27 20:51:26 +0000181MagickExport Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000182{
183 CacheInfo
184 *cache_info;
185
186 cache_info=(CacheInfo *) AcquireAlignedMemory(1,sizeof(*cache_info));
187 if (cache_info == (CacheInfo *) NULL)
188 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
189 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
190 cache_info->type=UndefinedCache;
cristy87528ea2009-09-10 14:53:56 +0000191 cache_info->mode=IOMode;
cristy3ed852e2009-09-05 21:47:34 +0000192 cache_info->colorspace=RGBColorspace;
193 cache_info->file=(-1);
194 cache_info->id=GetMagickThreadId();
195 cache_info->number_threads=number_threads;
196 if (number_threads == 0)
197 cache_info->number_threads=GetOpenMPMaximumThreads();
198 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
199 if (cache_info->nexus_info == (NexusInfo **) NULL)
200 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
201 GetPixelCacheMethods(&cache_info->methods);
202 cache_info->reference_count=1;
203 cache_info->semaphore=AllocateSemaphoreInfo();
204 cache_info->disk_semaphore=AllocateSemaphoreInfo();
205 cache_info->debug=IsEventLogging();
206 cache_info->signature=MagickSignature;
207 if ((cache_resources == (SplayTreeInfo *) NULL) &&
208 (instantiate_cache == MagickFalse))
209 {
cristy4e1dff62009-10-25 20:36:03 +0000210 if (cache_semaphore == (SemaphoreInfo *) NULL)
211 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000212 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000213 if ((cache_resources == (SplayTreeInfo *) NULL) &&
214 (instantiate_cache == MagickFalse))
215 {
216 cache_resources=NewSplayTree((int (*)(const void *,const void *))
217 NULL,(void *(*)(void *)) NULL,(void *(*)(void *)) NULL);
218 instantiate_cache=MagickTrue;
219 }
cristyf84a1932010-01-03 18:00:18 +0000220 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000221 }
222 (void) AddValueToSplayTree(cache_resources,cache_info,cache_info);
223 return((Cache ) cache_info);
224}
225
226/*
227%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
228% %
229% %
230% %
231% A c q u i r e P i x e l C a c h e N e x u s %
232% %
233% %
234% %
235%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
236%
237% AcquirePixelCacheNexus() allocates the NexusInfo structure.
238%
239% The format of the AcquirePixelCacheNexus method is:
240%
cristybb503372010-05-27 20:51:26 +0000241% NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000242%
243% A description of each parameter follows:
244%
245% o number_threads: the number of nexus threads.
246%
247*/
248MagickExport NexusInfo **AcquirePixelCacheNexus(
cristybb503372010-05-27 20:51:26 +0000249 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000250{
cristybb503372010-05-27 20:51:26 +0000251 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000252 i;
253
254 NexusInfo
255 **nexus_info;
256
257 nexus_info=(NexusInfo **) AcquireAlignedMemory(number_threads,
258 sizeof(*nexus_info));
259 if (nexus_info == (NexusInfo **) NULL)
260 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristybb503372010-05-27 20:51:26 +0000261 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000262 {
263 nexus_info[i]=(NexusInfo *) AcquireAlignedMemory(1,sizeof(**nexus_info));
264 if (nexus_info[i] == (NexusInfo *) NULL)
265 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
266 (void) ResetMagickMemory(nexus_info[i],0,sizeof(*nexus_info[i]));
267 nexus_info[i]->signature=MagickSignature;
268 }
269 return(nexus_info);
270}
271
272/*
273%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
274% %
275% %
276% %
cristyd43a46b2010-01-21 02:13:41 +0000277+ A c q u i r e P i x e l C a c h e P i x e l s %
278% %
279% %
280% %
281%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
282%
283% AcquirePixelCachePixels() returns the pixels associated with the specified
284% image.
285%
286% The format of the AcquirePixelCachePixels() method is:
287%
288% const void *AcquirePixelCachePixels(const Image *image,
289% MagickSizeType *length,ExceptionInfo *exception)
290%
291% A description of each parameter follows:
292%
293% o image: the image.
294%
295% o length: the pixel cache length.
296%
297% o exception: return any errors or warnings in this structure.
298%
299*/
300MagickExport const void *AcquirePixelCachePixels(const Image *image,
301 MagickSizeType *length,ExceptionInfo *exception)
302{
303 CacheInfo
304 *cache_info;
305
306 assert(image != (const Image *) NULL);
307 assert(image->signature == MagickSignature);
308 if (image->debug != MagickFalse)
309 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
310 assert(exception != (ExceptionInfo *) NULL);
311 assert(exception->signature == MagickSignature);
312 assert(image->cache != (Cache) NULL);
313 cache_info=(CacheInfo *) image->cache;
314 assert(cache_info->signature == MagickSignature);
315 *length=0;
316 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
317 return((const void *) NULL);
318 *length=cache_info->length;
319 return((const void *) cache_info->pixels);
320}
321
322/*
323%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
324% %
325% %
326% %
cristyf34a1452009-10-24 22:29:27 +0000327+ C a c h e C o m p o n e n t G e n e s i s %
328% %
329% %
330% %
331%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
332%
333% CacheComponentGenesis() instantiates the cache component.
334%
335% The format of the CacheComponentGenesis method is:
336%
337% MagickBooleanType CacheComponentGenesis(void)
338%
339*/
340MagickExport MagickBooleanType CacheComponentGenesis(void)
341{
cristy165b6092009-10-26 13:52:10 +0000342 AcquireSemaphoreInfo(&cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000343 return(MagickTrue);
344}
345
346/*
347%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
348% %
349% %
350% %
351+ C a c h e C o m p o n e n t T e r m i n u s %
352% %
353% %
354% %
355%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
356%
357% CacheComponentTerminus() destroys the cache component.
358%
359% The format of the CacheComponentTerminus() method is:
360%
361% CacheComponentTerminus(void)
362%
363*/
364MagickExport void CacheComponentTerminus(void)
365{
cristy18b17442009-10-25 18:36:48 +0000366 if (cache_semaphore == (SemaphoreInfo *) NULL)
367 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000368 LockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000369 if (cache_resources != (SplayTreeInfo *) NULL)
370 cache_resources=DestroySplayTree(cache_resources);
371 instantiate_cache=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +0000372 UnlockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000373 DestroySemaphoreInfo(&cache_semaphore);
374}
375
376/*
377%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
378% %
379% %
380% %
cristy3ed852e2009-09-05 21:47:34 +0000381+ C l i p P i x e l C a c h e N e x u s %
382% %
383% %
384% %
385%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
386%
387% ClipPixelCacheNexus() clips the cache nexus as defined by the image clip
388% mask. The method returns MagickTrue if the pixel region is clipped,
389% otherwise MagickFalse.
390%
391% The format of the ClipPixelCacheNexus() method is:
392%
393% MagickBooleanType ClipPixelCacheNexus(Image *image,NexusInfo *nexus_info,
394% ExceptionInfo *exception)
395%
396% A description of each parameter follows:
397%
398% o image: the image.
399%
400% o nexus_info: the cache nexus to clip.
401%
402% o exception: return any errors or warnings in this structure.
403%
404*/
405static MagickBooleanType ClipPixelCacheNexus(Image *image,
406 NexusInfo *nexus_info,ExceptionInfo *exception)
407{
408 CacheInfo
409 *cache_info;
410
411 MagickSizeType
412 number_pixels;
413
414 NexusInfo
415 **clip_nexus,
416 **image_nexus;
417
418 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000419 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +0000420
421 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +0000422 *restrict nexus_indexes,
423 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +0000424
cristybb503372010-05-27 20:51:26 +0000425 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000426 i;
427
428 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000429 *restrict p,
430 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000431
432 /*
433 Apply clip mask.
434 */
435 if (image->debug != MagickFalse)
436 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
437 if (image->clip_mask == (Image *) NULL)
438 return(MagickFalse);
439 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
440 if (cache_info == (Cache) NULL)
441 return(MagickFalse);
442 image_nexus=AcquirePixelCacheNexus(1);
443 clip_nexus=AcquirePixelCacheNexus(1);
444 if ((image_nexus == (NexusInfo **) NULL) ||
445 (clip_nexus == (NexusInfo **) NULL))
446 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
447 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,nexus_info->region.y,
448 nexus_info->region.width,nexus_info->region.height,image_nexus[0],
449 exception);
450 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
451 q=nexus_info->pixels;
452 nexus_indexes=nexus_info->indexes;
453 r=GetVirtualPixelsFromNexus(image->clip_mask,MaskVirtualPixelMethod,
454 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
455 nexus_info->region.height,clip_nexus[0],exception);
456 number_pixels=(MagickSizeType) nexus_info->region.width*
457 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +0000458 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000459 {
460 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
461 break;
462 if (PixelIntensityToQuantum(r) > ((Quantum) QuantumRange/2))
463 {
cristyce70c172010-01-07 17:15:30 +0000464 SetRedPixelComponent(q,GetRedPixelComponent(p));
465 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
466 SetBluePixelComponent(q,GetBluePixelComponent(p));
467 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
cristy3ed852e2009-09-05 21:47:34 +0000468 if (cache_info->active_index_channel != MagickFalse)
469 nexus_indexes[i]=indexes[i];
470 }
471 p++;
472 q++;
473 r++;
474 }
475 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
476 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +0000477 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +0000478 return(MagickFalse);
479 return(MagickTrue);
480}
481
482/*
483%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
484% %
485% %
486% %
487+ C l o n e P i x e l C a c h e %
488% %
489% %
490% %
491%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
492%
493% ClonePixelCache() clones a pixel cache.
494%
495% The format of the ClonePixelCache() method is:
496%
497% Cache ClonePixelCache(const Cache cache)
498%
499% A description of each parameter follows:
500%
501% o cache: the pixel cache.
502%
503*/
504MagickExport Cache ClonePixelCache(const Cache cache)
505{
506 CacheInfo
507 *clone_info;
508
509 const CacheInfo
510 *cache_info;
511
512 assert(cache != (const Cache) NULL);
513 cache_info=(const CacheInfo *) cache;
514 assert(cache_info->signature == MagickSignature);
515 if (cache_info->debug != MagickFalse)
516 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
517 cache_info->filename);
518 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
519 if (clone_info == (Cache) NULL)
520 return((Cache) NULL);
521 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
522 return((Cache ) clone_info);
523}
524
525/*
526%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
527% %
528% %
529% %
530+ C l o n e P i x e l C a c h e N e x u s %
531% %
532% %
533% %
534%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
535%
536% ClonePixelCacheNexus() clones the source cache nexus to the destination
537% nexus.
538%
539% The format of the ClonePixelCacheNexus() method is:
540%
541% MagickBooleanType ClonePixelCacheNexus(CacheInfo *destination,
542% CacheInfo *source,ExceptionInfo *exception)
543%
544% A description of each parameter follows:
545%
546% o destination: the destination cache nexus.
547%
548% o source: the source cache nexus.
549%
550% o exception: return any errors or warnings in this structure.
551%
552*/
553
554static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
555 NexusInfo *nexus_info,ExceptionInfo *exception)
556{
557 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
558 return(MagickFalse);
559 nexus_info->mapped=MagickFalse;
560 nexus_info->cache=(PixelPacket *) AcquireMagickMemory((size_t)
561 nexus_info->length);
562 if (nexus_info->cache == (PixelPacket *) NULL)
563 {
564 nexus_info->mapped=MagickTrue;
565 nexus_info->cache=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
566 nexus_info->length);
567 }
568 if (nexus_info->cache == (PixelPacket *) NULL)
569 {
570 (void) ThrowMagickException(exception,GetMagickModule(),
571 ResourceLimitError,"MemoryAllocationFailed","`%s'",
572 cache_info->filename);
573 return(MagickFalse);
574 }
575 return(MagickTrue);
576}
577
578static MagickBooleanType ClonePixelCacheNexus(CacheInfo *destination,
579 CacheInfo *source,ExceptionInfo *exception)
580{
581 MagickBooleanType
582 status;
583
584 MagickSizeType
585 number_pixels;
586
cristybb503372010-05-27 20:51:26 +0000587 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000588 i;
589
590 register const NexusInfo
591 *p;
592
593 register NexusInfo
594 *q;
595
596 status=MagickTrue;
cristybb503372010-05-27 20:51:26 +0000597 for (i=0; i < (ssize_t) source->number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000598 {
599 p=source->nexus_info[i];
600 q=destination->nexus_info[i];
601 q->mapped=p->mapped;
602 q->region=p->region;
603 q->length=p->length;
604 q->cache=p->cache;
605 q->pixels=p->pixels;
606 q->indexes=p->indexes;
607 if (p->cache != (PixelPacket *) NULL)
608 {
609 status=AcquireCacheNexusPixels(source,q,exception);
610 if (status != MagickFalse)
611 {
612 (void) CopyMagickMemory(q->cache,p->cache,(size_t) p->length);
613 q->pixels=q->cache;
614 q->indexes=(IndexPacket *) NULL;
615 number_pixels=(MagickSizeType) q->region.width*q->region.height;
616 if (p->indexes != (IndexPacket *) NULL)
617 q->indexes=(IndexPacket *) (q->pixels+number_pixels);
618 }
619 }
620 }
621 return(status);
622}
623
624/*
625%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
626% %
627% %
628% %
cristy60c44a82009-10-07 00:58:49 +0000629+ 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 +0000630% %
631% %
632% %
633%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
634% ClonePixelCachePixels() clones the source pixel cache to the destination
635% cache.
636%
637% The format of the ClonePixelCachePixels() method is:
638%
639% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
640% CacheInfo *source_info,ExceptionInfo *exception)
641%
642% A description of each parameter follows:
643%
644% o cache_info: the pixel cache.
645%
646% o source_info: the source pixel cache.
647%
648% o exception: return any errors or warnings in this structure.
649%
650*/
651
652static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
653{
654 int
655 status;
656
cristy5ee247a2010-02-12 15:42:34 +0000657 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000658 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000659 if (cache_info->file != -1)
660 status=close(cache_info->file);
cristy3ed852e2009-09-05 21:47:34 +0000661 cache_info->file=(-1);
662 RelinquishMagickResource(FileResource,1);
cristyf84a1932010-01-03 18:00:18 +0000663 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000664 return(status == -1 ? MagickFalse : MagickTrue);
665}
666
667static void LimitPixelCacheDescriptors(void)
668{
669 register CacheInfo
670 *p,
671 *q;
672
673 /*
674 Limit # of open file descriptors.
675 */
676 if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
677 return;
cristyf84a1932010-01-03 18:00:18 +0000678 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000679 if (cache_resources == (SplayTreeInfo *) NULL)
680 {
cristyf84a1932010-01-03 18:00:18 +0000681 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000682 return;
683 }
684 ResetSplayTreeIterator(cache_resources);
685 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
686 while (p != (CacheInfo *) NULL)
687 {
688 if ((p->type == DiskCache) && (p->file != -1))
cristy508d9312010-02-10 21:10:30 +0000689 break;
cristy3ed852e2009-09-05 21:47:34 +0000690 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
691 }
692 for (q=p; p != (CacheInfo *) NULL; )
693 {
694 if ((p->type == DiskCache) && (p->file != -1) &&
695 (p->timestamp < q->timestamp))
cristy508d9312010-02-10 21:10:30 +0000696 q=p;
cristy3ed852e2009-09-05 21:47:34 +0000697 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
698 }
699 if (q != (CacheInfo *) NULL)
cristy9e116922010-02-12 20:58:13 +0000700 {
701 /*
702 Close least recently used cache.
703 */
704 (void) close(q->file);
705 q->file=(-1);
706 }
cristyf84a1932010-01-03 18:00:18 +0000707 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000708}
709
710static inline MagickSizeType MagickMax(const MagickSizeType x,
711 const MagickSizeType y)
712{
713 if (x > y)
714 return(x);
715 return(y);
716}
717
718static inline MagickSizeType MagickMin(const MagickSizeType x,
719 const MagickSizeType y)
720{
721 if (x < y)
722 return(x);
723 return(y);
724}
725
726static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
727 const MapMode mode)
728{
729 int
730 file;
731
732 /*
733 Open pixel cache on disk.
734 */
cristyf84a1932010-01-03 18:00:18 +0000735 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000736 if (cache_info->file != -1)
737 {
cristyf84a1932010-01-03 18:00:18 +0000738 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000739 return(MagickTrue); /* cache already open */
740 }
741 LimitPixelCacheDescriptors();
742 if (*cache_info->cache_filename == '\0')
743 file=AcquireUniqueFileResource(cache_info->cache_filename);
744 else
745 switch (mode)
746 {
747 case ReadMode:
748 {
749 file=open(cache_info->cache_filename,O_RDONLY | O_BINARY);
750 break;
751 }
752 case WriteMode:
753 {
754 file=open(cache_info->cache_filename,O_WRONLY | O_CREAT | O_BINARY |
755 O_EXCL,S_MODE);
756 if (file == -1)
757 file=open(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
758 break;
759 }
760 case IOMode:
761 default:
762 {
763 file=open(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
764 O_EXCL,S_MODE);
765 if (file == -1)
766 file=open(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
767 break;
768 }
769 }
770 if (file == -1)
771 {
cristyf84a1932010-01-03 18:00:18 +0000772 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000773 return(MagickFalse);
774 }
775 (void) AcquireMagickResource(FileResource,1);
776 cache_info->file=file;
777 cache_info->timestamp=time(0);
cristyf84a1932010-01-03 18:00:18 +0000778 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000779 return(MagickTrue);
780}
781
782static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
783 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000784 unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000785{
786 register MagickOffsetType
787 i;
788
789 ssize_t
790 count;
791
cristy08a88202010-03-04 19:18:05 +0000792 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000793#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000794 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000795 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
796 {
cristyf84a1932010-01-03 18:00:18 +0000797 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000798 return((MagickOffsetType) -1);
799 }
800#endif
801 count=0;
802 for (i=0; i < (MagickOffsetType) length; i+=count)
803 {
804#if !defined(MAGICKCORE_HAVE_PREAD)
805 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
806 (MagickSizeType) SSIZE_MAX));
807#else
808 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
809 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
810#endif
811 if (count > 0)
812 continue;
813 count=0;
814 if (errno != EINTR)
815 {
816 i=(-1);
817 break;
818 }
819 }
820#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000821 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000822#endif
823 return(i);
824}
825
826static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
827 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000828 const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000829{
830 register MagickOffsetType
831 i;
832
833 ssize_t
834 count;
835
cristy08a88202010-03-04 19:18:05 +0000836 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000837#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000838 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000839 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
840 {
cristyf84a1932010-01-03 18:00:18 +0000841 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000842 return((MagickOffsetType) -1);
843 }
844#endif
845 count=0;
846 for (i=0; i < (MagickOffsetType) length; i+=count)
847 {
848#if !defined(MAGICKCORE_HAVE_PWRITE)
849 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
850 (MagickSizeType) SSIZE_MAX));
851#else
852 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
853 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
854#endif
855 if (count > 0)
856 continue;
857 count=0;
858 if (errno != EINTR)
859 {
860 i=(-1);
861 break;
862 }
863 }
864#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000865 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000866#endif
867 return(i);
868}
869
870static MagickBooleanType CloneDiskToDiskPixelCache(CacheInfo *clone_info,
871 CacheInfo *cache_info,ExceptionInfo *exception)
872{
873 MagickOffsetType
874 count,
875 offset,
876 source_offset;
877
878 MagickSizeType
879 length;
880
cristybb503372010-05-27 20:51:26 +0000881 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000882 y;
883
884 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000885 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +0000886
cristybb503372010-05-27 20:51:26 +0000887 size_t
cristy3ed852e2009-09-05 21:47:34 +0000888 columns,
889 rows;
890
891 if (cache_info->debug != MagickFalse)
892 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
893 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
894 {
895 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
896 clone_info->cache_filename);
897 return(MagickFalse);
898 }
899 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
900 {
901 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
902 cache_info->cache_filename);
903 return(MagickFalse);
904 }
cristybb503372010-05-27 20:51:26 +0000905 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
906 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +0000907 if ((clone_info->active_index_channel != MagickFalse) &&
908 (cache_info->active_index_channel != MagickFalse))
909 {
910 register IndexPacket
911 *indexes;
912
913 /*
914 Clone cache indexes.
915 */
916 length=MagickMax(clone_info->columns,cache_info->columns)*
917 sizeof(*indexes);
918 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
919 if (indexes == (IndexPacket *) NULL)
920 {
921 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
922 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
923 return(MagickFalse);
924 }
925 (void) ResetMagickMemory(indexes,0,(size_t) length);
926 length=columns*sizeof(*indexes);
927 source_offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
928 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
929 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
930 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +0000931 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000932 {
933 source_offset-=cache_info->columns*sizeof(*indexes);
934 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
935 length,(unsigned char *) indexes);
936 if ((MagickSizeType) count != length)
937 break;
938 offset-=clone_info->columns*sizeof(*indexes);
939 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
940 (unsigned char *) indexes);
941 if ((MagickSizeType) count != length)
942 break;
943 }
cristybb503372010-05-27 20:51:26 +0000944 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000945 {
946 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
947 ThrowFileException(exception,CacheError,"UnableToCloneCache",
948 cache_info->cache_filename);
949 return(MagickFalse);
950 }
951 if (clone_info->columns > cache_info->columns)
952 {
953 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
954 (void) ResetMagickMemory(indexes,0,(size_t) length);
955 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
956 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +0000957 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000958 {
959 offset-=clone_info->columns*sizeof(*indexes);
960 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
961 length,(unsigned char *) indexes);
962 if ((MagickSizeType) count != length)
963 break;
964 }
cristybb503372010-05-27 20:51:26 +0000965 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000966 {
967 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
968 ThrowFileException(exception,CacheError,"UnableToCloneCache",
969 cache_info->cache_filename);
970 return(MagickFalse);
971 }
972 }
973 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
974 }
975 /*
976 Clone cache pixels.
977 */
978 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
979 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
980 if (pixels == (PixelPacket *) NULL)
981 {
982 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
983 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
984 return(MagickFalse);
985 }
986 (void) ResetMagickMemory(pixels,0,(size_t) length);
987 length=columns*sizeof(*pixels);
988 source_offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
989 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +0000990 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000991 {
992 source_offset-=cache_info->columns*sizeof(*pixels);
993 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
994 length,(unsigned char *) pixels);
995 if ((MagickSizeType) count != length)
996 break;
997 offset-=clone_info->columns*sizeof(*pixels);
998 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
999 (unsigned char *) pixels);
1000 if ((MagickSizeType) count != length)
1001 break;
1002 }
cristybb503372010-05-27 20:51:26 +00001003 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001004 {
1005 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1006 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1007 cache_info->cache_filename);
1008 return(MagickFalse);
1009 }
1010 if (clone_info->columns > cache_info->columns)
1011 {
1012 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
1013 sizeof(*pixels);
1014 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1015 (void) ResetMagickMemory(pixels,0,(size_t) length);
cristybb503372010-05-27 20:51:26 +00001016 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001017 {
1018 offset-=clone_info->columns*sizeof(*pixels);
1019 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1020 (unsigned char *) pixels);
1021 if ((MagickSizeType) count != length)
1022 break;
1023 }
cristybb503372010-05-27 20:51:26 +00001024 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001025 {
1026 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1027 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1028 cache_info->cache_filename);
1029 return(MagickFalse);
1030 }
1031 }
1032 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1033 return(MagickTrue);
1034}
1035
1036static MagickBooleanType CloneDiskToMemoryPixelCache(CacheInfo *clone_info,
1037 CacheInfo *cache_info,ExceptionInfo *exception)
1038{
1039 MagickOffsetType
1040 count,
1041 offset;
1042
1043 MagickSizeType
1044 length;
1045
cristybb503372010-05-27 20:51:26 +00001046 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001047 y;
1048
1049 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001050 *restrict pixels,
1051 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00001052
cristybb503372010-05-27 20:51:26 +00001053 size_t
cristy3ed852e2009-09-05 21:47:34 +00001054 columns,
1055 rows;
1056
1057 if (cache_info->debug != MagickFalse)
1058 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
1059 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
1060 {
1061 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1062 cache_info->cache_filename);
1063 return(MagickFalse);
1064 }
cristybb503372010-05-27 20:51:26 +00001065 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1066 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001067 if ((clone_info->active_index_channel != MagickFalse) &&
1068 (cache_info->active_index_channel != MagickFalse))
1069 {
1070 register IndexPacket
1071 *indexes,
1072 *q;
1073
1074 /*
1075 Clone cache indexes.
1076 */
1077 length=MagickMax(clone_info->columns,cache_info->columns)*
1078 sizeof(*indexes);
1079 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1080 if (indexes == (IndexPacket *) NULL)
1081 {
1082 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1083 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1084 return(MagickFalse);
1085 }
1086 (void) ResetMagickMemory(indexes,0,(size_t) length);
1087 length=columns*sizeof(IndexPacket);
1088 offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
1089 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
1090 q=clone_info->indexes+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001091 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001092 {
1093 offset-=cache_info->columns*sizeof(IndexPacket);
1094 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,
1095 length,(unsigned char *) indexes);
1096 if ((MagickSizeType) count != length)
1097 break;
1098 q-=clone_info->columns;
1099 (void) CopyMagickMemory(q,indexes,(size_t) length);
1100 if ((MagickSizeType) count != length)
1101 break;
1102 }
cristybb503372010-05-27 20:51:26 +00001103 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001104 {
1105 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1106 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1107 cache_info->cache_filename);
1108 return(MagickFalse);
1109 }
1110 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1111 }
1112 /*
1113 Clone cache pixels.
1114 */
1115 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1116 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1117 if (pixels == (PixelPacket *) NULL)
1118 {
1119 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1120 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1121 return(MagickFalse);
1122 }
1123 (void) ResetMagickMemory(pixels,0,(size_t) length);
1124 length=columns*sizeof(*pixels);
1125 offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
1126 q=clone_info->pixels+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001127 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001128 {
1129 offset-=cache_info->columns*sizeof(*pixels);
1130 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,length,
1131 (unsigned char *) pixels);
1132 if ((MagickSizeType) count != length)
1133 break;
1134 q-=clone_info->columns;
1135 (void) CopyMagickMemory(q,pixels,(size_t) length);
1136 }
cristybb503372010-05-27 20:51:26 +00001137 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001138 {
1139 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1140 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1141 cache_info->cache_filename);
1142 return(MagickFalse);
1143 }
1144 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1145 return(MagickTrue);
1146}
1147
1148static MagickBooleanType CloneMemoryToDiskPixelCache(CacheInfo *clone_info,
1149 CacheInfo *cache_info,ExceptionInfo *exception)
1150{
1151 MagickOffsetType
1152 count,
1153 offset;
1154
1155 MagickSizeType
1156 length;
1157
cristybb503372010-05-27 20:51:26 +00001158 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001159 y;
1160
1161 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001162 *restrict p,
1163 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +00001164
cristybb503372010-05-27 20:51:26 +00001165 size_t
cristy3ed852e2009-09-05 21:47:34 +00001166 columns,
1167 rows;
1168
1169 if (cache_info->debug != MagickFalse)
1170 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
1171 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
1172 {
1173 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1174 clone_info->cache_filename);
1175 return(MagickFalse);
1176 }
cristybb503372010-05-27 20:51:26 +00001177 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1178 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001179 if ((clone_info->active_index_channel != MagickFalse) &&
1180 (cache_info->active_index_channel != MagickFalse))
1181 {
1182 register IndexPacket
1183 *p,
1184 *indexes;
1185
1186 /*
1187 Clone cache indexes.
1188 */
1189 length=MagickMax(clone_info->columns,cache_info->columns)*
1190 sizeof(*indexes);
1191 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1192 if (indexes == (IndexPacket *) NULL)
1193 {
1194 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1195 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1196 return(MagickFalse);
1197 }
1198 (void) ResetMagickMemory(indexes,0,(size_t) length);
1199 length=columns*sizeof(*indexes);
1200 p=cache_info->indexes+cache_info->columns*rows;
1201 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1202 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +00001203 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001204 {
1205 p-=cache_info->columns;
1206 (void) CopyMagickMemory(indexes,p,(size_t) length);
1207 offset-=clone_info->columns*sizeof(*indexes);
1208 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1209 (unsigned char *) indexes);
1210 if ((MagickSizeType) count != length)
1211 break;
1212 }
cristybb503372010-05-27 20:51:26 +00001213 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001214 {
1215 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1216 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1217 cache_info->cache_filename);
1218 return(MagickFalse);
1219 }
1220 if (clone_info->columns > cache_info->columns)
1221 {
1222 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
1223 (void) ResetMagickMemory(indexes,0,(size_t) length);
1224 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1225 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +00001226 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001227 {
1228 offset-=clone_info->columns*sizeof(*indexes);
1229 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
1230 length,(unsigned char *) indexes);
1231 if ((MagickSizeType) count != length)
1232 break;
1233 }
cristybb503372010-05-27 20:51:26 +00001234 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001235 {
1236 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1237 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1238 cache_info->cache_filename);
1239 return(MagickFalse);
1240 }
1241 }
1242 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1243 }
1244 /*
1245 Clone cache pixels.
1246 */
1247 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1248 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1249 if (pixels == (PixelPacket *) NULL)
1250 {
1251 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1252 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1253 return(MagickFalse);
1254 }
1255 (void) ResetMagickMemory(pixels,0,(size_t) length);
1256 length=columns*sizeof(*pixels);
1257 p=cache_info->pixels+cache_info->columns*rows;
1258 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +00001259 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001260 {
1261 p-=cache_info->columns;
1262 (void) CopyMagickMemory(pixels,p,(size_t) length);
1263 offset-=clone_info->columns*sizeof(*pixels);
1264 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1265 (unsigned char *) pixels);
1266 if ((MagickSizeType) count != length)
1267 break;
1268 }
cristybb503372010-05-27 20:51:26 +00001269 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001270 {
1271 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1272 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1273 cache_info->cache_filename);
1274 return(MagickFalse);
1275 }
1276 if (clone_info->columns > cache_info->columns)
1277 {
1278 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
1279 sizeof(*pixels);
1280 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1281 (void) ResetMagickMemory(pixels,0,(size_t) length);
cristybb503372010-05-27 20:51:26 +00001282 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001283 {
1284 offset-=clone_info->columns*sizeof(*pixels);
1285 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1286 (unsigned char *) pixels);
1287 if ((MagickSizeType) count != length)
1288 break;
1289 }
cristybb503372010-05-27 20:51:26 +00001290 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001291 {
1292 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1293 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1294 cache_info->cache_filename);
1295 return(MagickFalse);
1296 }
1297 }
1298 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1299 return(MagickTrue);
1300}
1301
1302static MagickBooleanType CloneMemoryToMemoryPixelCache(CacheInfo *clone_info,
1303 CacheInfo *cache_info,ExceptionInfo *magick_unused(exception))
1304{
cristybb503372010-05-27 20:51:26 +00001305 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001306 y;
1307
1308 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001309 *restrict pixels,
1310 *restrict source_pixels;
cristy3ed852e2009-09-05 21:47:34 +00001311
1312 size_t
1313 length;
1314
cristybb503372010-05-27 20:51:26 +00001315 size_t
cristy3ed852e2009-09-05 21:47:34 +00001316 columns,
1317 rows;
1318
1319 if (cache_info->debug != MagickFalse)
1320 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
cristybb503372010-05-27 20:51:26 +00001321 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1322 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001323 if ((clone_info->active_index_channel != MagickFalse) &&
1324 (cache_info->active_index_channel != MagickFalse))
1325 {
1326 register IndexPacket
1327 *indexes,
1328 *source_indexes;
1329
1330 /*
1331 Clone cache indexes.
1332 */
1333 length=columns*sizeof(*indexes);
1334 if (clone_info->columns == cache_info->columns)
1335 (void) CopyMagickMemory(clone_info->indexes,cache_info->indexes,
1336 length*rows);
1337 else
1338 {
1339 source_indexes=cache_info->indexes+cache_info->columns*rows;
1340 indexes=clone_info->indexes+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001341 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001342 {
1343 source_indexes-=cache_info->columns;
1344 indexes-=clone_info->columns;
1345 (void) CopyMagickMemory(indexes,source_indexes,length);
1346 }
1347 if (clone_info->columns > cache_info->columns)
1348 {
1349 length=(clone_info->columns-cache_info->columns)*
1350 sizeof(*indexes);
1351 indexes=clone_info->indexes+clone_info->columns*rows+
1352 cache_info->columns;
cristybb503372010-05-27 20:51:26 +00001353 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001354 {
1355 indexes-=clone_info->columns;
1356 (void) ResetMagickMemory(indexes,0,length);
1357 }
1358 }
1359 }
1360 }
1361 /*
1362 Clone cache pixels.
1363 */
1364 length=columns*sizeof(*pixels);
1365 if (clone_info->columns == cache_info->columns)
1366 (void) CopyMagickMemory(clone_info->pixels,cache_info->pixels,length*rows);
1367 else
1368 {
1369 source_pixels=cache_info->pixels+cache_info->columns*rows;
1370 pixels=clone_info->pixels+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001371 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001372 {
1373 source_pixels-=cache_info->columns;
1374 pixels-=clone_info->columns;
1375 (void) CopyMagickMemory(pixels,source_pixels,length);
1376 }
1377 if (clone_info->columns > cache_info->columns)
1378 {
1379 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1380 pixels=clone_info->pixels+clone_info->columns*rows+
1381 cache_info->columns;
cristybb503372010-05-27 20:51:26 +00001382 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001383 {
1384 pixels-=clone_info->columns;
1385 (void) ResetMagickMemory(pixels,0,length);
1386 }
1387 }
1388 }
1389 return(MagickTrue);
1390}
1391
1392static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1393 CacheInfo *cache_info,ExceptionInfo *exception)
1394{
1395 if ((clone_info->type != DiskCache) && (cache_info->type != DiskCache))
1396 return(CloneMemoryToMemoryPixelCache(clone_info,cache_info,exception));
1397 if ((clone_info->type == DiskCache) && (cache_info->type == DiskCache))
1398 return(CloneDiskToDiskPixelCache(clone_info,cache_info,exception));
1399 if (cache_info->type == DiskCache)
1400 return(CloneDiskToMemoryPixelCache(clone_info,cache_info,exception));
1401 return(CloneMemoryToDiskPixelCache(clone_info,cache_info,exception));
1402}
1403
1404/*
1405%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1406% %
1407% %
1408% %
1409+ C l o n e P i x e l C a c h e M e t h o d s %
1410% %
1411% %
1412% %
1413%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1414%
1415% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1416% another.
1417%
1418% The format of the ClonePixelCacheMethods() method is:
1419%
1420% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1421%
1422% A description of each parameter follows:
1423%
1424% o clone: Specifies a pointer to a Cache structure.
1425%
1426% o cache: the pixel cache.
1427%
1428*/
1429MagickExport void ClonePixelCacheMethods(Cache clone,const Cache cache)
1430{
1431 CacheInfo
1432 *cache_info,
1433 *source_info;
1434
1435 assert(clone != (Cache) NULL);
1436 source_info=(CacheInfo *) clone;
1437 assert(source_info->signature == MagickSignature);
1438 if (source_info->debug != MagickFalse)
1439 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1440 source_info->filename);
1441 assert(cache != (Cache) NULL);
1442 cache_info=(CacheInfo *) cache;
1443 assert(cache_info->signature == MagickSignature);
1444 source_info->methods=cache_info->methods;
1445}
1446
1447/*
1448%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1449% %
1450% %
1451% %
1452+ D e s t r o y I m a g e P i x e l C a c h e %
1453% %
1454% %
1455% %
1456%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1457%
1458% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1459%
1460% The format of the DestroyImagePixelCache() method is:
1461%
1462% void DestroyImagePixelCache(Image *image)
1463%
1464% A description of each parameter follows:
1465%
1466% o image: the image.
1467%
1468*/
1469static void DestroyImagePixelCache(Image *image)
1470{
1471 assert(image != (Image *) NULL);
1472 assert(image->signature == MagickSignature);
1473 if (image->debug != MagickFalse)
1474 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1475 if (image->cache == (void *) NULL)
1476 return;
1477 image->cache=DestroyPixelCache(image->cache);
1478}
1479
1480/*
1481%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1482% %
1483% %
1484% %
1485+ D e s t r o y I m a g e P i x e l s %
1486% %
1487% %
1488% %
1489%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1490%
1491% DestroyImagePixels() deallocates memory associated with the pixel cache.
1492%
1493% The format of the DestroyImagePixels() method is:
1494%
1495% void DestroyImagePixels(Image *image)
1496%
1497% A description of each parameter follows:
1498%
1499% o image: the image.
1500%
1501*/
1502MagickExport void DestroyImagePixels(Image *image)
1503{
1504 CacheInfo
1505 *cache_info;
1506
1507 assert(image != (const Image *) NULL);
1508 assert(image->signature == MagickSignature);
1509 if (image->debug != MagickFalse)
1510 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1511 assert(image->cache != (Cache) NULL);
1512 cache_info=(CacheInfo *) image->cache;
1513 assert(cache_info->signature == MagickSignature);
1514 if (cache_info->methods.destroy_pixel_handler == (DestroyPixelHandler) NULL)
1515 return;
1516 cache_info->methods.destroy_pixel_handler(image);
1517}
1518
1519/*
1520%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1521% %
1522% %
1523% %
1524+ D e s t r o y P i x e l C a c h e %
1525% %
1526% %
1527% %
1528%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1529%
1530% DestroyPixelCache() deallocates memory associated with the pixel cache.
1531%
1532% The format of the DestroyPixelCache() method is:
1533%
1534% Cache DestroyPixelCache(Cache cache)
1535%
1536% A description of each parameter follows:
1537%
1538% o cache: the pixel cache.
1539%
1540*/
1541
1542static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1543{
1544 switch (cache_info->type)
1545 {
1546 case MemoryCache:
1547 {
1548 if (cache_info->mapped == MagickFalse)
1549 cache_info->pixels=(PixelPacket *) RelinquishMagickMemory(
1550 cache_info->pixels);
1551 else
1552 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,
1553 (size_t) cache_info->length);
1554 RelinquishMagickResource(MemoryResource,cache_info->length);
1555 break;
1556 }
1557 case MapCache:
1558 {
1559 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,(size_t)
1560 cache_info->length);
1561 RelinquishMagickResource(MapResource,cache_info->length);
1562 }
1563 case DiskCache:
1564 {
1565 if (cache_info->file != -1)
1566 (void) ClosePixelCacheOnDisk(cache_info);
1567 RelinquishMagickResource(DiskResource,cache_info->length);
1568 break;
1569 }
1570 default:
1571 break;
1572 }
1573 cache_info->type=UndefinedCache;
1574 cache_info->mapped=MagickFalse;
1575 cache_info->indexes=(IndexPacket *) NULL;
1576}
1577
1578MagickExport Cache DestroyPixelCache(Cache cache)
1579{
1580 CacheInfo
1581 *cache_info;
1582
cristy3ed852e2009-09-05 21:47:34 +00001583 assert(cache != (Cache) NULL);
1584 cache_info=(CacheInfo *) cache;
1585 assert(cache_info->signature == MagickSignature);
1586 if (cache_info->debug != MagickFalse)
1587 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1588 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001589 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001590 cache_info->reference_count--;
1591 if (cache_info->reference_count != 0)
1592 {
cristyf84a1932010-01-03 18:00:18 +00001593 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001594 return((Cache) NULL);
1595 }
cristyf84a1932010-01-03 18:00:18 +00001596 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001597 if (cache_resources != (SplayTreeInfo *) NULL)
1598 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
cristy5b8de732009-09-10 23:50:40 +00001599 if (cache_info->debug != MagickFalse)
1600 {
1601 char
1602 message[MaxTextExtent];
1603
1604 (void) FormatMagickString(message,MaxTextExtent,"destroy %s",
1605 cache_info->filename);
1606 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1607 }
cristyc2e1bdd2009-09-10 23:43:34 +00001608 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1609 (cache_info->type != DiskCache)))
1610 RelinquishPixelCachePixels(cache_info);
1611 else
1612 {
1613 RelinquishPixelCachePixels(cache_info);
1614 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1615 }
cristy3ed852e2009-09-05 21:47:34 +00001616 *cache_info->cache_filename='\0';
1617 if (cache_info->nexus_info != (NexusInfo **) NULL)
1618 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1619 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001620 if (cache_info->random_info != (RandomInfo *) NULL)
1621 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001622 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1623 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1624 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1625 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001626 cache_info->signature=(~MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001627 cache_info=(CacheInfo *) RelinquishAlignedMemory(cache_info);
1628 cache=(Cache) NULL;
1629 return(cache);
1630}
1631
1632/*
1633%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1634% %
1635% %
1636% %
1637+ D e s t r o y P i x e l C a c h e N e x u s %
1638% %
1639% %
1640% %
1641%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1642%
1643% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1644%
1645% The format of the DestroyPixelCacheNexus() method is:
1646%
1647% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001648% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001649%
1650% A description of each parameter follows:
1651%
1652% o nexus_info: the nexus to destroy.
1653%
1654% o number_threads: the number of nexus threads.
1655%
1656*/
1657
1658static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1659{
1660 if (nexus_info->mapped == MagickFalse)
1661 (void) RelinquishMagickMemory(nexus_info->cache);
1662 else
1663 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1664 nexus_info->cache=(PixelPacket *) NULL;
1665 nexus_info->pixels=(PixelPacket *) NULL;
1666 nexus_info->indexes=(IndexPacket *) NULL;
1667 nexus_info->length=0;
1668 nexus_info->mapped=MagickFalse;
1669}
1670
1671MagickExport NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001672 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001673{
cristybb503372010-05-27 20:51:26 +00001674 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001675 i;
1676
1677 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001678 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001679 {
1680 if (nexus_info[i]->cache != (PixelPacket *) NULL)
1681 RelinquishCacheNexusPixels(nexus_info[i]);
1682 nexus_info[i]->signature=(~MagickSignature);
1683 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
1684 }
1685 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
1686 return(nexus_info);
1687}
1688
1689/*
1690%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1691% %
1692% %
1693% %
cristy3ed852e2009-09-05 21:47:34 +00001694+ 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 %
1695% %
1696% %
1697% %
1698%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1699%
1700% GetAuthenticIndexesFromCache() returns the indexes associated with the last
1701% call to QueueAuthenticPixelsCache() or GetAuthenticPixelsCache().
1702%
1703% The format of the GetAuthenticIndexesFromCache() method is:
1704%
1705% IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1706%
1707% A description of each parameter follows:
1708%
1709% o image: the image.
1710%
1711*/
1712static IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1713{
1714 CacheInfo
1715 *cache_info;
1716
1717 IndexPacket
1718 *indexes;
1719
cristybb503372010-05-27 20:51:26 +00001720 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001721 id;
1722
1723 if (image->debug != MagickFalse)
1724 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1725 cache_info=(CacheInfo *) image->cache;
1726 id=GetOpenMPThreadId();
cristybb503372010-05-27 20:51:26 +00001727 assert(id < (ssize_t) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001728 indexes=GetPixelCacheNexusIndexes(image->cache,cache_info->nexus_info[id]);
1729 return(indexes);
1730}
1731
1732/*
1733%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1734% %
1735% %
1736% %
1737% G e t A u t h e n t i c I n d e x Q u e u e %
1738% %
1739% %
1740% %
1741%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1742%
1743% GetAuthenticIndexQueue() returns the authentic black channel or the colormap
1744% indexes associated with the last call to QueueAuthenticPixels() or
1745% GetVirtualPixels(). NULL is returned if the black channel or colormap
1746% indexes are not available.
1747%
1748% The format of the GetAuthenticIndexQueue() method is:
1749%
1750% IndexPacket *GetAuthenticIndexQueue(const Image *image)
1751%
1752% A description of each parameter follows:
1753%
1754% o image: the image.
1755%
1756*/
1757MagickExport IndexPacket *GetAuthenticIndexQueue(const Image *image)
1758{
1759 CacheInfo
1760 *cache_info;
1761
1762 assert(image != (const Image *) NULL);
1763 assert(image->signature == MagickSignature);
1764 if (image->debug != MagickFalse)
1765 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1766 assert(image->cache != (Cache) NULL);
1767 cache_info=(CacheInfo *) image->cache;
1768 assert(cache_info->signature == MagickSignature);
1769 if (cache_info->methods.get_authentic_indexes_from_handler ==
1770 (GetAuthenticIndexesFromHandler) NULL)
1771 return((IndexPacket *) NULL);
1772 return(cache_info->methods.get_authentic_indexes_from_handler(image));
1773}
1774
1775/*
1776%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1777% %
1778% %
1779% %
1780+ 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 %
1781% %
1782% %
1783% %
1784%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1785%
1786% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1787% disk pixel cache as defined by the geometry parameters. A pointer to the
1788% pixels is returned if the pixels are transferred, otherwise a NULL is
1789% returned.
1790%
1791% The format of the GetAuthenticPixelCacheNexus() method is:
1792%
cristybb503372010-05-27 20:51:26 +00001793% PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1794% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001795% NexusInfo *nexus_info,ExceptionInfo *exception)
1796%
1797% A description of each parameter follows:
1798%
1799% o image: the image.
1800%
1801% o x,y,columns,rows: These values define the perimeter of a region of
1802% pixels.
1803%
1804% o nexus_info: the cache nexus to return.
1805%
1806% o exception: return any errors or warnings in this structure.
1807%
1808*/
1809
1810static inline MagickBooleanType IsNexusInCore(const CacheInfo *cache_info,
1811 NexusInfo *nexus_info)
1812{
1813 MagickOffsetType
1814 offset;
1815
cristy73724512010-04-12 14:43:14 +00001816 if (cache_info->type == PingCache)
1817 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001818 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1819 nexus_info->region.x;
1820 if (nexus_info->pixels != (cache_info->pixels+offset))
1821 return(MagickFalse);
1822 return(MagickTrue);
1823}
1824
cristybb503372010-05-27 20:51:26 +00001825MagickExport PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1826 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001827 NexusInfo *nexus_info,ExceptionInfo *exception)
1828{
1829 CacheInfo
1830 *cache_info;
1831
1832 PixelPacket
1833 *pixels;
1834
1835 /*
1836 Transfer pixels from the cache.
1837 */
1838 assert(image != (Image *) NULL);
1839 assert(image->signature == MagickSignature);
1840 if (image->debug != MagickFalse)
1841 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1842 pixels=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
1843 if (pixels == (PixelPacket *) NULL)
1844 return((PixelPacket *) NULL);
1845 cache_info=(CacheInfo *) image->cache;
1846 assert(cache_info->signature == MagickSignature);
1847 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
1848 return(pixels);
1849 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1850 return((PixelPacket *) NULL);
1851 if (cache_info->active_index_channel != MagickFalse)
1852 if (ReadPixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse)
1853 return((PixelPacket *) NULL);
1854 return(pixels);
1855}
1856
1857/*
1858%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1859% %
1860% %
1861% %
1862+ 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 %
1863% %
1864% %
1865% %
1866%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1867%
1868% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1869% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1870%
1871% The format of the GetAuthenticPixelsFromCache() method is:
1872%
1873% PixelPacket *GetAuthenticPixelsFromCache(const Image image)
1874%
1875% A description of each parameter follows:
1876%
1877% o image: the image.
1878%
1879*/
1880static PixelPacket *GetAuthenticPixelsFromCache(const Image *image)
1881{
1882 CacheInfo
1883 *cache_info;
1884
cristybb503372010-05-27 20:51:26 +00001885 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001886 id;
1887
1888 PixelPacket
1889 *pixels;
1890
1891 if (image->debug != MagickFalse)
1892 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1893 cache_info=(CacheInfo *) image->cache;
1894 id=GetOpenMPThreadId();
cristybb503372010-05-27 20:51:26 +00001895 assert(id < (ssize_t) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001896 pixels=GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]);
1897 return(pixels);
1898}
1899
1900/*
1901%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1902% %
1903% %
1904% %
1905% G e t A u t h e n t i c P i x e l Q u e u e %
1906% %
1907% %
1908% %
1909%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1910%
1911% GetAuthenticPixelQueue() returns the authentic pixels associated with the
1912% last call to QueueAuthenticPixels() or GetAuthenticPixels().
1913%
1914% The format of the GetAuthenticPixelQueue() method is:
1915%
1916% PixelPacket *GetAuthenticPixelQueue(const Image image)
1917%
1918% A description of each parameter follows:
1919%
1920% o image: the image.
1921%
1922*/
1923MagickExport PixelPacket *GetAuthenticPixelQueue(const Image *image)
1924{
1925 CacheInfo
1926 *cache_info;
1927
1928 assert(image != (const Image *) NULL);
1929 assert(image->signature == MagickSignature);
1930 if (image->debug != MagickFalse)
1931 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1932 assert(image->cache != (Cache) NULL);
1933 cache_info=(CacheInfo *) image->cache;
1934 assert(cache_info->signature == MagickSignature);
1935 if (cache_info->methods.get_authentic_pixels_from_handler ==
1936 (GetAuthenticPixelsFromHandler) NULL)
1937 return((PixelPacket *) NULL);
1938 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1939}
1940
1941/*
1942%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1943% %
1944% %
1945% %
1946% G e t A u t h e n t i c P i x e l s %
1947% %
1948% %
1949% %
1950%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1951%
1952% GetAuthenticPixels() obtains a pixel region for read/write access. If the
1953% region is successfully accessed, a pointer to a PixelPacket array
1954% representing the region is returned, otherwise NULL is returned.
1955%
1956% The returned pointer may point to a temporary working copy of the pixels
1957% or it may point to the original pixels in memory. Performance is maximized
1958% if the selected region is part of one row, or one or more full rows, since
1959% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001960% if the image is in memory, or in a memory-mapped file. The returned pointer
1961% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001962%
1963% Pixels accessed via the returned pointer represent a simple array of type
1964% PixelPacket. If the image type is CMYK or if the storage class is
1965% PseduoClass, call GetAuthenticIndexQueue() after invoking
1966% GetAuthenticPixels() to obtain the black color component or colormap indexes
1967% (of type IndexPacket) corresponding to the region. Once the PixelPacket
1968% (and/or IndexPacket) array has been updated, the changes must be saved back
1969% to the underlying image using SyncAuthenticPixels() or they may be lost.
1970%
1971% The format of the GetAuthenticPixels() method is:
1972%
cristy5f959472010-05-27 22:19:46 +00001973% PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1974% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001975% ExceptionInfo *exception)
1976%
1977% A description of each parameter follows:
1978%
1979% o image: the image.
1980%
1981% o x,y,columns,rows: These values define the perimeter of a region of
1982% pixels.
1983%
1984% o exception: return any errors or warnings in this structure.
1985%
1986*/
cristybb503372010-05-27 20:51:26 +00001987MagickExport PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1988 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001989 ExceptionInfo *exception)
1990{
1991 CacheInfo
1992 *cache_info;
1993
1994 PixelPacket
1995 *pixels;
1996
1997 assert(image != (Image *) NULL);
1998 assert(image->signature == MagickSignature);
1999 if (image->debug != MagickFalse)
2000 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2001 assert(image->cache != (Cache) NULL);
2002 cache_info=(CacheInfo *) image->cache;
2003 assert(cache_info->signature == MagickSignature);
2004 if (cache_info->methods.get_authentic_pixels_handler ==
2005 (GetAuthenticPixelsHandler) NULL)
2006 return((PixelPacket *) NULL);
2007 pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
2008 rows,exception);
2009 return(pixels);
2010}
2011
2012/*
2013%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2014% %
2015% %
2016% %
2017+ G e t A u t h e n t i c P i x e l s C a c h e %
2018% %
2019% %
2020% %
2021%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2022%
2023% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
2024% as defined by the geometry parameters. A pointer to the pixels is returned
2025% if the pixels are transferred, otherwise a NULL is returned.
2026%
2027% The format of the GetAuthenticPixelsCache() method is:
2028%
cristybb503372010-05-27 20:51:26 +00002029% PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
2030% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00002031% ExceptionInfo *exception)
2032%
2033% A description of each parameter follows:
2034%
2035% o image: the image.
2036%
2037% o x,y,columns,rows: These values define the perimeter of a region of
2038% pixels.
2039%
2040% o exception: return any errors or warnings in this structure.
2041%
2042*/
cristybb503372010-05-27 20:51:26 +00002043static PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
2044 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00002045 ExceptionInfo *exception)
2046{
2047 CacheInfo
2048 *cache_info;
2049
cristybb503372010-05-27 20:51:26 +00002050 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002051 id;
2052
2053 PixelPacket
2054 *pixels;
2055
2056 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
2057 if (cache_info == (Cache) NULL)
2058 return((PixelPacket *) NULL);
2059 id=GetOpenMPThreadId();
cristybb503372010-05-27 20:51:26 +00002060 assert(id < (ssize_t) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00002061 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
2062 cache_info->nexus_info[id],exception);
2063 return(pixels);
2064}
2065
2066/*
2067%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2068% %
2069% %
2070% %
2071+ G e t I m a g e E x t e n t %
2072% %
2073% %
2074% %
2075%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2076%
2077% GetImageExtent() returns the extent of the pixels associated with the
2078% last call to QueueAuthenticPixels() or GetAuthenticPixels().
2079%
2080% The format of the GetImageExtent() method is:
2081%
2082% MagickSizeType GetImageExtent(const Image *image)
2083%
2084% A description of each parameter follows:
2085%
2086% o image: the image.
2087%
2088*/
2089MagickExport MagickSizeType GetImageExtent(const Image *image)
2090{
2091 CacheInfo
2092 *cache_info;
2093
cristybb503372010-05-27 20:51:26 +00002094 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002095 id;
2096
2097 MagickSizeType
2098 extent;
2099
2100 assert(image != (Image *) NULL);
2101 assert(image->signature == MagickSignature);
2102 if (image->debug != MagickFalse)
2103 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2104 assert(image->cache != (Cache) NULL);
2105 cache_info=(CacheInfo *) image->cache;
2106 assert(cache_info->signature == MagickSignature);
2107 id=GetOpenMPThreadId();
cristybb503372010-05-27 20:51:26 +00002108 assert(id < (ssize_t) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00002109 extent=GetPixelCacheNexusExtent(image->cache,cache_info->nexus_info[id]);
2110 return(extent);
2111}
2112
2113/*
2114%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2115% %
2116% %
2117% %
2118+ G e t I m a g e P i x e l C a c h e %
2119% %
2120% %
2121% %
2122%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2123%
2124% GetImagePixelCache() ensures that there is only a single reference to the
2125% pixel cache to be modified, updating the provided cache pointer to point to
2126% a clone of the original pixel cache if necessary.
2127%
2128% The format of the GetImagePixelCache method is:
2129%
2130% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2131% ExceptionInfo *exception)
2132%
2133% A description of each parameter follows:
2134%
2135% o image: the image.
2136%
2137% o clone: any value other than MagickFalse clones the cache pixels.
2138%
2139% o exception: return any errors or warnings in this structure.
2140%
2141*/
2142
2143static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
2144{
2145 CacheInfo
2146 *cache_info;
2147
2148 /*
2149 Does the image match the pixel cache morphology?
2150 */
2151 cache_info=(CacheInfo *) image->cache;
2152 if ((image->storage_class != cache_info->storage_class) ||
2153 (image->colorspace != cache_info->colorspace) ||
2154 (image->columns != cache_info->columns) ||
2155 (image->rows != cache_info->rows) ||
2156 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2157 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2158 return(MagickFalse);
2159 return(MagickTrue);
2160}
2161
2162MagickExport Cache GetImagePixelCache(Image *image,
2163 const MagickBooleanType clone,ExceptionInfo *exception)
2164{
2165 CacheInfo
2166 *cache_info;
2167
cristy3ed852e2009-09-05 21:47:34 +00002168 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00002169 destroy,
cristy3ed852e2009-09-05 21:47:34 +00002170 status;
2171
cristy50a10922010-02-15 18:35:25 +00002172 static MagickSizeType
2173 time_limit = 0;
2174
cristy1ea34962010-07-01 19:49:21 +00002175 static time_t
2176 cache_timer = 0;
2177
cristy3ed852e2009-09-05 21:47:34 +00002178 if (image->debug != MagickFalse)
2179 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristyc4f9f132010-03-04 18:50:01 +00002180 status=MagickTrue;
2181 LockSemaphoreInfo(image->semaphore);
cristy1ea34962010-07-01 19:49:21 +00002182 if (time_limit == 0)
2183 {
2184 time_limit=GetMagickResourceLimit(TimeResource);
2185 cache_timer=time((time_t *) NULL);
2186 }
2187 if ((time_limit != MagickResourceInfinity) &&
2188 ((MagickSizeType) (time((time_t *) NULL)-cache_timer) >= time_limit))
2189 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00002190 assert(image->cache != (Cache) NULL);
2191 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002192 destroy=MagickFalse;
cristy01b7eb02009-09-10 23:10:14 +00002193 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002194 {
cristyaaa0cb62010-02-15 17:47:27 +00002195 LockSemaphoreInfo(cache_info->semaphore);
2196 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002197 {
cristyaaa0cb62010-02-15 17:47:27 +00002198 Image
2199 clone_image;
2200
2201 CacheInfo
2202 *clone_info;
2203
2204 /*
2205 Clone pixel cache.
2206 */
2207 clone_image=(*image);
2208 clone_image.cache=ClonePixelCache(cache_info);
2209 clone_info=(CacheInfo *) clone_image.cache;
2210 status=ClonePixelCacheNexus(cache_info,clone_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002211 if (status != MagickFalse)
2212 {
cristyaaa0cb62010-02-15 17:47:27 +00002213 status=OpenPixelCache(&clone_image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00002214 if (status != MagickFalse)
2215 {
cristyaaa0cb62010-02-15 17:47:27 +00002216 if (clone != MagickFalse)
2217 status=ClonePixelCachePixels(clone_info,cache_info,
2218 exception);
2219 if (status != MagickFalse)
2220 {
2221 destroy=MagickTrue;
2222 image->cache=clone_image.cache;
2223 }
cristy3ed852e2009-09-05 21:47:34 +00002224 }
2225 }
2226 }
cristyaaa0cb62010-02-15 17:47:27 +00002227 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002228 }
cristy4320e0e2009-09-10 15:00:08 +00002229 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002230 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002231 if (status != MagickFalse)
2232 {
2233 /*
2234 Ensure the image matches the pixel cache morphology.
2235 */
2236 image->taint=MagickTrue;
2237 image->type=UndefinedType;
cristydd438462010-05-06 13:44:04 +00002238 if (image->colorspace == GRAYColorspace)
2239 image->colorspace=RGBColorspace;
cristy3ed852e2009-09-05 21:47:34 +00002240 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2241 status=OpenPixelCache(image,IOMode,exception);
2242 }
cristyf84a1932010-01-03 18:00:18 +00002243 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002244 if (status == MagickFalse)
2245 return((Cache) NULL);
2246 return(image->cache);
2247}
2248
2249/*
2250%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2251% %
2252% %
2253% %
2254% G e t O n e A u t h e n t i c P i x e l %
2255% %
2256% %
2257% %
2258%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2259%
2260% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2261% location. The image background color is returned if an error occurs.
2262%
2263% The format of the GetOneAuthenticPixel() method is:
2264%
cristybb503372010-05-27 20:51:26 +00002265% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2266% const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002267%
2268% A description of each parameter follows:
2269%
2270% o image: the image.
2271%
2272% o x,y: These values define the location of the pixel to return.
2273%
2274% o pixel: return a pixel at the specified (x,y) location.
2275%
2276% o exception: return any errors or warnings in this structure.
2277%
2278*/
cristyacbbb7c2010-06-30 18:56:48 +00002279MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2280 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002281{
2282 CacheInfo
2283 *cache_info;
2284
2285 GetOneAuthenticPixelFromHandler
2286 get_one_authentic_pixel_from_handler;
2287
2288 MagickBooleanType
2289 status;
2290
2291 assert(image != (Image *) NULL);
2292 assert(image->signature == MagickSignature);
2293 if (image->debug != MagickFalse)
2294 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2295 assert(image->cache != (Cache) NULL);
2296 cache_info=(CacheInfo *) image->cache;
2297 assert(cache_info->signature == MagickSignature);
2298 *pixel=image->background_color;
2299 get_one_authentic_pixel_from_handler=
2300 cache_info->methods.get_one_authentic_pixel_from_handler;
2301 if (get_one_authentic_pixel_from_handler ==
2302 (GetOneAuthenticPixelFromHandler) NULL)
2303 return(MagickFalse);
2304 status=cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2305 pixel,exception);
2306 return(status);
2307}
2308
2309/*
2310%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2311% %
2312% %
2313% %
2314+ 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 %
2315% %
2316% %
2317% %
2318%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2319%
2320% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2321% location. The image background color is returned if an error occurs.
2322%
2323% The format of the GetOneAuthenticPixelFromCache() method is:
2324%
2325% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy5f959472010-05-27 22:19:46 +00002326% const ssize_t x,const ssize_t y,PixelPacket *pixel,
2327% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002328%
2329% A description of each parameter follows:
2330%
2331% o image: the image.
2332%
2333% o x,y: These values define the location of the pixel to return.
2334%
2335% o pixel: return a pixel at the specified (x,y) location.
2336%
2337% o exception: return any errors or warnings in this structure.
2338%
2339*/
2340static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristybb503372010-05-27 20:51:26 +00002341 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002342{
2343 PixelPacket
2344 *pixels;
2345
2346 if (image->debug != MagickFalse)
2347 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2348 *pixel=image->background_color;
2349 pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2350 if (pixels == (PixelPacket *) NULL)
2351 return(MagickFalse);
2352 *pixel=(*pixels);
2353 return(MagickTrue);
2354}
2355
2356/*
2357%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2358% %
2359% %
2360% %
2361% G e t O n e V i r t u a l M a g i c k P i x e l %
2362% %
2363% %
2364% %
2365%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2366%
2367% GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2368% location. The image background color is returned if an error occurs. If
2369% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2370%
2371% The format of the GetOneVirtualMagickPixel() method is:
2372%
2373% MagickBooleanType GetOneVirtualMagickPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002374% const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
cristy3ed852e2009-09-05 21:47:34 +00002375% ExceptionInfo exception)
2376%
2377% A description of each parameter follows:
2378%
2379% o image: the image.
2380%
2381% o x,y: these values define the location of the pixel to return.
2382%
2383% o pixel: return a pixel at the specified (x,y) location.
2384%
2385% o exception: return any errors or warnings in this structure.
2386%
2387*/
2388MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
cristyacbbb7c2010-06-30 18:56:48 +00002389 const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
2390 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002391{
2392 CacheInfo
2393 *cache_info;
2394
2395 register const IndexPacket
2396 *indexes;
2397
2398 register const PixelPacket
2399 *p;
2400
2401 assert(image != (const Image *) NULL);
2402 assert(image->signature == MagickSignature);
2403 assert(image->cache != (Cache) NULL);
2404 cache_info=(CacheInfo *) image->cache;
2405 assert(cache_info->signature == MagickSignature);
2406 GetMagickPixelPacket(image,pixel);
2407 p=GetVirtualPixelCache(image,GetPixelCacheVirtualMethod(image),x,y,1,1,
2408 exception);
2409 if (p == (const PixelPacket *) NULL)
2410 return(MagickFalse);
2411 indexes=GetVirtualIndexQueue(image);
2412 SetMagickPixelPacket(image,p,indexes,pixel);
2413 return(MagickTrue);
2414}
2415
2416/*
2417%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2418% %
2419% %
2420% %
2421% G e t O n e V i r t u a l M e t h o d P i x e l %
2422% %
2423% %
2424% %
2425%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2426%
2427% GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2428% location as defined by specified pixel method. The image background color
2429% is returned if an error occurs. If you plan to modify the pixel, use
2430% GetOneAuthenticPixel() instead.
2431%
2432% The format of the GetOneVirtualMethodPixel() method is:
2433%
2434% MagickBooleanType GetOneVirtualMethodPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002435% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2436% const ssize_t y,Pixelpacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002437%
2438% A description of each parameter follows:
2439%
2440% o image: the image.
2441%
2442% o virtual_pixel_method: the virtual pixel method.
2443%
2444% o x,y: These values define the location of the pixel to return.
2445%
2446% o pixel: return a pixel at the specified (x,y) location.
2447%
2448% o exception: return any errors or warnings in this structure.
2449%
2450*/
2451MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002452 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002453 PixelPacket *pixel,ExceptionInfo *exception)
2454{
2455 GetOneVirtualPixelFromHandler
2456 get_one_virtual_pixel_from_handler;
2457
2458 CacheInfo
2459 *cache_info;
2460
2461 MagickBooleanType
2462 status;
2463
2464 assert(image != (const Image *) NULL);
2465 assert(image->signature == MagickSignature);
2466 assert(image->cache != (Cache) NULL);
2467 cache_info=(CacheInfo *) image->cache;
2468 assert(cache_info->signature == MagickSignature);
2469 *pixel=image->background_color;
2470 get_one_virtual_pixel_from_handler=
2471 cache_info->methods.get_one_virtual_pixel_from_handler;
2472 if (get_one_virtual_pixel_from_handler ==
2473 (GetOneVirtualPixelFromHandler) NULL)
2474 return(MagickFalse);
2475 status=get_one_virtual_pixel_from_handler(image,virtual_pixel_method,x,y,
2476 pixel,exception);
2477 return(status);
2478}
2479
2480/*
2481%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2482% %
2483% %
2484% %
2485% G e t O n e V i r t u a l P i x e l %
2486% %
2487% %
2488% %
2489%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2490%
2491% GetOneVirtualPixel() returns a single virtual pixel at the specified
2492% (x,y) location. The image background color is returned if an error occurs.
2493% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2494%
2495% The format of the GetOneVirtualPixel() method is:
2496%
cristybb503372010-05-27 20:51:26 +00002497% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2498% const ssize_t y,PixelPacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002499%
2500% A description of each parameter follows:
2501%
2502% o image: the image.
2503%
2504% o x,y: These values define the location of the pixel to return.
2505%
2506% o pixel: return a pixel at the specified (x,y) location.
2507%
2508% o exception: return any errors or warnings in this structure.
2509%
2510*/
2511MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002512 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002513{
2514 GetOneVirtualPixelFromHandler
2515 get_one_virtual_pixel_from_handler;
2516
2517 CacheInfo
2518 *cache_info;
2519
2520 MagickBooleanType
2521 status;
2522
2523 assert(image != (const Image *) NULL);
2524 assert(image->signature == MagickSignature);
2525 assert(image->cache != (Cache) NULL);
2526 cache_info=(CacheInfo *) image->cache;
2527 assert(cache_info->signature == MagickSignature);
2528 *pixel=image->background_color;
2529 get_one_virtual_pixel_from_handler=
2530 cache_info->methods.get_one_virtual_pixel_from_handler;
2531 if (get_one_virtual_pixel_from_handler ==
2532 (GetOneVirtualPixelFromHandler) NULL)
2533 return(MagickFalse);
2534 status=get_one_virtual_pixel_from_handler(image,GetPixelCacheVirtualMethod(
2535 image),x,y,pixel,exception);
2536 return(status);
2537}
2538
2539/*
2540%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2541% %
2542% %
2543% %
2544+ 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 %
2545% %
2546% %
2547% %
2548%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2549%
2550% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2551% specified (x,y) location. The image background color is returned if an
2552% error occurs.
2553%
2554% The format of the GetOneVirtualPixelFromCache() method is:
2555%
2556% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristybb503372010-05-27 20:51:26 +00002557% const VirtualPixelPacket method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002558% PixelPacket *pixel,ExceptionInfo *exception)
2559%
2560% A description of each parameter follows:
2561%
2562% o image: the image.
2563%
2564% o virtual_pixel_method: the virtual pixel method.
2565%
2566% o x,y: These values define the location of the pixel to return.
2567%
2568% o pixel: return a pixel at the specified (x,y) location.
2569%
2570% o exception: return any errors or warnings in this structure.
2571%
2572*/
2573static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002574 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002575 PixelPacket *pixel,ExceptionInfo *exception)
2576{
2577 const PixelPacket
2578 *pixels;
2579
2580 *pixel=image->background_color;
2581 pixels=GetVirtualPixelCache(image,virtual_pixel_method,x,y,1UL,1UL,exception);
2582 if (pixels == (const PixelPacket *) NULL)
2583 return(MagickFalse);
2584 *pixel=(*pixels);
2585 return(MagickTrue);
2586}
2587
2588/*
2589%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2590% %
2591% %
2592% %
2593+ G e t P i x e l C a c h e C o l o r s p a c e %
2594% %
2595% %
2596% %
2597%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2598%
2599% GetPixelCacheColorspace() returns the class type of the pixel cache.
2600%
2601% The format of the GetPixelCacheColorspace() method is:
2602%
2603% Colorspace GetPixelCacheColorspace(Cache cache)
2604%
2605% A description of each parameter follows:
2606%
2607% o cache: the pixel cache.
2608%
2609*/
2610MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
2611{
2612 CacheInfo
2613 *cache_info;
2614
2615 assert(cache != (Cache) NULL);
2616 cache_info=(CacheInfo *) cache;
2617 assert(cache_info->signature == MagickSignature);
2618 if (cache_info->debug != MagickFalse)
2619 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2620 cache_info->filename);
2621 return(cache_info->colorspace);
2622}
2623
2624/*
2625%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2626% %
2627% %
2628% %
2629+ G e t P i x e l C a c h e M e t h o d s %
2630% %
2631% %
2632% %
2633%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2634%
2635% GetPixelCacheMethods() initializes the CacheMethods structure.
2636%
2637% The format of the GetPixelCacheMethods() method is:
2638%
2639% void GetPixelCacheMethods(CacheMethods *cache_methods)
2640%
2641% A description of each parameter follows:
2642%
2643% o cache_methods: Specifies a pointer to a CacheMethods structure.
2644%
2645*/
2646MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
2647{
2648 assert(cache_methods != (CacheMethods *) NULL);
2649 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2650 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2651 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2652 cache_methods->get_virtual_indexes_from_handler=GetVirtualIndexesFromCache;
2653 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2654 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2655 cache_methods->get_authentic_indexes_from_handler=
2656 GetAuthenticIndexesFromCache;
2657 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2658 cache_methods->get_one_authentic_pixel_from_handler=
2659 GetOneAuthenticPixelFromCache;
2660 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2661 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2662 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2663}
2664
2665/*
2666%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2667% %
2668% %
2669% %
2670+ G e t P i x e l C a c h e N e x u s E x t e n t %
2671% %
2672% %
2673% %
2674%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2675%
2676% GetPixelCacheNexusExtent() returns the extent of the pixels associated with
2677% the last call to SetPixelCacheNexusPixels() or GetPixelCacheNexusPixels().
2678%
2679% The format of the GetPixelCacheNexusExtent() method is:
2680%
2681% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2682% NexusInfo *nexus_info)
2683%
2684% A description of each parameter follows:
2685%
2686% o nexus_info: the nexus info.
2687%
2688*/
2689MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2690 NexusInfo *nexus_info)
2691{
2692 CacheInfo
2693 *cache_info;
2694
2695 MagickSizeType
2696 extent;
2697
2698 if (cache == (Cache) NULL)
2699 return(0);
2700 cache_info=(CacheInfo *) cache;
2701 assert(cache_info->signature == MagickSignature);
2702 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2703 if (extent == 0)
2704 return((MagickSizeType) cache_info->columns*cache_info->rows);
2705 return(extent);
2706}
2707
2708/*
2709%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2710% %
2711% %
2712% %
2713+ 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 %
2714% %
2715% %
2716% %
2717%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2718%
2719% GetPixelCacheNexusIndexes() returns the indexes associated with the
2720% specified cache nexus.
2721%
2722% The format of the GetPixelCacheNexusIndexes() method is:
2723%
2724% IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2725% NexusInfo *nexus_info)
2726%
2727% A description of each parameter follows:
2728%
2729% o cache: the pixel cache.
2730%
2731% o nexus_info: the cache nexus to return the colormap indexes.
2732%
2733*/
2734MagickExport IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2735 NexusInfo *nexus_info)
2736{
2737 CacheInfo
2738 *cache_info;
2739
2740 if (cache == (Cache) NULL)
2741 return((IndexPacket *) NULL);
2742 cache_info=(CacheInfo *) cache;
2743 assert(cache_info->signature == MagickSignature);
2744 if (cache_info->storage_class == UndefinedClass)
2745 return((IndexPacket *) NULL);
2746 return(nexus_info->indexes);
2747}
2748
2749/*
2750%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2751% %
2752% %
2753% %
2754+ G e t P i x e l C a c h e N e x u s P i x e l s %
2755% %
2756% %
2757% %
2758%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2759%
2760% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2761% cache nexus.
2762%
2763% The format of the GetPixelCacheNexusPixels() method is:
2764%
2765% PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2766% NexusInfo *nexus_info)
2767%
2768% A description of each parameter follows:
2769%
2770% o cache: the pixel cache.
2771%
2772% o nexus_info: the cache nexus to return the pixels.
2773%
2774*/
2775MagickExport PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2776 NexusInfo *nexus_info)
2777{
2778 CacheInfo
2779 *cache_info;
2780
2781 if (cache == (Cache) NULL)
2782 return((PixelPacket *) NULL);
2783 cache_info=(CacheInfo *) cache;
2784 assert(cache_info->signature == MagickSignature);
2785 if (cache_info->debug != MagickFalse)
2786 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2787 cache_info->filename);
2788 if (cache_info->storage_class == UndefinedClass)
2789 return((PixelPacket *) NULL);
2790 return(nexus_info->pixels);
2791}
2792
2793/*
2794%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2795% %
2796% %
2797% %
cristy056ba772010-01-02 23:33:54 +00002798+ G e t P i x e l C a c h e P i x e l s %
2799% %
2800% %
2801% %
2802%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2803%
2804% GetPixelCachePixels() returns the pixels associated with the specified image.
2805%
2806% The format of the GetPixelCachePixels() method is:
2807%
cristyf84a1932010-01-03 18:00:18 +00002808% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2809% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002810%
2811% A description of each parameter follows:
2812%
2813% o image: the image.
2814%
2815% o length: the pixel cache length.
2816%
cristyf84a1932010-01-03 18:00:18 +00002817% o exception: return any errors or warnings in this structure.
2818%
cristy056ba772010-01-02 23:33:54 +00002819*/
cristyf84a1932010-01-03 18:00:18 +00002820MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2821 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002822{
2823 CacheInfo
2824 *cache_info;
2825
2826 assert(image != (const Image *) NULL);
2827 assert(image->signature == MagickSignature);
2828 if (image->debug != MagickFalse)
2829 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2830 assert(image->cache != (Cache) NULL);
cristyc4c8d132010-01-07 01:58:38 +00002831 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
cristy056ba772010-01-02 23:33:54 +00002832 assert(cache_info->signature == MagickSignature);
2833 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002834 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002835 return((void *) NULL);
2836 *length=cache_info->length;
2837 return((void *) cache_info->pixels);
2838}
2839
2840/*
2841%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2842% %
2843% %
2844% %
cristyb32b90a2009-09-07 21:45:48 +00002845+ 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 +00002846% %
2847% %
2848% %
2849%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2850%
2851% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2852%
2853% The format of the GetPixelCacheStorageClass() method is:
2854%
2855% ClassType GetPixelCacheStorageClass(Cache cache)
2856%
2857% A description of each parameter follows:
2858%
2859% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2860%
2861% o cache: the pixel cache.
2862%
2863*/
2864MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
2865{
2866 CacheInfo
2867 *cache_info;
2868
2869 assert(cache != (Cache) NULL);
2870 cache_info=(CacheInfo *) cache;
2871 assert(cache_info->signature == MagickSignature);
2872 if (cache_info->debug != MagickFalse)
2873 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2874 cache_info->filename);
2875 return(cache_info->storage_class);
2876}
2877
2878/*
2879%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2880% %
2881% %
2882% %
cristyb32b90a2009-09-07 21:45:48 +00002883+ G e t P i x e l C a c h e T i l e S i z e %
2884% %
2885% %
2886% %
2887%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2888%
2889% GetPixelCacheTileSize() returns the pixel cache tile size.
2890%
2891% The format of the GetPixelCacheTileSize() method is:
2892%
cristybb503372010-05-27 20:51:26 +00002893% void GetPixelCacheTileSize(const Image *image,size_t *width,
2894% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002895%
2896% A description of each parameter follows:
2897%
2898% o image: the image.
2899%
2900% o width: the optimize cache tile width in pixels.
2901%
2902% o height: the optimize cache tile height in pixels.
2903%
2904*/
cristybb503372010-05-27 20:51:26 +00002905MagickExport void GetPixelCacheTileSize(const Image *image,size_t *width,
2906 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002907{
2908 CacheInfo
2909 *cache_info;
2910
2911 assert(image != (Image *) NULL);
2912 assert(image->signature == MagickSignature);
2913 if (image->debug != MagickFalse)
2914 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2915 assert(image->cache != (Cache) NULL);
2916 cache_info=(CacheInfo *) image->cache;
2917 assert(cache_info->signature == MagickSignature);
2918 *width=2048UL/sizeof(PixelPacket);
2919 if (GetPixelCacheType(image) == DiskCache)
cristydaa97692009-09-13 02:10:35 +00002920 *width=8192UL/sizeof(PixelPacket);
cristyb32b90a2009-09-07 21:45:48 +00002921 *height=(*width);
2922}
2923
2924/*
2925%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2926% %
2927% %
2928% %
2929+ G e t P i x e l C a c h e T y p e %
2930% %
2931% %
2932% %
2933%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2934%
2935% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2936%
2937% The format of the GetPixelCacheType() method is:
2938%
2939% CacheType GetPixelCacheType(const Image *image)
2940%
2941% A description of each parameter follows:
2942%
2943% o image: the image.
2944%
2945*/
2946MagickExport CacheType GetPixelCacheType(const Image *image)
2947{
2948 CacheInfo
2949 *cache_info;
2950
2951 assert(image != (Image *) NULL);
2952 assert(image->signature == MagickSignature);
2953 if (image->debug != MagickFalse)
2954 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2955 assert(image->cache != (Cache) NULL);
2956 cache_info=(CacheInfo *) image->cache;
2957 assert(cache_info->signature == MagickSignature);
2958 return(cache_info->type);
2959}
2960
2961/*
2962%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2963% %
2964% %
2965% %
cristy3ed852e2009-09-05 21:47:34 +00002966+ 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 %
2967% %
2968% %
2969% %
2970%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2971%
2972% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2973% pixel cache. A virtual pixel is any pixel access that is outside the
2974% boundaries of the image cache.
2975%
2976% The format of the GetPixelCacheVirtualMethod() method is:
2977%
2978% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2979%
2980% A description of each parameter follows:
2981%
2982% o image: the image.
2983%
2984*/
2985MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2986{
2987 CacheInfo
2988 *cache_info;
2989
2990 assert(image != (Image *) NULL);
2991 assert(image->signature == MagickSignature);
2992 if (image->debug != MagickFalse)
2993 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2994 assert(image->cache != (Cache) NULL);
2995 cache_info=(CacheInfo *) image->cache;
2996 assert(cache_info->signature == MagickSignature);
2997 return(cache_info->virtual_pixel_method);
2998}
2999
3000/*
3001%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3002% %
3003% %
3004% %
3005+ 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 %
3006% %
3007% %
3008% %
3009%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3010%
3011% GetVirtualIndexesFromCache() returns the indexes associated with the last
3012% call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3013%
3014% The format of the GetVirtualIndexesFromCache() method is:
3015%
3016% IndexPacket *GetVirtualIndexesFromCache(const Image *image)
3017%
3018% A description of each parameter follows:
3019%
3020% o image: the image.
3021%
3022*/
3023static const IndexPacket *GetVirtualIndexesFromCache(const Image *image)
3024{
3025 CacheInfo
3026 *cache_info;
3027
3028 const IndexPacket
3029 *indexes;
3030
cristybb503372010-05-27 20:51:26 +00003031 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003032 id;
3033
3034 if (image->debug != MagickFalse)
3035 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3036 cache_info=(CacheInfo *) image->cache;
3037 id=GetOpenMPThreadId();
cristybb503372010-05-27 20:51:26 +00003038 assert(id < (ssize_t) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00003039 indexes=GetVirtualIndexesFromNexus(image->cache,cache_info->nexus_info[id]);
3040 return(indexes);
3041}
3042
3043/*
3044%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3045% %
3046% %
3047% %
3048+ 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 %
3049% %
3050% %
3051% %
3052%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3053%
3054% GetVirtualIndexesFromNexus() returns the indexes associated with the
3055% specified cache nexus.
3056%
3057% The format of the GetVirtualIndexesFromNexus() method is:
3058%
3059% const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
3060% NexusInfo *nexus_info)
3061%
3062% A description of each parameter follows:
3063%
3064% o cache: the pixel cache.
3065%
3066% o nexus_info: the cache nexus to return the colormap indexes.
3067%
3068*/
3069MagickExport const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
3070 NexusInfo *nexus_info)
3071{
3072 CacheInfo
3073 *cache_info;
3074
3075 if (cache == (Cache) NULL)
3076 return((IndexPacket *) NULL);
3077 cache_info=(CacheInfo *) cache;
3078 assert(cache_info->signature == MagickSignature);
3079 if (cache_info->storage_class == UndefinedClass)
3080 return((IndexPacket *) NULL);
3081 return(nexus_info->indexes);
3082}
3083
3084/*
3085%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3086% %
3087% %
3088% %
3089% G e t V i r t u a l I n d e x Q u e u e %
3090% %
3091% %
3092% %
3093%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3094%
3095% GetVirtualIndexQueue() returns the virtual black channel or the
3096% colormap indexes associated with the last call to QueueAuthenticPixels() or
3097% GetVirtualPixels(). NULL is returned if the black channel or colormap
3098% indexes are not available.
3099%
3100% The format of the GetVirtualIndexQueue() method is:
3101%
3102% const IndexPacket *GetVirtualIndexQueue(const Image *image)
3103%
3104% A description of each parameter follows:
3105%
3106% o image: the image.
3107%
3108*/
3109MagickExport const IndexPacket *GetVirtualIndexQueue(const Image *image)
3110{
3111 CacheInfo
3112 *cache_info;
3113
3114 assert(image != (const Image *) NULL);
3115 assert(image->signature == MagickSignature);
3116 if (image->debug != MagickFalse)
3117 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3118 assert(image->cache != (Cache) NULL);
3119 cache_info=(CacheInfo *) image->cache;
3120 assert(cache_info->signature == MagickSignature);
3121 if (cache_info->methods.get_virtual_indexes_from_handler ==
3122 (GetVirtualIndexesFromHandler) NULL)
3123 return((IndexPacket *) NULL);
3124 return(cache_info->methods.get_virtual_indexes_from_handler(image));
3125}
3126
3127/*
3128%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3129% %
3130% %
3131% %
3132+ 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 %
3133% %
3134% %
3135% %
3136%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3137%
3138% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3139% pixel cache as defined by the geometry parameters. A pointer to the pixels
3140% is returned if the pixels are transferred, otherwise a NULL is returned.
3141%
3142% The format of the GetVirtualPixelsFromNexus() method is:
3143%
3144% PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003145% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00003146% const size_t columns,const size_t rows,NexusInfo *nexus_info,
3147% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003148%
3149% A description of each parameter follows:
3150%
3151% o image: the image.
3152%
3153% o virtual_pixel_method: the virtual pixel method.
3154%
3155% o x,y,columns,rows: These values define the perimeter of a region of
3156% pixels.
3157%
3158% o nexus_info: the cache nexus to acquire.
3159%
3160% o exception: return any errors or warnings in this structure.
3161%
3162*/
3163
cristybb503372010-05-27 20:51:26 +00003164static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003165 DitherMatrix[64] =
3166 {
3167 0, 48, 12, 60, 3, 51, 15, 63,
3168 32, 16, 44, 28, 35, 19, 47, 31,
3169 8, 56, 4, 52, 11, 59, 7, 55,
3170 40, 24, 36, 20, 43, 27, 39, 23,
3171 2, 50, 14, 62, 1, 49, 13, 61,
3172 34, 18, 46, 30, 33, 17, 45, 29,
3173 10, 58, 6, 54, 9, 57, 5, 53,
3174 42, 26, 38, 22, 41, 25, 37, 21
3175 };
3176
cristybb503372010-05-27 20:51:26 +00003177static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003178{
cristybb503372010-05-27 20:51:26 +00003179 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003180 index;
3181
3182 index=x+DitherMatrix[x & 0x07]-32L;
3183 if (index < 0L)
3184 return(0L);
cristybb503372010-05-27 20:51:26 +00003185 if (index >= (ssize_t) columns)
3186 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00003187 return(index);
3188}
3189
cristybb503372010-05-27 20:51:26 +00003190static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003191{
cristybb503372010-05-27 20:51:26 +00003192 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003193 index;
3194
3195 index=y+DitherMatrix[y & 0x07]-32L;
3196 if (index < 0L)
3197 return(0L);
cristybb503372010-05-27 20:51:26 +00003198 if (index >= (ssize_t) rows)
3199 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00003200 return(index);
3201}
3202
cristybb503372010-05-27 20:51:26 +00003203static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003204{
3205 if (x < 0L)
3206 return(0L);
cristybb503372010-05-27 20:51:26 +00003207 if (x >= (ssize_t) columns)
3208 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003209 return(x);
3210}
3211
cristybb503372010-05-27 20:51:26 +00003212static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003213{
3214 if (y < 0L)
3215 return(0L);
cristybb503372010-05-27 20:51:26 +00003216 if (y >= (ssize_t) rows)
3217 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003218 return(y);
3219}
3220
cristybb503372010-05-27 20:51:26 +00003221static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003222{
cristybb503372010-05-27 20:51:26 +00003223 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003224}
3225
cristybb503372010-05-27 20:51:26 +00003226static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003227{
cristybb503372010-05-27 20:51:26 +00003228 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003229}
3230
3231/*
3232 VirtualPixelModulo() computes the remainder of dividing offset by extent. It
3233 returns not only the quotient (tile the offset falls in) but also the positive
3234 remainer within that tile such that 0 <= remainder < extent. This method is
3235 essentially a ldiv() using a floored modulo division rather than the normal
3236 default truncated modulo division.
3237*/
cristybb503372010-05-27 20:51:26 +00003238static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3239 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003240{
3241 MagickModulo
3242 modulo;
3243
cristybb503372010-05-27 20:51:26 +00003244 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003245 if (offset < 0L)
3246 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003247 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003248 return(modulo);
3249}
3250
3251MagickExport const PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003252 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3253 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003254 ExceptionInfo *exception)
3255{
3256 CacheInfo
3257 *cache_info;
3258
cristyc3ec0d42010-04-07 01:18:08 +00003259 IndexPacket
3260 virtual_index;
3261
cristy3ed852e2009-09-05 21:47:34 +00003262 MagickOffsetType
3263 offset;
3264
3265 MagickSizeType
3266 length,
3267 number_pixels;
3268
3269 NexusInfo
3270 **virtual_nexus;
3271
3272 PixelPacket
3273 *pixels,
3274 virtual_pixel;
3275
3276 RectangleInfo
3277 region;
3278
3279 register const IndexPacket
cristyc3ec0d42010-04-07 01:18:08 +00003280 *restrict virtual_indexes;
cristy3ed852e2009-09-05 21:47:34 +00003281
3282 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003283 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003284
3285 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003286 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003287
cristybb503372010-05-27 20:51:26 +00003288 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003289 u,
3290 v;
3291
3292 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003293 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003294
3295 /*
3296 Acquire pixels.
3297 */
3298 if (image->debug != MagickFalse)
3299 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3300 cache_info=(CacheInfo *) image->cache;
cristy4cfbb3f2010-03-14 20:40:23 +00003301 if (cache_info->type == UndefinedCache)
cristy3ed852e2009-09-05 21:47:34 +00003302 return((const PixelPacket *) NULL);
3303 region.x=x;
3304 region.y=y;
3305 region.width=columns;
3306 region.height=rows;
3307 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
3308 if (pixels == (PixelPacket *) NULL)
3309 return((const PixelPacket *) NULL);
cristydf415c82010-03-11 16:47:50 +00003310 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3311 nexus_info->region.x;
3312 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3313 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003314 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3315 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003316 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3317 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003318 {
3319 MagickBooleanType
3320 status;
3321
3322 /*
3323 Pixel request is inside cache extents.
3324 */
3325 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
3326 return(pixels);
3327 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3328 if (status == MagickFalse)
3329 return((const PixelPacket *) NULL);
3330 if ((cache_info->storage_class == PseudoClass) ||
3331 (cache_info->colorspace == CMYKColorspace))
3332 {
3333 status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
3334 if (status == MagickFalse)
3335 return((const PixelPacket *) NULL);
3336 }
3337 return(pixels);
3338 }
3339 /*
3340 Pixel request is outside cache extents.
3341 */
3342 q=pixels;
3343 indexes=GetPixelCacheNexusIndexes(cache_info,nexus_info);
3344 virtual_nexus=AcquirePixelCacheNexus(1);
3345 if (virtual_nexus == (NexusInfo **) NULL)
3346 {
3347 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3348 "UnableToGetCacheNexus","`%s'",image->filename);
3349 return((const PixelPacket *) NULL);
3350 }
3351 switch (virtual_pixel_method)
3352 {
3353 case BlackVirtualPixelMethod:
3354 {
cristy4789f0d2010-01-10 00:01:06 +00003355 SetRedPixelComponent(&virtual_pixel,0);
3356 SetGreenPixelComponent(&virtual_pixel,0);
3357 SetBluePixelComponent(&virtual_pixel,0);
3358 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003359 break;
3360 }
3361 case GrayVirtualPixelMethod:
3362 {
cristy4789f0d2010-01-10 00:01:06 +00003363 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3364 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3365 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3366 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003367 break;
3368 }
3369 case TransparentVirtualPixelMethod:
3370 {
cristy4789f0d2010-01-10 00:01:06 +00003371 SetRedPixelComponent(&virtual_pixel,0);
3372 SetGreenPixelComponent(&virtual_pixel,0);
3373 SetBluePixelComponent(&virtual_pixel,0);
3374 SetOpacityPixelComponent(&virtual_pixel,TransparentOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003375 break;
3376 }
3377 case MaskVirtualPixelMethod:
3378 case WhiteVirtualPixelMethod:
3379 {
cristy4789f0d2010-01-10 00:01:06 +00003380 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3381 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3382 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3383 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003384 break;
3385 }
3386 default:
3387 {
3388 virtual_pixel=image->background_color;
3389 break;
3390 }
3391 }
cristyc3ec0d42010-04-07 01:18:08 +00003392 virtual_index=0;
cristybb503372010-05-27 20:51:26 +00003393 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003394 {
cristybb503372010-05-27 20:51:26 +00003395 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003396 {
3397 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003398 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003399 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3400 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003401 {
3402 MagickModulo
3403 x_modulo,
3404 y_modulo;
3405
3406 /*
3407 Transfer a single pixel.
3408 */
3409 length=(MagickSizeType) 1;
3410 switch (virtual_pixel_method)
3411 {
3412 case BackgroundVirtualPixelMethod:
3413 case ConstantVirtualPixelMethod:
3414 case BlackVirtualPixelMethod:
3415 case GrayVirtualPixelMethod:
3416 case TransparentVirtualPixelMethod:
3417 case MaskVirtualPixelMethod:
3418 case WhiteVirtualPixelMethod:
3419 {
3420 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003421 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003422 break;
3423 }
3424 case EdgeVirtualPixelMethod:
3425 default:
3426 {
3427 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003428 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003429 1UL,1UL,virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003430 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3431 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003432 break;
3433 }
3434 case RandomVirtualPixelMethod:
3435 {
3436 if (cache_info->random_info == (RandomInfo *) NULL)
3437 cache_info->random_info=AcquireRandomInfo();
3438 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003439 RandomX(cache_info->random_info,cache_info->columns),
3440 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003441 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003442 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3443 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003444 break;
3445 }
3446 case DitherVirtualPixelMethod:
3447 {
3448 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003449 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003450 1UL,1UL,virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003451 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3452 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003453 break;
3454 }
3455 case TileVirtualPixelMethod:
3456 {
3457 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3458 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3459 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3460 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3461 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003462 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3463 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003464 break;
3465 }
3466 case MirrorVirtualPixelMethod:
3467 {
3468 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3469 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003470 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003471 x_modulo.remainder-1L;
3472 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3473 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003474 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003475 y_modulo.remainder-1L;
3476 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3477 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3478 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003479 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3480 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003481 break;
3482 }
3483 case CheckerTileVirtualPixelMethod:
3484 {
3485 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3486 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3487 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3488 {
3489 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003490 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003491 break;
3492 }
3493 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3494 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3495 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003496 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3497 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003498 break;
3499 }
3500 case HorizontalTileVirtualPixelMethod:
3501 {
cristybb503372010-05-27 20:51:26 +00003502 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003503 {
3504 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003505 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003506 break;
3507 }
3508 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3509 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3510 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3511 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3512 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003513 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3514 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003515 break;
3516 }
3517 case VerticalTileVirtualPixelMethod:
3518 {
cristybb503372010-05-27 20:51:26 +00003519 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
cristy3ed852e2009-09-05 21:47:34 +00003520 {
3521 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003522 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003523 break;
3524 }
3525 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3526 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3527 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3528 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3529 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003530 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3531 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003532 break;
3533 }
3534 case HorizontalTileEdgeVirtualPixelMethod:
3535 {
3536 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3537 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003538 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003539 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003540 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3541 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003542 break;
3543 }
3544 case VerticalTileEdgeVirtualPixelMethod:
3545 {
3546 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3547 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003548 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003549 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003550 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3551 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003552 break;
3553 }
3554 }
3555 if (p == (const PixelPacket *) NULL)
3556 break;
3557 *q++=(*p);
cristyc3ec0d42010-04-07 01:18:08 +00003558 if ((indexes != (IndexPacket *) NULL) &&
3559 (virtual_indexes != (const IndexPacket *) NULL))
3560 *indexes++=(*virtual_indexes);
cristy3ed852e2009-09-05 21:47:34 +00003561 continue;
3562 }
3563 /*
3564 Transfer a run of pixels.
3565 */
3566 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,
cristybb503372010-05-27 20:51:26 +00003567 (size_t) length,1UL,virtual_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003568 if (p == (const PixelPacket *) NULL)
3569 break;
cristyc3ec0d42010-04-07 01:18:08 +00003570 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003571 (void) CopyMagickMemory(q,p,(size_t) length*sizeof(*p));
3572 q+=length;
cristyc3ec0d42010-04-07 01:18:08 +00003573 if ((indexes != (IndexPacket *) NULL) &&
3574 (virtual_indexes != (const IndexPacket *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003575 {
cristyc3ec0d42010-04-07 01:18:08 +00003576 (void) CopyMagickMemory(indexes,virtual_indexes,(size_t) length*
3577 sizeof(*virtual_indexes));
3578 indexes+=length;
cristy3ed852e2009-09-05 21:47:34 +00003579 }
3580 }
3581 }
3582 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3583 return(pixels);
3584}
3585
3586/*
3587%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3588% %
3589% %
3590% %
3591+ G e t V i r t u a l P i x e l C a c h e %
3592% %
3593% %
3594% %
3595%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3596%
3597% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3598% cache as defined by the geometry parameters. A pointer to the pixels
3599% is returned if the pixels are transferred, otherwise a NULL is returned.
3600%
3601% The format of the GetVirtualPixelCache() method is:
3602%
3603% const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003604% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3605% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003606% ExceptionInfo *exception)
3607%
3608% A description of each parameter follows:
3609%
3610% o image: the image.
3611%
3612% o virtual_pixel_method: the virtual pixel method.
3613%
3614% o x,y,columns,rows: These values define the perimeter of a region of
3615% pixels.
3616%
3617% o exception: return any errors or warnings in this structure.
3618%
3619*/
3620static const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003621 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3622 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003623{
3624 CacheInfo
3625 *cache_info;
3626
3627 const PixelPacket
3628 *pixels;
3629
cristybb503372010-05-27 20:51:26 +00003630 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003631 id;
3632
3633 if (image->debug != MagickFalse)
3634 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3635 cache_info=(CacheInfo *) image->cache;
3636 id=GetOpenMPThreadId();
cristybb503372010-05-27 20:51:26 +00003637 assert(id < (ssize_t) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00003638 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3639 cache_info->nexus_info[id],exception);
3640 return(pixels);
3641}
3642
3643/*
3644%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3645% %
3646% %
3647% %
3648% G e t V i r t u a l P i x e l Q u e u e %
3649% %
3650% %
3651% %
3652%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3653%
3654% GetVirtualPixelQueue() returns the virtual pixels associated with the
3655% last call to QueueAuthenticPixels() or GetVirtualPixels().
3656%
3657% The format of the GetVirtualPixelQueue() method is:
3658%
3659% const PixelPacket *GetVirtualPixelQueue(const Image image)
3660%
3661% A description of each parameter follows:
3662%
3663% o image: the image.
3664%
3665*/
3666MagickExport const PixelPacket *GetVirtualPixelQueue(const Image *image)
3667{
3668 CacheInfo
3669 *cache_info;
3670
3671 assert(image != (const Image *) NULL);
3672 assert(image->signature == MagickSignature);
3673 if (image->debug != MagickFalse)
3674 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3675 assert(image->cache != (Cache) NULL);
3676 cache_info=(CacheInfo *) image->cache;
3677 assert(cache_info->signature == MagickSignature);
3678 if (cache_info->methods.get_virtual_pixels_handler ==
3679 (GetVirtualPixelsHandler) NULL)
3680 return((PixelPacket *) NULL);
3681 return(cache_info->methods.get_virtual_pixels_handler(image));
3682}
3683
3684/*
3685%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3686% %
3687% %
3688% %
3689% G e t V i r t u a l P i x e l s %
3690% %
3691% %
3692% %
3693%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3694%
3695% GetVirtualPixels() returns an immutable pixel region. If the
3696% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003697% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003698% copy of the pixels or it may point to the original pixels in memory.
3699% Performance is maximized if the selected region is part of one row, or one
3700% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003701% (without a copy) if the image is in memory, or in a memory-mapped file. The
3702% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003703%
3704% Pixels accessed via the returned pointer represent a simple array of type
3705% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
3706% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access
3707% the black color component or to obtain the colormap indexes (of type
3708% IndexPacket) corresponding to the region.
3709%
3710% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3711%
3712% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3713% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3714% GetCacheViewAuthenticPixels() instead.
3715%
3716% The format of the GetVirtualPixels() method is:
3717%
cristybb503372010-05-27 20:51:26 +00003718% const PixelPacket *GetVirtualPixels(const Image *image,const ssize_t x,
3719% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003720% ExceptionInfo *exception)
3721%
3722% A description of each parameter follows:
3723%
3724% o image: the image.
3725%
3726% o x,y,columns,rows: These values define the perimeter of a region of
3727% pixels.
3728%
3729% o exception: return any errors or warnings in this structure.
3730%
3731*/
3732MagickExport const PixelPacket *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003733 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3734 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003735{
3736 CacheInfo
3737 *cache_info;
3738
3739 const PixelPacket
3740 *pixels;
3741
3742 assert(image != (const Image *) NULL);
3743 assert(image->signature == MagickSignature);
3744 if (image->debug != MagickFalse)
3745 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3746 assert(image->cache != (Cache) NULL);
3747 cache_info=(CacheInfo *) image->cache;
3748 assert(cache_info->signature == MagickSignature);
3749 if (cache_info->methods.get_virtual_pixel_handler ==
3750 (GetVirtualPixelHandler) NULL)
3751 return((const PixelPacket *) NULL);
3752 pixels=cache_info->methods.get_virtual_pixel_handler(image,
3753 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception);
3754 return(pixels);
3755}
3756
3757/*
3758%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3759% %
3760% %
3761% %
3762+ 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 %
3763% %
3764% %
3765% %
3766%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3767%
3768% GetVirtualPixelsCache() returns the pixels associated with the last call
3769% to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3770%
3771% The format of the GetVirtualPixelsCache() method is:
3772%
3773% PixelPacket *GetVirtualPixelsCache(const Image *image)
3774%
3775% A description of each parameter follows:
3776%
3777% o image: the image.
3778%
3779*/
3780static const PixelPacket *GetVirtualPixelsCache(const Image *image)
3781{
3782 CacheInfo
3783 *cache_info;
3784
3785 const PixelPacket
3786 *pixels;
3787
cristybb503372010-05-27 20:51:26 +00003788 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003789 id;
3790
3791 if (image->debug != MagickFalse)
3792 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3793 cache_info=(CacheInfo *) image->cache;
3794 id=GetOpenMPThreadId();
cristybb503372010-05-27 20:51:26 +00003795 assert(id < (ssize_t) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00003796 pixels=GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]);
3797 return(pixels);
3798}
3799
3800/*
3801%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3802% %
3803% %
3804% %
3805+ G e t V i r t u a l P i x e l s N e x u s %
3806% %
3807% %
3808% %
3809%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3810%
3811% GetVirtualPixelsNexus() returns the pixels associated with the specified
3812% cache nexus.
3813%
3814% The format of the GetVirtualPixelsNexus() method is:
3815%
3816% const IndexPacket *GetVirtualPixelsNexus(const Cache cache,
3817% NexusInfo *nexus_info)
3818%
3819% A description of each parameter follows:
3820%
3821% o cache: the pixel cache.
3822%
3823% o nexus_info: the cache nexus to return the colormap pixels.
3824%
3825*/
3826MagickExport const PixelPacket *GetVirtualPixelsNexus(const Cache cache,
3827 NexusInfo *nexus_info)
3828{
3829 CacheInfo
3830 *cache_info;
3831
3832 if (cache == (Cache) NULL)
3833 return((PixelPacket *) NULL);
3834 cache_info=(CacheInfo *) cache;
3835 assert(cache_info->signature == MagickSignature);
3836 if (cache_info->storage_class == UndefinedClass)
3837 return((PixelPacket *) NULL);
3838 return((const PixelPacket *) nexus_info->pixels);
3839}
3840
3841/*
3842%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3843% %
3844% %
3845% %
3846+ M a s k P i x e l C a c h e N e x u s %
3847% %
3848% %
3849% %
3850%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3851%
3852% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3853% The method returns MagickTrue if the pixel region is masked, otherwise
3854% MagickFalse.
3855%
3856% The format of the MaskPixelCacheNexus() method is:
3857%
3858% MagickBooleanType MaskPixelCacheNexus(Image *image,
3859% NexusInfo *nexus_info,ExceptionInfo *exception)
3860%
3861% A description of each parameter follows:
3862%
3863% o image: the image.
3864%
3865% o nexus_info: the cache nexus to clip.
3866%
3867% o exception: return any errors or warnings in this structure.
3868%
3869*/
3870
3871static inline void MagickPixelCompositeMask(const MagickPixelPacket *p,
3872 const MagickRealType alpha,const MagickPixelPacket *q,
3873 const MagickRealType beta,MagickPixelPacket *composite)
3874{
3875 MagickRealType
3876 gamma;
3877
3878 if (alpha == TransparentOpacity)
3879 {
3880 *composite=(*q);
3881 return;
3882 }
3883 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3884 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3885 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3886 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3887 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3888 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3889 composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
3890}
3891
3892static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3893 ExceptionInfo *exception)
3894{
3895 CacheInfo
3896 *cache_info;
3897
3898 MagickPixelPacket
3899 alpha,
3900 beta;
3901
3902 MagickSizeType
3903 number_pixels;
3904
3905 NexusInfo
3906 **clip_nexus,
3907 **image_nexus;
3908
3909 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003910 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003911
3912 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003913 *restrict nexus_indexes,
3914 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003915
cristybb503372010-05-27 20:51:26 +00003916 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003917 i;
3918
3919 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003920 *restrict p,
3921 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003922
3923 /*
3924 Apply clip mask.
3925 */
3926 if (image->debug != MagickFalse)
3927 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3928 if (image->mask == (Image *) NULL)
3929 return(MagickFalse);
3930 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
3931 if (cache_info == (Cache) NULL)
3932 return(MagickFalse);
3933 image_nexus=AcquirePixelCacheNexus(1);
3934 clip_nexus=AcquirePixelCacheNexus(1);
3935 if ((image_nexus == (NexusInfo **) NULL) ||
3936 (clip_nexus == (NexusInfo **) NULL))
3937 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy09449f72010-01-23 03:08:36 +00003938 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,
3939 nexus_info->region.y,nexus_info->region.width,nexus_info->region.height,
3940 image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003941 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
3942 q=nexus_info->pixels;
3943 nexus_indexes=nexus_info->indexes;
3944 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3945 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3946 nexus_info->region.height,clip_nexus[0],&image->exception);
3947 GetMagickPixelPacket(image,&alpha);
3948 GetMagickPixelPacket(image,&beta);
3949 number_pixels=(MagickSizeType) nexus_info->region.width*
3950 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +00003951 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +00003952 {
3953 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
3954 break;
3955 SetMagickPixelPacket(image,p,indexes+i,&alpha);
3956 SetMagickPixelPacket(image,q,nexus_indexes+i,&beta);
3957 MagickPixelCompositeMask(&beta,(MagickRealType) PixelIntensityToQuantum(r),
3958 &alpha,alpha.opacity,&beta);
cristyce70c172010-01-07 17:15:30 +00003959 q->red=ClampToQuantum(beta.red);
3960 q->green=ClampToQuantum(beta.green);
3961 q->blue=ClampToQuantum(beta.blue);
3962 q->opacity=ClampToQuantum(beta.opacity);
cristy3ed852e2009-09-05 21:47:34 +00003963 if (cache_info->active_index_channel != MagickFalse)
3964 nexus_indexes[i]=indexes[i];
3965 p++;
3966 q++;
3967 r++;
3968 }
3969 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3970 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +00003971 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003972 return(MagickFalse);
3973 return(MagickTrue);
3974}
3975
3976/*
3977%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3978% %
3979% %
3980% %
3981+ O p e n P i x e l C a c h e %
3982% %
3983% %
3984% %
3985%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3986%
3987% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3988% dimensions, allocating space for the image pixels and optionally the
3989% colormap indexes, and memory mapping the cache if it is disk based. The
3990% cache nexus array is initialized as well.
3991%
3992% The format of the OpenPixelCache() method is:
3993%
3994% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3995% ExceptionInfo *exception)
3996%
3997% A description of each parameter follows:
3998%
3999% o image: the image.
4000%
4001% o mode: ReadMode, WriteMode, or IOMode.
4002%
4003% o exception: return any errors or warnings in this structure.
4004%
4005*/
4006
cristyd43a46b2010-01-21 02:13:41 +00004007static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00004008{
4009 cache_info->mapped=MagickFalse;
4010 cache_info->pixels=(PixelPacket *) AcquireMagickMemory((size_t)
4011 cache_info->length);
4012 if (cache_info->pixels == (PixelPacket *) NULL)
4013 {
4014 cache_info->mapped=MagickTrue;
4015 cache_info->pixels=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
4016 cache_info->length);
4017 }
4018}
4019
4020static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
4021{
4022 CacheInfo
4023 *cache_info;
4024
4025 MagickOffsetType
4026 count,
4027 extent,
4028 offset;
4029
4030 cache_info=(CacheInfo *) image->cache;
4031 if (image->debug != MagickFalse)
4032 {
4033 char
4034 format[MaxTextExtent],
4035 message[MaxTextExtent];
4036
cristyb9080c92009-12-01 20:13:26 +00004037 (void) FormatMagickSize(length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00004038 (void) FormatMagickString(message,MaxTextExtent,
cristy2ce15c92010-03-12 14:03:41 +00004039 "extend %s (%s[%d], disk, %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00004040 cache_info->cache_filename,cache_info->file,format);
4041 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4042 }
4043 if (length != (MagickSizeType) ((MagickOffsetType) length))
4044 return(MagickFalse);
4045 extent=(MagickOffsetType) MagickSeek(cache_info->file,0,SEEK_END);
4046 if (extent < 0)
4047 return(MagickFalse);
4048 if ((MagickSizeType) extent >= length)
4049 return(MagickTrue);
4050 offset=(MagickOffsetType) length-1;
4051 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
4052 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
4053}
4054
4055static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
4056 ExceptionInfo *exception)
4057{
4058 char
4059 format[MaxTextExtent],
4060 message[MaxTextExtent];
4061
4062 CacheInfo
4063 *cache_info,
4064 source_info;
4065
4066 MagickSizeType
4067 length,
4068 number_pixels;
4069
4070 MagickStatusType
4071 status;
4072
4073 size_t
4074 packet_size;
4075
cristybb503372010-05-27 20:51:26 +00004076 size_t
cristy3ed852e2009-09-05 21:47:34 +00004077 columns;
4078
4079 if (image->debug != MagickFalse)
4080 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4081 if ((image->columns == 0) || (image->rows == 0))
4082 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
4083 cache_info=(CacheInfo *) image->cache;
4084 source_info=(*cache_info);
4085 source_info.file=(-1);
cristye8c25f92010-06-03 00:53:06 +00004086 (void) FormatMagickString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
4087 image->filename,(double) GetImageIndexInList(image));
cristy87528ea2009-09-10 14:53:56 +00004088 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +00004089 cache_info->rows=image->rows;
4090 cache_info->columns=image->columns;
4091 cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
4092 (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
cristy73724512010-04-12 14:43:14 +00004093 if (image->ping != MagickFalse)
4094 {
4095 cache_info->storage_class=image->storage_class;
4096 cache_info->colorspace=image->colorspace;
4097 cache_info->type=PingCache;
4098 cache_info->pixels=(PixelPacket *) NULL;
4099 cache_info->indexes=(IndexPacket *) NULL;
4100 cache_info->length=0;
4101 return(MagickTrue);
4102 }
cristy3ed852e2009-09-05 21:47:34 +00004103 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4104 packet_size=sizeof(PixelPacket);
4105 if (cache_info->active_index_channel != MagickFalse)
4106 packet_size+=sizeof(IndexPacket);
4107 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00004108 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00004109 if (cache_info->columns != columns)
4110 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4111 image->filename);
4112 cache_info->length=length;
4113 status=AcquireMagickResource(AreaResource,cache_info->length);
4114 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4115 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4116 {
4117 status=AcquireMagickResource(MemoryResource,cache_info->length);
4118 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4119 (cache_info->type == MemoryCache))
4120 {
cristyd43a46b2010-01-21 02:13:41 +00004121 AllocatePixelCachePixels(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004122 if (cache_info->pixels == (PixelPacket *) NULL)
4123 cache_info->pixels=source_info.pixels;
4124 else
4125 {
4126 /*
4127 Create memory pixel cache.
4128 */
4129 if (image->debug != MagickFalse)
4130 {
cristy97e7a572009-12-05 15:07:53 +00004131 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004132 format);
cristy3ed852e2009-09-05 21:47:34 +00004133 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004134 "open %s (%s memory, %.20gx%.20g %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00004135 cache_info->mapped != MagickFalse ? "anonymous" : "heap",
cristye8c25f92010-06-03 00:53:06 +00004136 (double) cache_info->columns,(double) cache_info->rows,
4137 format);
cristy3ed852e2009-09-05 21:47:34 +00004138 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4139 message);
4140 }
4141 cache_info->storage_class=image->storage_class;
4142 cache_info->colorspace=image->colorspace;
4143 cache_info->type=MemoryCache;
4144 cache_info->indexes=(IndexPacket *) NULL;
4145 if (cache_info->active_index_channel != MagickFalse)
4146 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4147 number_pixels);
4148 if (source_info.storage_class != UndefinedClass)
4149 {
4150 status|=ClonePixelCachePixels(cache_info,&source_info,
4151 exception);
4152 RelinquishPixelCachePixels(&source_info);
4153 }
4154 return(MagickTrue);
4155 }
4156 }
4157 RelinquishMagickResource(MemoryResource,cache_info->length);
4158 }
4159 /*
4160 Create pixel cache on disk.
4161 */
4162 status=AcquireMagickResource(DiskResource,cache_info->length);
4163 if (status == MagickFalse)
4164 {
4165 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4166 "CacheResourcesExhausted","`%s'",image->filename);
4167 return(MagickFalse);
4168 }
4169 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4170 {
4171 RelinquishMagickResource(DiskResource,cache_info->length);
4172 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4173 image->filename);
4174 return(MagickFalse);
4175 }
4176 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4177 cache_info->length);
4178 if (status == MagickFalse)
4179 {
4180 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4181 image->filename);
4182 return(MagickFalse);
4183 }
4184 cache_info->storage_class=image->storage_class;
4185 cache_info->colorspace=image->colorspace;
4186 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4187 status=AcquireMagickResource(AreaResource,cache_info->length);
4188 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4189 cache_info->type=DiskCache;
4190 else
4191 {
4192 status=AcquireMagickResource(MapResource,cache_info->length);
4193 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4194 (cache_info->type != MemoryCache))
4195 cache_info->type=DiskCache;
4196 else
4197 {
4198 cache_info->pixels=(PixelPacket *) MapBlob(cache_info->file,mode,
4199 cache_info->offset,(size_t) cache_info->length);
4200 if (cache_info->pixels == (PixelPacket *) NULL)
4201 {
4202 cache_info->pixels=source_info.pixels;
4203 cache_info->type=DiskCache;
4204 }
4205 else
4206 {
4207 /*
4208 Create file-backed memory-mapped pixel cache.
4209 */
4210 (void) ClosePixelCacheOnDisk(cache_info);
4211 cache_info->type=MapCache;
4212 cache_info->mapped=MagickTrue;
4213 cache_info->indexes=(IndexPacket *) NULL;
4214 if (cache_info->active_index_channel != MagickFalse)
4215 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4216 number_pixels);
4217 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4218 {
4219 status=ClonePixelCachePixels(cache_info,&source_info,
4220 exception);
4221 RelinquishPixelCachePixels(&source_info);
4222 }
4223 if (image->debug != MagickFalse)
4224 {
cristy97e7a572009-12-05 15:07:53 +00004225 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004226 format);
cristy3ed852e2009-09-05 21:47:34 +00004227 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004228 "open %s (%s[%d], memory-mapped, %.20gx%.20g %sB)",
cristy3ed852e2009-09-05 21:47:34 +00004229 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004230 cache_info->file,(double) cache_info->columns,(double)
4231 cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004232 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4233 message);
4234 }
4235 return(MagickTrue);
4236 }
4237 }
4238 RelinquishMagickResource(MapResource,cache_info->length);
4239 }
4240 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4241 {
4242 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4243 RelinquishPixelCachePixels(&source_info);
4244 }
4245 if (image->debug != MagickFalse)
4246 {
cristyb9080c92009-12-01 20:13:26 +00004247 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00004248 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004249 "open %s (%s[%d], disk, %.20gx%.20g %sB)",cache_info->filename,
4250 cache_info->cache_filename,cache_info->file,(double)
4251 cache_info->columns,(double) cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004252 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4253 }
4254 return(MagickTrue);
4255}
4256
4257/*
4258%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4259% %
4260% %
4261% %
4262+ P e r s i s t P i x e l C a c h e %
4263% %
4264% %
4265% %
4266%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4267%
4268% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4269% persistent pixel cache is one that resides on disk and is not destroyed
4270% when the program exits.
4271%
4272% The format of the PersistPixelCache() method is:
4273%
4274% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4275% const MagickBooleanType attach,MagickOffsetType *offset,
4276% ExceptionInfo *exception)
4277%
4278% A description of each parameter follows:
4279%
4280% o image: the image.
4281%
4282% o filename: the persistent pixel cache filename.
4283%
cristy01b7eb02009-09-10 23:10:14 +00004284% o attach: A value other than zero initializes the persistent pixel
4285% cache.
4286%
cristy3ed852e2009-09-05 21:47:34 +00004287% o initialize: A value other than zero initializes the persistent pixel
4288% cache.
4289%
4290% o offset: the offset in the persistent cache to store pixels.
4291%
4292% o exception: return any errors or warnings in this structure.
4293%
4294*/
4295MagickExport MagickBooleanType PersistPixelCache(Image *image,
4296 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4297 ExceptionInfo *exception)
4298{
4299 CacheInfo
4300 *cache_info,
4301 *clone_info;
4302
4303 Image
4304 clone_image;
4305
cristybb503372010-05-27 20:51:26 +00004306 ssize_t
cristy688f07b2009-09-27 15:19:13 +00004307 page_size;
cristy3ed852e2009-09-05 21:47:34 +00004308
4309 MagickBooleanType
4310 status;
4311
4312 assert(image != (Image *) NULL);
4313 assert(image->signature == MagickSignature);
4314 if (image->debug != MagickFalse)
4315 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4316 assert(image->cache != (void *) NULL);
4317 assert(filename != (const char *) NULL);
4318 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004319 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004320 cache_info=(CacheInfo *) image->cache;
4321 assert(cache_info->signature == MagickSignature);
4322 if (attach != MagickFalse)
4323 {
4324 /*
cristy01b7eb02009-09-10 23:10:14 +00004325 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004326 */
4327 if (image->debug != MagickFalse)
4328 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4329 "attach persistent cache");
4330 (void) CopyMagickString(cache_info->cache_filename,filename,
4331 MaxTextExtent);
4332 cache_info->type=DiskCache;
4333 cache_info->offset=(*offset);
4334 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4335 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004336 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004337 return(MagickTrue);
4338 }
cristy01b7eb02009-09-10 23:10:14 +00004339 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4340 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004341 {
cristyf84a1932010-01-03 18:00:18 +00004342 LockSemaphoreInfo(cache_info->semaphore);
cristy09449f72010-01-23 03:08:36 +00004343 if ((cache_info->mode != ReadMode) &&
4344 (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004345 (cache_info->reference_count == 1))
4346 {
4347 int
4348 status;
4349
4350 /*
cristy01b7eb02009-09-10 23:10:14 +00004351 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004352 */
4353 status=rename(cache_info->cache_filename,filename);
4354 if (status == 0)
4355 {
4356 (void) CopyMagickString(cache_info->cache_filename,filename,
4357 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004358 *offset+=cache_info->length+page_size-(cache_info->length %
4359 page_size);
cristyf84a1932010-01-03 18:00:18 +00004360 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004361 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004362 if (image->debug != MagickFalse)
4363 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4364 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004365 return(MagickTrue);
4366 }
4367 }
cristyf84a1932010-01-03 18:00:18 +00004368 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004369 }
4370 /*
cristy01b7eb02009-09-10 23:10:14 +00004371 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004372 */
4373 clone_image=(*image);
4374 clone_info=(CacheInfo *) clone_image.cache;
4375 image->cache=ClonePixelCache(cache_info);
4376 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4377 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4378 cache_info->type=DiskCache;
4379 cache_info->offset=(*offset);
4380 cache_info=(CacheInfo *) image->cache;
4381 status=ClonePixelCacheNexus(cache_info,clone_info,exception);
4382 if (status != MagickFalse)
4383 {
4384 status=OpenPixelCache(image,IOMode,exception);
4385 if (status != MagickFalse)
4386 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
4387 }
cristy688f07b2009-09-27 15:19:13 +00004388 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004389 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4390 return(status);
4391}
4392
4393/*
4394%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4395% %
4396% %
4397% %
4398+ Q u e u e A u t h e n t i c N e x u s %
4399% %
4400% %
4401% %
4402%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4403%
4404% QueueAuthenticNexus() allocates an region to store image pixels as defined
4405% by the region rectangle and returns a pointer to the region. This region is
4406% subsequently transferred from the pixel cache with
4407% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4408% pixels are transferred, otherwise a NULL is returned.
4409%
4410% The format of the QueueAuthenticNexus() method is:
4411%
cristy5f959472010-05-27 22:19:46 +00004412% PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
4413% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004414% NexusInfo *nexus_info,ExceptionInfo *exception)
4415%
4416% A description of each parameter follows:
4417%
4418% o image: the image.
4419%
4420% o x,y,columns,rows: These values define the perimeter of a region of
4421% pixels.
4422%
4423% o nexus_info: the cache nexus to set.
4424%
4425% o exception: return any errors or warnings in this structure.
4426%
4427*/
cristybb503372010-05-27 20:51:26 +00004428MagickExport PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy30097232010-07-01 02:16:30 +00004429 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
4430 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004431{
4432 CacheInfo
4433 *cache_info;
4434
4435 MagickOffsetType
4436 offset;
4437
4438 MagickSizeType
4439 number_pixels;
4440
4441 RectangleInfo
4442 region;
4443
4444 /*
4445 Validate pixel cache geometry.
4446 */
4447 cache_info=(CacheInfo *) image->cache;
4448 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4449 {
4450 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4451 "NoPixelsDefinedInCache","`%s'",image->filename);
4452 return((PixelPacket *) NULL);
4453 }
cristybb503372010-05-27 20:51:26 +00004454 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4455 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004456 {
4457 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4458 "PixelsAreNotAuthentic","`%s'",image->filename);
4459 return((PixelPacket *) NULL);
4460 }
4461 offset=(MagickOffsetType) y*cache_info->columns+x;
4462 if (offset < 0)
4463 return((PixelPacket *) NULL);
4464 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4465 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4466 if ((MagickSizeType) offset >= number_pixels)
4467 return((PixelPacket *) NULL);
4468 /*
4469 Return pixel cache.
4470 */
4471 region.x=x;
4472 region.y=y;
4473 region.width=columns;
4474 region.height=rows;
4475 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4476}
4477
4478/*
4479%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4480% %
4481% %
4482% %
4483+ 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 %
4484% %
4485% %
4486% %
4487%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4488%
4489% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4490% defined by the region rectangle and returns a pointer to the region. This
4491% region is subsequently transferred from the pixel cache with
4492% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4493% pixels are transferred, otherwise a NULL is returned.
4494%
4495% The format of the QueueAuthenticPixelsCache() method is:
4496%
cristybb503372010-05-27 20:51:26 +00004497% PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4498% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004499% ExceptionInfo *exception)
4500%
4501% A description of each parameter follows:
4502%
4503% o image: the image.
4504%
4505% o x,y,columns,rows: These values define the perimeter of a region of
4506% pixels.
4507%
4508% o exception: return any errors or warnings in this structure.
4509%
4510*/
cristybb503372010-05-27 20:51:26 +00004511static PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4512 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004513 ExceptionInfo *exception)
4514{
4515 CacheInfo
4516 *cache_info;
4517
cristybb503372010-05-27 20:51:26 +00004518 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004519 id;
4520
4521 PixelPacket
4522 *pixels;
4523
4524 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickFalse,exception);
4525 if (cache_info == (Cache) NULL)
4526 return((PixelPacket *) NULL);
4527 id=GetOpenMPThreadId();
cristybb503372010-05-27 20:51:26 +00004528 assert(id < (ssize_t) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00004529 pixels=QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4530 exception);
4531 return(pixels);
4532}
4533
4534/*
4535%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4536% %
4537% %
4538% %
4539% Q u e u e A u t h e n t i c P i x e l s %
4540% %
4541% %
4542% %
4543%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4544%
4545% QueueAuthenticPixels() queues a mutable pixel region. If the region is
4546% successfully intialized a pointer to a PixelPacket array representing the
4547% region is returned, otherwise NULL is returned. The returned pointer may
4548% point to a temporary working buffer for the pixels or it may point to the
4549% final location of the pixels in memory.
4550%
4551% Write-only access means that any existing pixel values corresponding to
4552% the region are ignored. This is useful if the initial image is being
4553% created from scratch, or if the existing pixel values are to be
4554% completely replaced without need to refer to their pre-existing values.
4555% The application is free to read and write the pixel buffer returned by
4556% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4557% initialize the pixel array values. Initializing pixel array values is the
4558% application's responsibility.
4559%
4560% Performance is maximized if the selected region is part of one row, or
4561% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004562% pixels in-place (without a copy) if the image is in memory, or in a
4563% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004564% by the user.
4565%
4566% Pixels accessed via the returned pointer represent a simple array of type
4567% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
4568% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
4569% the black color component or the colormap indexes (of type IndexPacket)
4570% corresponding to the region. Once the PixelPacket (and/or IndexPacket)
4571% array has been updated, the changes must be saved back to the underlying
4572% image using SyncAuthenticPixels() or they may be lost.
4573%
4574% The format of the QueueAuthenticPixels() method is:
4575%
cristy5f959472010-05-27 22:19:46 +00004576% PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4577% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004578% ExceptionInfo *exception)
4579%
4580% A description of each parameter follows:
4581%
4582% o image: the image.
4583%
4584% o x,y,columns,rows: These values define the perimeter of a region of
4585% pixels.
4586%
4587% o exception: return any errors or warnings in this structure.
4588%
4589*/
cristybb503372010-05-27 20:51:26 +00004590MagickExport PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4591 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004592 ExceptionInfo *exception)
4593{
4594 CacheInfo
4595 *cache_info;
4596
4597 PixelPacket
4598 *pixels;
4599
4600 assert(image != (Image *) NULL);
4601 assert(image->signature == MagickSignature);
4602 if (image->debug != MagickFalse)
4603 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4604 assert(image->cache != (Cache) NULL);
4605 cache_info=(CacheInfo *) image->cache;
4606 assert(cache_info->signature == MagickSignature);
4607 if (cache_info->methods.queue_authentic_pixels_handler ==
4608 (QueueAuthenticPixelsHandler) NULL)
4609 return((PixelPacket *) NULL);
4610 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4611 rows,exception);
4612 return(pixels);
4613}
4614
4615/*
4616%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4617% %
4618% %
4619% %
4620+ R e a d P i x e l C a c h e I n d e x e s %
4621% %
4622% %
4623% %
4624%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4625%
4626% ReadPixelCacheIndexes() reads colormap indexes from the specified region of
4627% the pixel cache.
4628%
4629% The format of the ReadPixelCacheIndexes() method is:
4630%
4631% MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4632% NexusInfo *nexus_info,ExceptionInfo *exception)
4633%
4634% A description of each parameter follows:
4635%
4636% o cache_info: the pixel cache.
4637%
4638% o nexus_info: the cache nexus to read the colormap indexes.
4639%
4640% o exception: return any errors or warnings in this structure.
4641%
4642*/
4643static MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4644 NexusInfo *nexus_info,ExceptionInfo *exception)
4645{
4646 MagickOffsetType
4647 count,
4648 offset;
4649
4650 MagickSizeType
4651 length,
4652 number_pixels;
4653
4654 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004655 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004656
cristybb503372010-05-27 20:51:26 +00004657 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004658 y;
4659
cristybb503372010-05-27 20:51:26 +00004660 size_t
cristy3ed852e2009-09-05 21:47:34 +00004661 rows;
4662
4663 if (cache_info->debug != MagickFalse)
4664 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4665 cache_info->filename);
4666 if (cache_info->active_index_channel == MagickFalse)
4667 return(MagickFalse);
4668 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4669 return(MagickTrue);
4670 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4671 nexus_info->region.x;
4672 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
4673 rows=nexus_info->region.height;
4674 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004675 q=nexus_info->indexes;
4676 switch (cache_info->type)
4677 {
4678 case MemoryCache:
4679 case MapCache:
4680 {
4681 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004682 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004683
4684 /*
4685 Read indexes from memory.
4686 */
cristydd341db2010-03-04 19:06:38 +00004687 if ((cache_info->columns == nexus_info->region.width) &&
4688 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4689 {
4690 length=number_pixels;
4691 rows=1UL;
4692 }
cristy3ed852e2009-09-05 21:47:34 +00004693 p=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00004694 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004695 {
4696 (void) CopyMagickMemory(q,p,(size_t) length);
4697 p+=cache_info->columns;
4698 q+=nexus_info->region.width;
4699 }
4700 break;
4701 }
4702 case DiskCache:
4703 {
4704 /*
4705 Read indexes from disk.
4706 */
4707 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4708 {
4709 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4710 cache_info->cache_filename);
4711 return(MagickFalse);
4712 }
cristydd341db2010-03-04 19:06:38 +00004713 if ((cache_info->columns == nexus_info->region.width) &&
4714 (number_pixels < MagickMaxBufferExtent))
4715 {
4716 length=number_pixels;
4717 rows=1UL;
4718 }
cristy3ed852e2009-09-05 21:47:34 +00004719 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004720 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004721 {
4722 count=ReadPixelCacheRegion(cache_info,cache_info->offset+number_pixels*
4723 sizeof(PixelPacket)+offset*sizeof(*q),length,(unsigned char *) q);
4724 if ((MagickSizeType) count < length)
4725 break;
4726 offset+=cache_info->columns;
4727 q+=nexus_info->region.width;
4728 }
cristybb503372010-05-27 20:51:26 +00004729 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004730 {
4731 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4732 cache_info->cache_filename);
4733 return(MagickFalse);
4734 }
4735 break;
4736 }
4737 default:
4738 break;
4739 }
4740 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004741 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004742 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004743 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004744 nexus_info->region.width,(double) nexus_info->region.height,(double)
4745 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004746 return(MagickTrue);
4747}
4748
4749/*
4750%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4751% %
4752% %
4753% %
4754+ R e a d P i x e l C a c h e P i x e l s %
4755% %
4756% %
4757% %
4758%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4759%
4760% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4761% cache.
4762%
4763% The format of the ReadPixelCachePixels() method is:
4764%
4765% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4766% NexusInfo *nexus_info,ExceptionInfo *exception)
4767%
4768% A description of each parameter follows:
4769%
4770% o cache_info: the pixel cache.
4771%
4772% o nexus_info: the cache nexus to read the pixels.
4773%
4774% o exception: return any errors or warnings in this structure.
4775%
4776*/
4777static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4778 NexusInfo *nexus_info,ExceptionInfo *exception)
4779{
4780 MagickOffsetType
4781 count,
4782 offset;
4783
4784 MagickSizeType
4785 length,
4786 number_pixels;
4787
cristybb503372010-05-27 20:51:26 +00004788 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004789 y;
4790
4791 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004792 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004793
cristybb503372010-05-27 20:51:26 +00004794 size_t
cristy3ed852e2009-09-05 21:47:34 +00004795 rows;
4796
4797 if (cache_info->debug != MagickFalse)
4798 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4799 cache_info->filename);
4800 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4801 return(MagickTrue);
4802 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4803 nexus_info->region.x;
4804 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
4805 rows=nexus_info->region.height;
4806 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004807 q=nexus_info->pixels;
4808 switch (cache_info->type)
4809 {
4810 case MemoryCache:
4811 case MapCache:
4812 {
4813 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004814 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004815
4816 /*
4817 Read pixels from memory.
4818 */
cristydd341db2010-03-04 19:06:38 +00004819 if ((cache_info->columns == nexus_info->region.width) &&
4820 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4821 {
4822 length=number_pixels;
4823 rows=1UL;
4824 }
cristy3ed852e2009-09-05 21:47:34 +00004825 p=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00004826 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004827 {
4828 (void) CopyMagickMemory(q,p,(size_t) length);
4829 p+=cache_info->columns;
4830 q+=nexus_info->region.width;
4831 }
4832 break;
4833 }
4834 case DiskCache:
4835 {
4836 /*
4837 Read pixels from disk.
4838 */
4839 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4840 {
4841 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4842 cache_info->cache_filename);
4843 return(MagickFalse);
4844 }
cristydd341db2010-03-04 19:06:38 +00004845 if ((cache_info->columns == nexus_info->region.width) &&
4846 (number_pixels < MagickMaxBufferExtent))
4847 {
4848 length=number_pixels;
4849 rows=1UL;
4850 }
cristybb503372010-05-27 20:51:26 +00004851 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004852 {
4853 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4854 sizeof(*q),length,(unsigned char *) q);
4855 if ((MagickSizeType) count < length)
4856 break;
4857 offset+=cache_info->columns;
4858 q+=nexus_info->region.width;
4859 }
cristybb503372010-05-27 20:51:26 +00004860 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004861 {
4862 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4863 cache_info->cache_filename);
4864 return(MagickFalse);
4865 }
4866 break;
4867 }
4868 default:
4869 break;
4870 }
4871 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004872 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004873 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004874 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004875 nexus_info->region.width,(double) nexus_info->region.height,(double)
4876 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004877 return(MagickTrue);
4878}
4879
4880/*
4881%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4882% %
4883% %
4884% %
4885+ R e f e r e n c e P i x e l C a c h e %
4886% %
4887% %
4888% %
4889%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4890%
4891% ReferencePixelCache() increments the reference count associated with the
4892% pixel cache returning a pointer to the cache.
4893%
4894% The format of the ReferencePixelCache method is:
4895%
4896% Cache ReferencePixelCache(Cache cache_info)
4897%
4898% A description of each parameter follows:
4899%
4900% o cache_info: the pixel cache.
4901%
4902*/
4903MagickExport Cache ReferencePixelCache(Cache cache)
4904{
4905 CacheInfo
4906 *cache_info;
4907
4908 assert(cache != (Cache *) NULL);
4909 cache_info=(CacheInfo *) cache;
4910 assert(cache_info->signature == MagickSignature);
4911 if (cache_info->debug != MagickFalse)
4912 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4913 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00004914 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004915 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004916 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004917 return(cache_info);
4918}
4919
4920/*
4921%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4922% %
4923% %
4924% %
4925+ S e t P i x e l C a c h e M e t h o d s %
4926% %
4927% %
4928% %
4929%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4930%
4931% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4932%
4933% The format of the SetPixelCacheMethods() method is:
4934%
4935% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4936%
4937% A description of each parameter follows:
4938%
4939% o cache: the pixel cache.
4940%
4941% o cache_methods: Specifies a pointer to a CacheMethods structure.
4942%
4943*/
4944MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4945{
4946 CacheInfo
4947 *cache_info;
4948
4949 GetOneAuthenticPixelFromHandler
4950 get_one_authentic_pixel_from_handler;
4951
4952 GetOneVirtualPixelFromHandler
4953 get_one_virtual_pixel_from_handler;
4954
4955 /*
4956 Set cache pixel methods.
4957 */
4958 assert(cache != (Cache) NULL);
4959 assert(cache_methods != (CacheMethods *) NULL);
4960 cache_info=(CacheInfo *) cache;
4961 assert(cache_info->signature == MagickSignature);
4962 if (cache_info->debug != MagickFalse)
4963 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4964 cache_info->filename);
4965 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4966 cache_info->methods.get_virtual_pixel_handler=
4967 cache_methods->get_virtual_pixel_handler;
4968 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4969 cache_info->methods.destroy_pixel_handler=
4970 cache_methods->destroy_pixel_handler;
4971 if (cache_methods->get_virtual_indexes_from_handler !=
4972 (GetVirtualIndexesFromHandler) NULL)
4973 cache_info->methods.get_virtual_indexes_from_handler=
4974 cache_methods->get_virtual_indexes_from_handler;
4975 if (cache_methods->get_authentic_pixels_handler !=
4976 (GetAuthenticPixelsHandler) NULL)
4977 cache_info->methods.get_authentic_pixels_handler=
4978 cache_methods->get_authentic_pixels_handler;
4979 if (cache_methods->queue_authentic_pixels_handler !=
4980 (QueueAuthenticPixelsHandler) NULL)
4981 cache_info->methods.queue_authentic_pixels_handler=
4982 cache_methods->queue_authentic_pixels_handler;
4983 if (cache_methods->sync_authentic_pixels_handler !=
4984 (SyncAuthenticPixelsHandler) NULL)
4985 cache_info->methods.sync_authentic_pixels_handler=
4986 cache_methods->sync_authentic_pixels_handler;
4987 if (cache_methods->get_authentic_pixels_from_handler !=
4988 (GetAuthenticPixelsFromHandler) NULL)
4989 cache_info->methods.get_authentic_pixels_from_handler=
4990 cache_methods->get_authentic_pixels_from_handler;
4991 if (cache_methods->get_authentic_indexes_from_handler !=
4992 (GetAuthenticIndexesFromHandler) NULL)
4993 cache_info->methods.get_authentic_indexes_from_handler=
4994 cache_methods->get_authentic_indexes_from_handler;
4995 get_one_virtual_pixel_from_handler=
4996 cache_info->methods.get_one_virtual_pixel_from_handler;
4997 if (get_one_virtual_pixel_from_handler !=
4998 (GetOneVirtualPixelFromHandler) NULL)
4999 cache_info->methods.get_one_virtual_pixel_from_handler=
5000 cache_methods->get_one_virtual_pixel_from_handler;
5001 get_one_authentic_pixel_from_handler=
5002 cache_methods->get_one_authentic_pixel_from_handler;
5003 if (get_one_authentic_pixel_from_handler !=
5004 (GetOneAuthenticPixelFromHandler) NULL)
5005 cache_info->methods.get_one_authentic_pixel_from_handler=
5006 cache_methods->get_one_authentic_pixel_from_handler;
5007}
5008
5009/*
5010%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5011% %
5012% %
5013% %
5014+ S e t P i x e l C a c h e N e x u s P i x e l s %
5015% %
5016% %
5017% %
5018%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5019%
5020% SetPixelCacheNexusPixels() defines the region of the cache for the
5021% specified cache nexus.
5022%
5023% The format of the SetPixelCacheNexusPixels() method is:
5024%
5025% PixelPacket SetPixelCacheNexusPixels(const Image *image,
5026% const RectangleInfo *region,NexusInfo *nexus_info,
5027% ExceptionInfo *exception)
5028%
5029% A description of each parameter follows:
5030%
5031% o image: the image.
5032%
5033% o region: A pointer to the RectangleInfo structure that defines the
5034% region of this particular cache nexus.
5035%
5036% o nexus_info: the cache nexus to set.
5037%
5038% o exception: return any errors or warnings in this structure.
5039%
5040*/
5041static PixelPacket *SetPixelCacheNexusPixels(const Image *image,
5042 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
5043{
5044 CacheInfo
5045 *cache_info;
5046
5047 MagickBooleanType
5048 status;
5049
cristy3ed852e2009-09-05 21:47:34 +00005050 MagickSizeType
5051 length,
5052 number_pixels;
5053
5054 if (image->debug != MagickFalse)
5055 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5056 cache_info=(CacheInfo *) image->cache;
5057 assert(cache_info->signature == MagickSignature);
5058 if (cache_info->type == UndefinedCache)
5059 return((PixelPacket *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00005060 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00005061 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
5062 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00005063 {
cristybb503372010-05-27 20:51:26 +00005064 ssize_t
cristybad067a2010-02-15 17:20:55 +00005065 x,
5066 y;
cristy3ed852e2009-09-05 21:47:34 +00005067
cristyeaedf062010-05-29 22:36:02 +00005068 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
5069 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00005070 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5071 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristy731c3532010-02-15 15:40:03 +00005072 ((nexus_info->region.height == 1UL) ||
5073 ((nexus_info->region.x == 0) &&
5074 ((nexus_info->region.width == cache_info->columns) ||
5075 ((nexus_info->region.width % cache_info->columns) == 0)))))
5076 {
5077 MagickOffsetType
5078 offset;
5079
5080 /*
5081 Pixels are accessed directly from memory.
5082 */
5083 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5084 nexus_info->region.x;
5085 nexus_info->pixels=cache_info->pixels+offset;
5086 nexus_info->indexes=(IndexPacket *) NULL;
5087 if (cache_info->active_index_channel != MagickFalse)
5088 nexus_info->indexes=cache_info->indexes+offset;
5089 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00005090 }
5091 }
5092 /*
5093 Pixels are stored in a cache region until they are synced to the cache.
5094 */
5095 number_pixels=(MagickSizeType) nexus_info->region.width*
5096 nexus_info->region.height;
5097 length=number_pixels*sizeof(PixelPacket);
5098 if (cache_info->active_index_channel != MagickFalse)
5099 length+=number_pixels*sizeof(IndexPacket);
5100 if (nexus_info->cache == (PixelPacket *) NULL)
5101 {
5102 nexus_info->length=length;
5103 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5104 if (status == MagickFalse)
5105 return((PixelPacket *) NULL);
5106 }
5107 else
5108 if (nexus_info->length != length)
5109 {
5110 RelinquishCacheNexusPixels(nexus_info);
5111 nexus_info->length=length;
5112 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5113 if (status == MagickFalse)
5114 return((PixelPacket *) NULL);
5115 }
5116 nexus_info->pixels=nexus_info->cache;
5117 nexus_info->indexes=(IndexPacket *) NULL;
5118 if (cache_info->active_index_channel != MagickFalse)
5119 nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
5120 return(nexus_info->pixels);
5121}
5122
5123/*
5124%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5125% %
5126% %
5127% %
5128% 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 %
5129% %
5130% %
5131% %
5132%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5133%
5134% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5135% pixel cache and returns the previous setting. A virtual pixel is any pixel
5136% access that is outside the boundaries of the image cache.
5137%
5138% The format of the SetPixelCacheVirtualMethod() method is:
5139%
5140% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5141% const VirtualPixelMethod virtual_pixel_method)
5142%
5143% A description of each parameter follows:
5144%
5145% o image: the image.
5146%
5147% o virtual_pixel_method: choose the type of virtual pixel.
5148%
5149*/
5150MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5151 const VirtualPixelMethod virtual_pixel_method)
5152{
5153 CacheInfo
5154 *cache_info;
5155
5156 VirtualPixelMethod
5157 method;
5158
5159 assert(image != (Image *) NULL);
5160 assert(image->signature == MagickSignature);
5161 if (image->debug != MagickFalse)
5162 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5163 assert(image->cache != (Cache) NULL);
5164 cache_info=(CacheInfo *) image->cache;
5165 assert(cache_info->signature == MagickSignature);
5166 method=cache_info->virtual_pixel_method;
5167 cache_info->virtual_pixel_method=virtual_pixel_method;
5168 return(method);
5169}
5170
5171/*
5172%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5173% %
5174% %
5175% %
5176+ 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 %
5177% %
5178% %
5179% %
5180%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5181%
5182% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5183% in-memory or disk cache. The method returns MagickTrue if the pixel region
5184% is synced, otherwise MagickFalse.
5185%
5186% The format of the SyncAuthenticPixelCacheNexus() method is:
5187%
5188% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5189% NexusInfo *nexus_info,ExceptionInfo *exception)
5190%
5191% A description of each parameter follows:
5192%
5193% o image: the image.
5194%
5195% o nexus_info: the cache nexus to sync.
5196%
5197% o exception: return any errors or warnings in this structure.
5198%
5199*/
5200MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5201 NexusInfo *nexus_info,ExceptionInfo *exception)
5202{
5203 CacheInfo
5204 *cache_info;
5205
5206 MagickBooleanType
5207 status;
5208
5209 /*
5210 Transfer pixels to the cache.
5211 */
5212 assert(image != (Image *) NULL);
5213 assert(image->signature == MagickSignature);
5214 if (image->debug != MagickFalse)
5215 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5216 if (image->cache == (Cache) NULL)
5217 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5218 cache_info=(CacheInfo *) image->cache;
5219 if (cache_info->type == UndefinedCache)
5220 return(MagickFalse);
5221 if ((image->clip_mask != (Image *) NULL) &&
5222 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5223 return(MagickFalse);
5224 if ((image->mask != (Image *) NULL) &&
5225 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5226 return(MagickFalse);
5227 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5228 return(MagickTrue);
5229 assert(cache_info->signature == MagickSignature);
5230 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5231 if ((cache_info->active_index_channel != MagickFalse) &&
5232 (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
5233 return(MagickFalse);
5234 return(status);
5235}
5236
5237/*
5238%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5239% %
5240% %
5241% %
5242+ S y n c A u t h e n t i c P i x e l C a c h e %
5243% %
5244% %
5245% %
5246%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5247%
5248% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5249% or disk cache. The method returns MagickTrue if the pixel region is synced,
5250% otherwise MagickFalse.
5251%
5252% The format of the SyncAuthenticPixelsCache() method is:
5253%
5254% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5255% ExceptionInfo *exception)
5256%
5257% A description of each parameter follows:
5258%
5259% o image: the image.
5260%
5261% o exception: return any errors or warnings in this structure.
5262%
5263*/
5264static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5265 ExceptionInfo *exception)
5266{
5267 CacheInfo
5268 *cache_info;
5269
cristybb503372010-05-27 20:51:26 +00005270 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005271 id;
5272
5273 MagickBooleanType
5274 status;
5275
5276 cache_info=(CacheInfo *) image->cache;
5277 id=GetOpenMPThreadId();
cristybb503372010-05-27 20:51:26 +00005278 assert(id < (ssize_t) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00005279 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5280 exception);
5281 return(status);
5282}
5283
5284/*
5285%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5286% %
5287% %
5288% %
5289% S y n c A u t h e n t i c P i x e l s %
5290% %
5291% %
5292% %
5293%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5294%
5295% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5296% The method returns MagickTrue if the pixel region is flushed, otherwise
5297% MagickFalse.
5298%
5299% The format of the SyncAuthenticPixels() method is:
5300%
5301% MagickBooleanType SyncAuthenticPixels(Image *image,
5302% ExceptionInfo *exception)
5303%
5304% A description of each parameter follows:
5305%
5306% o image: the image.
5307%
5308% o exception: return any errors or warnings in this structure.
5309%
5310*/
5311MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5312 ExceptionInfo *exception)
5313{
5314 CacheInfo
5315 *cache_info;
5316
5317 assert(image != (Image *) NULL);
5318 assert(image->signature == MagickSignature);
5319 if (image->debug != MagickFalse)
5320 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5321 assert(image->cache != (Cache) NULL);
5322 cache_info=(CacheInfo *) image->cache;
5323 assert(cache_info->signature == MagickSignature);
5324 if (cache_info->methods.sync_authentic_pixels_handler ==
5325 (SyncAuthenticPixelsHandler) NULL)
5326 return(MagickFalse);
5327 return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
5328}
5329
5330/*
5331%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5332% %
5333% %
5334% %
5335+ W r i t e P i x e l C a c h e I n d e x e s %
5336% %
5337% %
5338% %
5339%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5340%
5341% WritePixelCacheIndexes() writes the colormap indexes to the specified
5342% region of the pixel cache.
5343%
5344% The format of the WritePixelCacheIndexes() method is:
5345%
5346% MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5347% NexusInfo *nexus_info,ExceptionInfo *exception)
5348%
5349% A description of each parameter follows:
5350%
5351% o cache_info: the pixel cache.
5352%
5353% o nexus_info: the cache nexus to write the colormap indexes.
5354%
5355% o exception: return any errors or warnings in this structure.
5356%
5357*/
5358static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5359 NexusInfo *nexus_info,ExceptionInfo *exception)
5360{
5361 MagickOffsetType
5362 count,
5363 offset;
5364
5365 MagickSizeType
5366 length,
5367 number_pixels;
5368
5369 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005370 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005371
cristybb503372010-05-27 20:51:26 +00005372 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005373 y;
5374
cristybb503372010-05-27 20:51:26 +00005375 size_t
cristy3ed852e2009-09-05 21:47:34 +00005376 rows;
5377
5378 if (cache_info->debug != MagickFalse)
5379 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
5380 cache_info->filename);
5381 if (cache_info->active_index_channel == MagickFalse)
5382 return(MagickFalse);
5383 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5384 return(MagickTrue);
5385 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5386 nexus_info->region.x;
5387 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
5388 rows=nexus_info->region.height;
5389 number_pixels=(MagickSizeType) length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005390 p=nexus_info->indexes;
5391 switch (cache_info->type)
5392 {
5393 case MemoryCache:
5394 case MapCache:
5395 {
5396 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005397 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005398
5399 /*
5400 Write indexes to memory.
5401 */
cristydd341db2010-03-04 19:06:38 +00005402 if ((cache_info->columns == nexus_info->region.width) &&
5403 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5404 {
5405 length=number_pixels;
5406 rows=1UL;
5407 }
cristy3ed852e2009-09-05 21:47:34 +00005408 q=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00005409 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005410 {
5411 (void) CopyMagickMemory(q,p,(size_t) length);
5412 p+=nexus_info->region.width;
5413 q+=cache_info->columns;
5414 }
5415 break;
5416 }
5417 case DiskCache:
5418 {
5419 /*
5420 Write indexes to disk.
5421 */
5422 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5423 {
5424 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5425 cache_info->cache_filename);
5426 return(MagickFalse);
5427 }
cristydd341db2010-03-04 19:06:38 +00005428 if ((cache_info->columns == nexus_info->region.width) &&
5429 (number_pixels < MagickMaxBufferExtent))
5430 {
5431 length=number_pixels;
5432 rows=1UL;
5433 }
cristy3ed852e2009-09-05 21:47:34 +00005434 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005435 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005436 {
5437 count=WritePixelCacheRegion(cache_info,cache_info->offset+number_pixels*
5438 sizeof(PixelPacket)+offset*sizeof(*p),length,
5439 (const unsigned char *) p);
5440 if ((MagickSizeType) count < length)
5441 break;
5442 p+=nexus_info->region.width;
5443 offset+=cache_info->columns;
5444 }
cristybb503372010-05-27 20:51:26 +00005445 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005446 {
5447 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5448 cache_info->cache_filename);
5449 return(MagickFalse);
5450 }
5451 break;
5452 }
5453 default:
5454 break;
5455 }
5456 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005457 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005458 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005459 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005460 nexus_info->region.width,(double) nexus_info->region.height,(double)
5461 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005462 return(MagickTrue);
5463}
5464
5465/*
5466%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5467% %
5468% %
5469% %
5470+ W r i t e C a c h e P i x e l s %
5471% %
5472% %
5473% %
5474%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5475%
5476% WritePixelCachePixels() writes image pixels to the specified region of the
5477% pixel cache.
5478%
5479% The format of the WritePixelCachePixels() method is:
5480%
5481% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5482% NexusInfo *nexus_info,ExceptionInfo *exception)
5483%
5484% A description of each parameter follows:
5485%
5486% o cache_info: the pixel cache.
5487%
5488% o nexus_info: the cache nexus to write the pixels.
5489%
5490% o exception: return any errors or warnings in this structure.
5491%
5492*/
5493static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5494 NexusInfo *nexus_info,ExceptionInfo *exception)
5495{
5496 MagickOffsetType
5497 count,
5498 offset;
5499
5500 MagickSizeType
5501 length,
5502 number_pixels;
5503
cristy3ed852e2009-09-05 21:47:34 +00005504 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005505 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005506
cristybb503372010-05-27 20:51:26 +00005507 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005508 y;
5509
cristybb503372010-05-27 20:51:26 +00005510 size_t
cristy3ed852e2009-09-05 21:47:34 +00005511 rows;
5512
5513 if (cache_info->debug != MagickFalse)
5514 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
5515 cache_info->filename);
5516 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5517 return(MagickTrue);
5518 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5519 nexus_info->region.x;
5520 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
5521 rows=nexus_info->region.height;
5522 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005523 p=nexus_info->pixels;
5524 switch (cache_info->type)
5525 {
5526 case MemoryCache:
5527 case MapCache:
5528 {
5529 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005530 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005531
5532 /*
5533 Write pixels to memory.
5534 */
cristydd341db2010-03-04 19:06:38 +00005535 if ((cache_info->columns == nexus_info->region.width) &&
5536 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5537 {
5538 length=number_pixels;
5539 rows=1UL;
5540 }
cristy3ed852e2009-09-05 21:47:34 +00005541 q=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00005542 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005543 {
5544 (void) CopyMagickMemory(q,p,(size_t) length);
5545 p+=nexus_info->region.width;
5546 q+=cache_info->columns;
5547 }
5548 break;
5549 }
5550 case DiskCache:
5551 {
5552 /*
5553 Write pixels to disk.
5554 */
5555 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5556 {
5557 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5558 cache_info->cache_filename);
5559 return(MagickFalse);
5560 }
cristydd341db2010-03-04 19:06:38 +00005561 if ((cache_info->columns == nexus_info->region.width) &&
5562 (number_pixels < MagickMaxBufferExtent))
5563 {
5564 length=number_pixels;
5565 rows=1UL;
5566 }
cristybb503372010-05-27 20:51:26 +00005567 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005568 {
5569 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5570 sizeof(*p),length,(const unsigned char *) p);
5571 if ((MagickSizeType) count < length)
5572 break;
5573 p+=nexus_info->region.width;
5574 offset+=cache_info->columns;
5575 }
cristybb503372010-05-27 20:51:26 +00005576 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005577 {
5578 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5579 cache_info->cache_filename);
5580 return(MagickFalse);
5581 }
5582 break;
5583 }
5584 default:
5585 break;
5586 }
5587 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005588 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005589 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005590 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005591 nexus_info->region.width,(double) nexus_info->region.height,(double)
5592 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005593 return(MagickTrue);
5594}