blob: 7da1c951496c801981e875946a8e9ffaad808cc6 [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"
cristya21afde2010-07-02 00:45:40 +000059#include "magick/policy.h"
cristy3ed852e2009-09-05 21:47:34 +000060#include "magick/quantum.h"
61#include "magick/random_.h"
62#include "magick/resource_.h"
63#include "magick/semaphore.h"
64#include "magick/splay-tree.h"
65#include "magick/string_.h"
cristya21afde2010-07-02 00:45:40 +000066#include "magick/string-private.h"
cristy3ed852e2009-09-05 21:47:34 +000067#include "magick/thread-private.h"
68#include "magick/utility.h"
69#if defined(MAGICKCORE_ZLIB_DELEGATE)
70#include "zlib.h"
71#endif
72
73/*
cristy30097232010-07-01 02:16:30 +000074 Define declarations.
75*/
76#define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
77
78/*
cristy3ed852e2009-09-05 21:47:34 +000079 Typedef declarations.
80*/
81typedef struct _MagickModulo
82{
cristybb503372010-05-27 20:51:26 +000083 ssize_t
cristy3ed852e2009-09-05 21:47:34 +000084 quotient,
85 remainder;
86} MagickModulo;
87
88struct _NexusInfo
89{
90 MagickBooleanType
91 mapped;
92
93 RectangleInfo
94 region;
95
96 MagickSizeType
97 length;
98
99 PixelPacket
100 *cache,
101 *pixels;
102
103 IndexPacket
104 *indexes;
105
cristybb503372010-05-27 20:51:26 +0000106 size_t
cristy3ed852e2009-09-05 21:47:34 +0000107 signature;
108};
109
110/*
111 Forward declarations.
112*/
113#if defined(__cplusplus) || defined(c_plusplus)
114extern "C" {
115#endif
116
117static const IndexPacket
118 *GetVirtualIndexesFromCache(const Image *);
119
120static const PixelPacket
cristybb503372010-05-27 20:51:26 +0000121 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
122 const ssize_t,const size_t,const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000123 *GetVirtualPixelsCache(const Image *);
124
125static MagickBooleanType
cristy09c1c4d2010-06-30 18:23:16 +0000126 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,
127 PixelPacket *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000128 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
cristybb503372010-05-27 20:51:26 +0000129 const ssize_t,const ssize_t,PixelPacket *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000130 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
131 ReadPixelCacheIndexes(CacheInfo *,NexusInfo *,ExceptionInfo *),
132 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
133 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
134 WritePixelCacheIndexes(CacheInfo *,NexusInfo *,ExceptionInfo *),
135 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
136
137static PixelPacket
cristybb503372010-05-27 20:51:26 +0000138 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
139 const size_t,ExceptionInfo *),
140 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
141 const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000142 *SetPixelCacheNexusPixels(const Image *,const RectangleInfo *,NexusInfo *,
cristya4af2e32010-03-08 00:51:56 +0000143 ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +0000144
145#if defined(__cplusplus) || defined(c_plusplus)
146}
147#endif
148
149/*
150 Global declarations.
151*/
152static volatile MagickBooleanType
153 instantiate_cache = MagickFalse;
154
155static SemaphoreInfo
156 *cache_semaphore = (SemaphoreInfo *) NULL;
157
158static SplayTreeInfo
159 *cache_resources = (SplayTreeInfo *) NULL;
cristy3ed852e2009-09-05 21:47:34 +0000160
161/*
162%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
163% %
164% %
165% %
166+ A c q u i r e P i x e l C a c h e %
167% %
168% %
169% %
170%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
171%
172% AcquirePixelCache() acquires a pixel cache.
173%
174% The format of the AcquirePixelCache() method is:
175%
cristybb503372010-05-27 20:51:26 +0000176% Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000177%
178% A description of each parameter follows:
179%
180% o number_threads: the number of nexus threads.
181%
182*/
cristybb503372010-05-27 20:51:26 +0000183MagickExport Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000184{
185 CacheInfo
186 *cache_info;
187
188 cache_info=(CacheInfo *) AcquireAlignedMemory(1,sizeof(*cache_info));
189 if (cache_info == (CacheInfo *) NULL)
190 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
191 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
192 cache_info->type=UndefinedCache;
cristy87528ea2009-09-10 14:53:56 +0000193 cache_info->mode=IOMode;
cristy3ed852e2009-09-05 21:47:34 +0000194 cache_info->colorspace=RGBColorspace;
195 cache_info->file=(-1);
196 cache_info->id=GetMagickThreadId();
197 cache_info->number_threads=number_threads;
198 if (number_threads == 0)
199 cache_info->number_threads=GetOpenMPMaximumThreads();
200 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
201 if (cache_info->nexus_info == (NexusInfo **) NULL)
202 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
203 GetPixelCacheMethods(&cache_info->methods);
204 cache_info->reference_count=1;
205 cache_info->semaphore=AllocateSemaphoreInfo();
206 cache_info->disk_semaphore=AllocateSemaphoreInfo();
207 cache_info->debug=IsEventLogging();
208 cache_info->signature=MagickSignature;
209 if ((cache_resources == (SplayTreeInfo *) NULL) &&
210 (instantiate_cache == MagickFalse))
211 {
cristy4e1dff62009-10-25 20:36:03 +0000212 if (cache_semaphore == (SemaphoreInfo *) NULL)
213 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000214 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000215 if ((cache_resources == (SplayTreeInfo *) NULL) &&
216 (instantiate_cache == MagickFalse))
217 {
218 cache_resources=NewSplayTree((int (*)(const void *,const void *))
219 NULL,(void *(*)(void *)) NULL,(void *(*)(void *)) NULL);
220 instantiate_cache=MagickTrue;
221 }
cristyf84a1932010-01-03 18:00:18 +0000222 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000223 }
224 (void) AddValueToSplayTree(cache_resources,cache_info,cache_info);
225 return((Cache ) cache_info);
226}
227
228/*
229%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
230% %
231% %
232% %
233% A c q u i r e P i x e l C a c h e N e x u s %
234% %
235% %
236% %
237%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
238%
239% AcquirePixelCacheNexus() allocates the NexusInfo structure.
240%
241% The format of the AcquirePixelCacheNexus method is:
242%
cristybb503372010-05-27 20:51:26 +0000243% NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000244%
245% A description of each parameter follows:
246%
247% o number_threads: the number of nexus threads.
248%
249*/
250MagickExport NexusInfo **AcquirePixelCacheNexus(
cristybb503372010-05-27 20:51:26 +0000251 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000252{
cristybb503372010-05-27 20:51:26 +0000253 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000254 i;
255
256 NexusInfo
257 **nexus_info;
258
259 nexus_info=(NexusInfo **) AcquireAlignedMemory(number_threads,
260 sizeof(*nexus_info));
261 if (nexus_info == (NexusInfo **) NULL)
262 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristybb503372010-05-27 20:51:26 +0000263 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000264 {
265 nexus_info[i]=(NexusInfo *) AcquireAlignedMemory(1,sizeof(**nexus_info));
266 if (nexus_info[i] == (NexusInfo *) NULL)
267 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
268 (void) ResetMagickMemory(nexus_info[i],0,sizeof(*nexus_info[i]));
269 nexus_info[i]->signature=MagickSignature;
270 }
271 return(nexus_info);
272}
273
274/*
275%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
276% %
277% %
278% %
cristyd43a46b2010-01-21 02:13:41 +0000279+ A c q u i r e P i x e l C a c h e P i x e l s %
280% %
281% %
282% %
283%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
284%
285% AcquirePixelCachePixels() returns the pixels associated with the specified
286% image.
287%
288% The format of the AcquirePixelCachePixels() method is:
289%
290% const void *AcquirePixelCachePixels(const Image *image,
291% MagickSizeType *length,ExceptionInfo *exception)
292%
293% A description of each parameter follows:
294%
295% o image: the image.
296%
297% o length: the pixel cache length.
298%
299% o exception: return any errors or warnings in this structure.
300%
301*/
302MagickExport const void *AcquirePixelCachePixels(const Image *image,
303 MagickSizeType *length,ExceptionInfo *exception)
304{
305 CacheInfo
306 *cache_info;
307
308 assert(image != (const Image *) NULL);
309 assert(image->signature == MagickSignature);
310 if (image->debug != MagickFalse)
311 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
312 assert(exception != (ExceptionInfo *) NULL);
313 assert(exception->signature == MagickSignature);
314 assert(image->cache != (Cache) NULL);
315 cache_info=(CacheInfo *) image->cache;
316 assert(cache_info->signature == MagickSignature);
317 *length=0;
318 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
319 return((const void *) NULL);
320 *length=cache_info->length;
321 return((const void *) cache_info->pixels);
322}
323
324/*
325%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
326% %
327% %
328% %
cristyf34a1452009-10-24 22:29:27 +0000329+ C a c h e C o m p o n e n t G e n e s i s %
330% %
331% %
332% %
333%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
334%
335% CacheComponentGenesis() instantiates the cache component.
336%
337% The format of the CacheComponentGenesis method is:
338%
339% MagickBooleanType CacheComponentGenesis(void)
340%
341*/
342MagickExport MagickBooleanType CacheComponentGenesis(void)
343{
cristy165b6092009-10-26 13:52:10 +0000344 AcquireSemaphoreInfo(&cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000345 return(MagickTrue);
346}
347
348/*
349%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
350% %
351% %
352% %
353+ C a c h e C o m p o n e n t T e r m i n u s %
354% %
355% %
356% %
357%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
358%
359% CacheComponentTerminus() destroys the cache component.
360%
361% The format of the CacheComponentTerminus() method is:
362%
363% CacheComponentTerminus(void)
364%
365*/
366MagickExport void CacheComponentTerminus(void)
367{
cristy18b17442009-10-25 18:36:48 +0000368 if (cache_semaphore == (SemaphoreInfo *) NULL)
369 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000370 LockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000371 if (cache_resources != (SplayTreeInfo *) NULL)
372 cache_resources=DestroySplayTree(cache_resources);
373 instantiate_cache=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +0000374 UnlockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000375 DestroySemaphoreInfo(&cache_semaphore);
376}
377
378/*
379%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
380% %
381% %
382% %
cristy3ed852e2009-09-05 21:47:34 +0000383+ C l i p P i x e l C a c h e N e x u s %
384% %
385% %
386% %
387%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
388%
389% ClipPixelCacheNexus() clips the cache nexus as defined by the image clip
390% mask. The method returns MagickTrue if the pixel region is clipped,
391% otherwise MagickFalse.
392%
393% The format of the ClipPixelCacheNexus() method is:
394%
395% MagickBooleanType ClipPixelCacheNexus(Image *image,NexusInfo *nexus_info,
396% ExceptionInfo *exception)
397%
398% A description of each parameter follows:
399%
400% o image: the image.
401%
402% o nexus_info: the cache nexus to clip.
403%
404% o exception: return any errors or warnings in this structure.
405%
406*/
407static MagickBooleanType ClipPixelCacheNexus(Image *image,
408 NexusInfo *nexus_info,ExceptionInfo *exception)
409{
410 CacheInfo
411 *cache_info;
412
413 MagickSizeType
414 number_pixels;
415
416 NexusInfo
417 **clip_nexus,
418 **image_nexus;
419
420 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000421 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +0000422
423 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +0000424 *restrict nexus_indexes,
425 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +0000426
cristybb503372010-05-27 20:51:26 +0000427 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000428 i;
429
430 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000431 *restrict p,
432 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000433
434 /*
435 Apply clip mask.
436 */
437 if (image->debug != MagickFalse)
438 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
439 if (image->clip_mask == (Image *) NULL)
440 return(MagickFalse);
441 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
442 if (cache_info == (Cache) NULL)
443 return(MagickFalse);
444 image_nexus=AcquirePixelCacheNexus(1);
445 clip_nexus=AcquirePixelCacheNexus(1);
446 if ((image_nexus == (NexusInfo **) NULL) ||
447 (clip_nexus == (NexusInfo **) NULL))
448 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
449 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,nexus_info->region.y,
450 nexus_info->region.width,nexus_info->region.height,image_nexus[0],
451 exception);
452 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
453 q=nexus_info->pixels;
454 nexus_indexes=nexus_info->indexes;
455 r=GetVirtualPixelsFromNexus(image->clip_mask,MaskVirtualPixelMethod,
456 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
457 nexus_info->region.height,clip_nexus[0],exception);
458 number_pixels=(MagickSizeType) nexus_info->region.width*
459 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +0000460 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000461 {
462 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
463 break;
464 if (PixelIntensityToQuantum(r) > ((Quantum) QuantumRange/2))
465 {
cristyce70c172010-01-07 17:15:30 +0000466 SetRedPixelComponent(q,GetRedPixelComponent(p));
467 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
468 SetBluePixelComponent(q,GetBluePixelComponent(p));
469 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
cristy3ed852e2009-09-05 21:47:34 +0000470 if (cache_info->active_index_channel != MagickFalse)
471 nexus_indexes[i]=indexes[i];
472 }
473 p++;
474 q++;
475 r++;
476 }
477 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
478 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +0000479 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +0000480 return(MagickFalse);
481 return(MagickTrue);
482}
483
484/*
485%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
486% %
487% %
488% %
489+ C l o n e P i x e l C a c h e %
490% %
491% %
492% %
493%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
494%
495% ClonePixelCache() clones a pixel cache.
496%
497% The format of the ClonePixelCache() method is:
498%
499% Cache ClonePixelCache(const Cache cache)
500%
501% A description of each parameter follows:
502%
503% o cache: the pixel cache.
504%
505*/
506MagickExport Cache ClonePixelCache(const Cache cache)
507{
508 CacheInfo
509 *clone_info;
510
511 const CacheInfo
512 *cache_info;
513
514 assert(cache != (const Cache) NULL);
515 cache_info=(const CacheInfo *) cache;
516 assert(cache_info->signature == MagickSignature);
517 if (cache_info->debug != MagickFalse)
518 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
519 cache_info->filename);
520 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
521 if (clone_info == (Cache) NULL)
522 return((Cache) NULL);
523 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
524 return((Cache ) clone_info);
525}
526
527/*
528%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
529% %
530% %
531% %
532+ C l o n e P i x e l C a c h e N e x u s %
533% %
534% %
535% %
536%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
537%
538% ClonePixelCacheNexus() clones the source cache nexus to the destination
539% nexus.
540%
541% The format of the ClonePixelCacheNexus() method is:
542%
543% MagickBooleanType ClonePixelCacheNexus(CacheInfo *destination,
544% CacheInfo *source,ExceptionInfo *exception)
545%
546% A description of each parameter follows:
547%
548% o destination: the destination cache nexus.
549%
550% o source: the source cache nexus.
551%
552% o exception: return any errors or warnings in this structure.
553%
554*/
555
556static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
557 NexusInfo *nexus_info,ExceptionInfo *exception)
558{
559 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
560 return(MagickFalse);
561 nexus_info->mapped=MagickFalse;
562 nexus_info->cache=(PixelPacket *) AcquireMagickMemory((size_t)
563 nexus_info->length);
564 if (nexus_info->cache == (PixelPacket *) NULL)
565 {
566 nexus_info->mapped=MagickTrue;
567 nexus_info->cache=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
568 nexus_info->length);
569 }
570 if (nexus_info->cache == (PixelPacket *) NULL)
571 {
572 (void) ThrowMagickException(exception,GetMagickModule(),
573 ResourceLimitError,"MemoryAllocationFailed","`%s'",
574 cache_info->filename);
575 return(MagickFalse);
576 }
577 return(MagickTrue);
578}
579
580static MagickBooleanType ClonePixelCacheNexus(CacheInfo *destination,
581 CacheInfo *source,ExceptionInfo *exception)
582{
583 MagickBooleanType
584 status;
585
586 MagickSizeType
587 number_pixels;
588
cristybb503372010-05-27 20:51:26 +0000589 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000590 i;
591
592 register const NexusInfo
593 *p;
594
595 register NexusInfo
596 *q;
597
598 status=MagickTrue;
cristybb503372010-05-27 20:51:26 +0000599 for (i=0; i < (ssize_t) source->number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000600 {
601 p=source->nexus_info[i];
602 q=destination->nexus_info[i];
603 q->mapped=p->mapped;
604 q->region=p->region;
605 q->length=p->length;
606 q->cache=p->cache;
607 q->pixels=p->pixels;
608 q->indexes=p->indexes;
609 if (p->cache != (PixelPacket *) NULL)
610 {
611 status=AcquireCacheNexusPixels(source,q,exception);
612 if (status != MagickFalse)
613 {
614 (void) CopyMagickMemory(q->cache,p->cache,(size_t) p->length);
615 q->pixels=q->cache;
616 q->indexes=(IndexPacket *) NULL;
617 number_pixels=(MagickSizeType) q->region.width*q->region.height;
618 if (p->indexes != (IndexPacket *) NULL)
619 q->indexes=(IndexPacket *) (q->pixels+number_pixels);
620 }
621 }
622 }
623 return(status);
624}
625
626/*
627%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
628% %
629% %
630% %
cristy60c44a82009-10-07 00:58:49 +0000631+ 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 +0000632% %
633% %
634% %
635%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
636% ClonePixelCachePixels() clones the source pixel cache to the destination
637% cache.
638%
639% The format of the ClonePixelCachePixels() method is:
640%
641% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
642% CacheInfo *source_info,ExceptionInfo *exception)
643%
644% A description of each parameter follows:
645%
646% o cache_info: the pixel cache.
647%
648% o source_info: the source pixel cache.
649%
650% o exception: return any errors or warnings in this structure.
651%
652*/
653
654static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
655{
656 int
657 status;
658
cristy5ee247a2010-02-12 15:42:34 +0000659 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000660 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000661 if (cache_info->file != -1)
662 status=close(cache_info->file);
cristy3ed852e2009-09-05 21:47:34 +0000663 cache_info->file=(-1);
664 RelinquishMagickResource(FileResource,1);
cristyf84a1932010-01-03 18:00:18 +0000665 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000666 return(status == -1 ? MagickFalse : MagickTrue);
667}
668
669static void LimitPixelCacheDescriptors(void)
670{
671 register CacheInfo
672 *p,
673 *q;
674
675 /*
676 Limit # of open file descriptors.
677 */
678 if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
679 return;
cristyf84a1932010-01-03 18:00:18 +0000680 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000681 if (cache_resources == (SplayTreeInfo *) NULL)
682 {
cristyf84a1932010-01-03 18:00:18 +0000683 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000684 return;
685 }
686 ResetSplayTreeIterator(cache_resources);
687 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
688 while (p != (CacheInfo *) NULL)
689 {
690 if ((p->type == DiskCache) && (p->file != -1))
cristy508d9312010-02-10 21:10:30 +0000691 break;
cristy3ed852e2009-09-05 21:47:34 +0000692 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
693 }
694 for (q=p; p != (CacheInfo *) NULL; )
695 {
696 if ((p->type == DiskCache) && (p->file != -1) &&
697 (p->timestamp < q->timestamp))
cristy508d9312010-02-10 21:10:30 +0000698 q=p;
cristy3ed852e2009-09-05 21:47:34 +0000699 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
700 }
701 if (q != (CacheInfo *) NULL)
cristy9e116922010-02-12 20:58:13 +0000702 {
703 /*
704 Close least recently used cache.
705 */
706 (void) close(q->file);
707 q->file=(-1);
708 }
cristyf84a1932010-01-03 18:00:18 +0000709 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000710}
711
712static inline MagickSizeType MagickMax(const MagickSizeType x,
713 const MagickSizeType y)
714{
715 if (x > y)
716 return(x);
717 return(y);
718}
719
720static inline MagickSizeType MagickMin(const MagickSizeType x,
721 const MagickSizeType y)
722{
723 if (x < y)
724 return(x);
725 return(y);
726}
727
728static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
729 const MapMode mode)
730{
731 int
732 file;
733
734 /*
735 Open pixel cache on disk.
736 */
cristyf84a1932010-01-03 18:00:18 +0000737 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000738 if (cache_info->file != -1)
739 {
cristyf84a1932010-01-03 18:00:18 +0000740 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000741 return(MagickTrue); /* cache already open */
742 }
743 LimitPixelCacheDescriptors();
744 if (*cache_info->cache_filename == '\0')
745 file=AcquireUniqueFileResource(cache_info->cache_filename);
746 else
747 switch (mode)
748 {
749 case ReadMode:
750 {
751 file=open(cache_info->cache_filename,O_RDONLY | O_BINARY);
752 break;
753 }
754 case WriteMode:
755 {
756 file=open(cache_info->cache_filename,O_WRONLY | O_CREAT | O_BINARY |
757 O_EXCL,S_MODE);
758 if (file == -1)
759 file=open(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
760 break;
761 }
762 case IOMode:
763 default:
764 {
765 file=open(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
766 O_EXCL,S_MODE);
767 if (file == -1)
768 file=open(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
769 break;
770 }
771 }
772 if (file == -1)
773 {
cristyf84a1932010-01-03 18:00:18 +0000774 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000775 return(MagickFalse);
776 }
777 (void) AcquireMagickResource(FileResource,1);
778 cache_info->file=file;
779 cache_info->timestamp=time(0);
cristyf84a1932010-01-03 18:00:18 +0000780 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000781 return(MagickTrue);
782}
783
784static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
785 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000786 unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000787{
788 register MagickOffsetType
789 i;
790
791 ssize_t
792 count;
793
cristy08a88202010-03-04 19:18:05 +0000794 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000795#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000796 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000797 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
798 {
cristyf84a1932010-01-03 18:00:18 +0000799 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000800 return((MagickOffsetType) -1);
801 }
802#endif
803 count=0;
804 for (i=0; i < (MagickOffsetType) length; i+=count)
805 {
806#if !defined(MAGICKCORE_HAVE_PREAD)
807 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
808 (MagickSizeType) SSIZE_MAX));
809#else
810 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
811 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
812#endif
813 if (count > 0)
814 continue;
815 count=0;
816 if (errno != EINTR)
817 {
818 i=(-1);
819 break;
820 }
821 }
822#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000823 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000824#endif
825 return(i);
826}
827
828static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
829 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000830 const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000831{
832 register MagickOffsetType
833 i;
834
835 ssize_t
836 count;
837
cristy08a88202010-03-04 19:18:05 +0000838 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000839#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000840 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000841 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
842 {
cristyf84a1932010-01-03 18:00:18 +0000843 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000844 return((MagickOffsetType) -1);
845 }
846#endif
847 count=0;
848 for (i=0; i < (MagickOffsetType) length; i+=count)
849 {
850#if !defined(MAGICKCORE_HAVE_PWRITE)
851 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
852 (MagickSizeType) SSIZE_MAX));
853#else
854 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
855 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
856#endif
857 if (count > 0)
858 continue;
859 count=0;
860 if (errno != EINTR)
861 {
862 i=(-1);
863 break;
864 }
865 }
866#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000867 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000868#endif
869 return(i);
870}
871
872static MagickBooleanType CloneDiskToDiskPixelCache(CacheInfo *clone_info,
873 CacheInfo *cache_info,ExceptionInfo *exception)
874{
875 MagickOffsetType
876 count,
877 offset,
878 source_offset;
879
880 MagickSizeType
881 length;
882
cristybb503372010-05-27 20:51:26 +0000883 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000884 y;
885
886 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000887 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +0000888
cristybb503372010-05-27 20:51:26 +0000889 size_t
cristy3ed852e2009-09-05 21:47:34 +0000890 columns,
891 rows;
892
893 if (cache_info->debug != MagickFalse)
894 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
895 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
896 {
897 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
898 clone_info->cache_filename);
899 return(MagickFalse);
900 }
901 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
902 {
903 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
904 cache_info->cache_filename);
905 return(MagickFalse);
906 }
cristybb503372010-05-27 20:51:26 +0000907 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
908 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +0000909 if ((clone_info->active_index_channel != MagickFalse) &&
910 (cache_info->active_index_channel != MagickFalse))
911 {
912 register IndexPacket
913 *indexes;
914
915 /*
916 Clone cache indexes.
917 */
918 length=MagickMax(clone_info->columns,cache_info->columns)*
919 sizeof(*indexes);
920 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
921 if (indexes == (IndexPacket *) NULL)
922 {
923 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
924 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
925 return(MagickFalse);
926 }
927 (void) ResetMagickMemory(indexes,0,(size_t) length);
928 length=columns*sizeof(*indexes);
929 source_offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
930 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
931 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
932 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +0000933 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000934 {
935 source_offset-=cache_info->columns*sizeof(*indexes);
936 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
937 length,(unsigned char *) indexes);
938 if ((MagickSizeType) count != length)
939 break;
940 offset-=clone_info->columns*sizeof(*indexes);
941 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
942 (unsigned char *) indexes);
943 if ((MagickSizeType) count != length)
944 break;
945 }
cristybb503372010-05-27 20:51:26 +0000946 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000947 {
948 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
949 ThrowFileException(exception,CacheError,"UnableToCloneCache",
950 cache_info->cache_filename);
951 return(MagickFalse);
952 }
953 if (clone_info->columns > cache_info->columns)
954 {
955 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
956 (void) ResetMagickMemory(indexes,0,(size_t) length);
957 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
958 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +0000959 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000960 {
961 offset-=clone_info->columns*sizeof(*indexes);
962 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
963 length,(unsigned char *) indexes);
964 if ((MagickSizeType) count != length)
965 break;
966 }
cristybb503372010-05-27 20:51:26 +0000967 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000968 {
969 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
970 ThrowFileException(exception,CacheError,"UnableToCloneCache",
971 cache_info->cache_filename);
972 return(MagickFalse);
973 }
974 }
975 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
976 }
977 /*
978 Clone cache pixels.
979 */
980 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
981 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
982 if (pixels == (PixelPacket *) NULL)
983 {
984 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
985 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
986 return(MagickFalse);
987 }
988 (void) ResetMagickMemory(pixels,0,(size_t) length);
989 length=columns*sizeof(*pixels);
990 source_offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
991 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +0000992 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000993 {
994 source_offset-=cache_info->columns*sizeof(*pixels);
995 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
996 length,(unsigned char *) pixels);
997 if ((MagickSizeType) count != length)
998 break;
999 offset-=clone_info->columns*sizeof(*pixels);
1000 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1001 (unsigned char *) pixels);
1002 if ((MagickSizeType) count != length)
1003 break;
1004 }
cristybb503372010-05-27 20:51:26 +00001005 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001006 {
1007 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1008 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1009 cache_info->cache_filename);
1010 return(MagickFalse);
1011 }
1012 if (clone_info->columns > cache_info->columns)
1013 {
1014 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
1015 sizeof(*pixels);
1016 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1017 (void) ResetMagickMemory(pixels,0,(size_t) length);
cristybb503372010-05-27 20:51:26 +00001018 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001019 {
1020 offset-=clone_info->columns*sizeof(*pixels);
1021 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1022 (unsigned char *) pixels);
1023 if ((MagickSizeType) count != length)
1024 break;
1025 }
cristybb503372010-05-27 20:51:26 +00001026 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001027 {
1028 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1029 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1030 cache_info->cache_filename);
1031 return(MagickFalse);
1032 }
1033 }
1034 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1035 return(MagickTrue);
1036}
1037
1038static MagickBooleanType CloneDiskToMemoryPixelCache(CacheInfo *clone_info,
1039 CacheInfo *cache_info,ExceptionInfo *exception)
1040{
1041 MagickOffsetType
1042 count,
1043 offset;
1044
1045 MagickSizeType
1046 length;
1047
cristybb503372010-05-27 20:51:26 +00001048 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001049 y;
1050
1051 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001052 *restrict pixels,
1053 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00001054
cristybb503372010-05-27 20:51:26 +00001055 size_t
cristy3ed852e2009-09-05 21:47:34 +00001056 columns,
1057 rows;
1058
1059 if (cache_info->debug != MagickFalse)
1060 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
1061 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
1062 {
1063 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1064 cache_info->cache_filename);
1065 return(MagickFalse);
1066 }
cristybb503372010-05-27 20:51:26 +00001067 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1068 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001069 if ((clone_info->active_index_channel != MagickFalse) &&
1070 (cache_info->active_index_channel != MagickFalse))
1071 {
1072 register IndexPacket
1073 *indexes,
1074 *q;
1075
1076 /*
1077 Clone cache indexes.
1078 */
1079 length=MagickMax(clone_info->columns,cache_info->columns)*
1080 sizeof(*indexes);
1081 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1082 if (indexes == (IndexPacket *) NULL)
1083 {
1084 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1085 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1086 return(MagickFalse);
1087 }
1088 (void) ResetMagickMemory(indexes,0,(size_t) length);
1089 length=columns*sizeof(IndexPacket);
1090 offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
1091 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
1092 q=clone_info->indexes+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001093 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001094 {
1095 offset-=cache_info->columns*sizeof(IndexPacket);
1096 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,
1097 length,(unsigned char *) indexes);
1098 if ((MagickSizeType) count != length)
1099 break;
1100 q-=clone_info->columns;
1101 (void) CopyMagickMemory(q,indexes,(size_t) length);
1102 if ((MagickSizeType) count != length)
1103 break;
1104 }
cristybb503372010-05-27 20:51:26 +00001105 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001106 {
1107 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1108 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1109 cache_info->cache_filename);
1110 return(MagickFalse);
1111 }
1112 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1113 }
1114 /*
1115 Clone cache pixels.
1116 */
1117 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1118 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1119 if (pixels == (PixelPacket *) NULL)
1120 {
1121 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1122 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1123 return(MagickFalse);
1124 }
1125 (void) ResetMagickMemory(pixels,0,(size_t) length);
1126 length=columns*sizeof(*pixels);
1127 offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
1128 q=clone_info->pixels+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001129 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001130 {
1131 offset-=cache_info->columns*sizeof(*pixels);
1132 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,length,
1133 (unsigned char *) pixels);
1134 if ((MagickSizeType) count != length)
1135 break;
1136 q-=clone_info->columns;
1137 (void) CopyMagickMemory(q,pixels,(size_t) length);
1138 }
cristybb503372010-05-27 20:51:26 +00001139 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001140 {
1141 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1142 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1143 cache_info->cache_filename);
1144 return(MagickFalse);
1145 }
1146 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1147 return(MagickTrue);
1148}
1149
1150static MagickBooleanType CloneMemoryToDiskPixelCache(CacheInfo *clone_info,
1151 CacheInfo *cache_info,ExceptionInfo *exception)
1152{
1153 MagickOffsetType
1154 count,
1155 offset;
1156
1157 MagickSizeType
1158 length;
1159
cristybb503372010-05-27 20:51:26 +00001160 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001161 y;
1162
1163 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001164 *restrict p,
1165 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +00001166
cristybb503372010-05-27 20:51:26 +00001167 size_t
cristy3ed852e2009-09-05 21:47:34 +00001168 columns,
1169 rows;
1170
1171 if (cache_info->debug != MagickFalse)
1172 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
1173 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
1174 {
1175 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1176 clone_info->cache_filename);
1177 return(MagickFalse);
1178 }
cristybb503372010-05-27 20:51:26 +00001179 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1180 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001181 if ((clone_info->active_index_channel != MagickFalse) &&
1182 (cache_info->active_index_channel != MagickFalse))
1183 {
1184 register IndexPacket
1185 *p,
1186 *indexes;
1187
1188 /*
1189 Clone cache indexes.
1190 */
1191 length=MagickMax(clone_info->columns,cache_info->columns)*
1192 sizeof(*indexes);
1193 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1194 if (indexes == (IndexPacket *) NULL)
1195 {
1196 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1197 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1198 return(MagickFalse);
1199 }
1200 (void) ResetMagickMemory(indexes,0,(size_t) length);
1201 length=columns*sizeof(*indexes);
1202 p=cache_info->indexes+cache_info->columns*rows;
1203 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1204 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +00001205 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001206 {
1207 p-=cache_info->columns;
1208 (void) CopyMagickMemory(indexes,p,(size_t) length);
1209 offset-=clone_info->columns*sizeof(*indexes);
1210 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1211 (unsigned char *) indexes);
1212 if ((MagickSizeType) count != length)
1213 break;
1214 }
cristybb503372010-05-27 20:51:26 +00001215 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001216 {
1217 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1218 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1219 cache_info->cache_filename);
1220 return(MagickFalse);
1221 }
1222 if (clone_info->columns > cache_info->columns)
1223 {
1224 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
1225 (void) ResetMagickMemory(indexes,0,(size_t) length);
1226 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1227 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +00001228 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001229 {
1230 offset-=clone_info->columns*sizeof(*indexes);
1231 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
1232 length,(unsigned char *) indexes);
1233 if ((MagickSizeType) count != length)
1234 break;
1235 }
cristybb503372010-05-27 20:51:26 +00001236 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001237 {
1238 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1239 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1240 cache_info->cache_filename);
1241 return(MagickFalse);
1242 }
1243 }
1244 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1245 }
1246 /*
1247 Clone cache pixels.
1248 */
1249 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1250 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1251 if (pixels == (PixelPacket *) NULL)
1252 {
1253 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1254 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1255 return(MagickFalse);
1256 }
1257 (void) ResetMagickMemory(pixels,0,(size_t) length);
1258 length=columns*sizeof(*pixels);
1259 p=cache_info->pixels+cache_info->columns*rows;
1260 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +00001261 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001262 {
1263 p-=cache_info->columns;
1264 (void) CopyMagickMemory(pixels,p,(size_t) length);
1265 offset-=clone_info->columns*sizeof(*pixels);
1266 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1267 (unsigned char *) pixels);
1268 if ((MagickSizeType) count != length)
1269 break;
1270 }
cristybb503372010-05-27 20:51:26 +00001271 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001272 {
1273 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1274 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1275 cache_info->cache_filename);
1276 return(MagickFalse);
1277 }
1278 if (clone_info->columns > cache_info->columns)
1279 {
1280 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
1281 sizeof(*pixels);
1282 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1283 (void) ResetMagickMemory(pixels,0,(size_t) length);
cristybb503372010-05-27 20:51:26 +00001284 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001285 {
1286 offset-=clone_info->columns*sizeof(*pixels);
1287 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1288 (unsigned char *) pixels);
1289 if ((MagickSizeType) count != length)
1290 break;
1291 }
cristybb503372010-05-27 20:51:26 +00001292 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001293 {
1294 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1295 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1296 cache_info->cache_filename);
1297 return(MagickFalse);
1298 }
1299 }
1300 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1301 return(MagickTrue);
1302}
1303
1304static MagickBooleanType CloneMemoryToMemoryPixelCache(CacheInfo *clone_info,
1305 CacheInfo *cache_info,ExceptionInfo *magick_unused(exception))
1306{
cristybb503372010-05-27 20:51:26 +00001307 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001308 y;
1309
1310 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001311 *restrict pixels,
1312 *restrict source_pixels;
cristy3ed852e2009-09-05 21:47:34 +00001313
1314 size_t
1315 length;
1316
cristybb503372010-05-27 20:51:26 +00001317 size_t
cristy3ed852e2009-09-05 21:47:34 +00001318 columns,
1319 rows;
1320
1321 if (cache_info->debug != MagickFalse)
1322 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
cristybb503372010-05-27 20:51:26 +00001323 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1324 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001325 if ((clone_info->active_index_channel != MagickFalse) &&
1326 (cache_info->active_index_channel != MagickFalse))
1327 {
1328 register IndexPacket
1329 *indexes,
1330 *source_indexes;
1331
1332 /*
1333 Clone cache indexes.
1334 */
1335 length=columns*sizeof(*indexes);
1336 if (clone_info->columns == cache_info->columns)
1337 (void) CopyMagickMemory(clone_info->indexes,cache_info->indexes,
1338 length*rows);
1339 else
1340 {
1341 source_indexes=cache_info->indexes+cache_info->columns*rows;
1342 indexes=clone_info->indexes+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001343 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001344 {
1345 source_indexes-=cache_info->columns;
1346 indexes-=clone_info->columns;
1347 (void) CopyMagickMemory(indexes,source_indexes,length);
1348 }
1349 if (clone_info->columns > cache_info->columns)
1350 {
1351 length=(clone_info->columns-cache_info->columns)*
1352 sizeof(*indexes);
1353 indexes=clone_info->indexes+clone_info->columns*rows+
1354 cache_info->columns;
cristybb503372010-05-27 20:51:26 +00001355 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001356 {
1357 indexes-=clone_info->columns;
1358 (void) ResetMagickMemory(indexes,0,length);
1359 }
1360 }
1361 }
1362 }
1363 /*
1364 Clone cache pixels.
1365 */
1366 length=columns*sizeof(*pixels);
1367 if (clone_info->columns == cache_info->columns)
1368 (void) CopyMagickMemory(clone_info->pixels,cache_info->pixels,length*rows);
1369 else
1370 {
1371 source_pixels=cache_info->pixels+cache_info->columns*rows;
1372 pixels=clone_info->pixels+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001373 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001374 {
1375 source_pixels-=cache_info->columns;
1376 pixels-=clone_info->columns;
1377 (void) CopyMagickMemory(pixels,source_pixels,length);
1378 }
1379 if (clone_info->columns > cache_info->columns)
1380 {
1381 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1382 pixels=clone_info->pixels+clone_info->columns*rows+
1383 cache_info->columns;
cristybb503372010-05-27 20:51:26 +00001384 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001385 {
1386 pixels-=clone_info->columns;
1387 (void) ResetMagickMemory(pixels,0,length);
1388 }
1389 }
1390 }
1391 return(MagickTrue);
1392}
1393
1394static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1395 CacheInfo *cache_info,ExceptionInfo *exception)
1396{
1397 if ((clone_info->type != DiskCache) && (cache_info->type != DiskCache))
1398 return(CloneMemoryToMemoryPixelCache(clone_info,cache_info,exception));
1399 if ((clone_info->type == DiskCache) && (cache_info->type == DiskCache))
1400 return(CloneDiskToDiskPixelCache(clone_info,cache_info,exception));
1401 if (cache_info->type == DiskCache)
1402 return(CloneDiskToMemoryPixelCache(clone_info,cache_info,exception));
1403 return(CloneMemoryToDiskPixelCache(clone_info,cache_info,exception));
1404}
1405
1406/*
1407%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1408% %
1409% %
1410% %
1411+ C l o n e P i x e l C a c h e M e t h o d s %
1412% %
1413% %
1414% %
1415%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1416%
1417% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1418% another.
1419%
1420% The format of the ClonePixelCacheMethods() method is:
1421%
1422% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1423%
1424% A description of each parameter follows:
1425%
1426% o clone: Specifies a pointer to a Cache structure.
1427%
1428% o cache: the pixel cache.
1429%
1430*/
1431MagickExport void ClonePixelCacheMethods(Cache clone,const Cache cache)
1432{
1433 CacheInfo
1434 *cache_info,
1435 *source_info;
1436
1437 assert(clone != (Cache) NULL);
1438 source_info=(CacheInfo *) clone;
1439 assert(source_info->signature == MagickSignature);
1440 if (source_info->debug != MagickFalse)
1441 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1442 source_info->filename);
1443 assert(cache != (Cache) NULL);
1444 cache_info=(CacheInfo *) cache;
1445 assert(cache_info->signature == MagickSignature);
1446 source_info->methods=cache_info->methods;
1447}
1448
1449/*
1450%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1451% %
1452% %
1453% %
1454+ D e s t r o y I m a g e P i x e l C a c h e %
1455% %
1456% %
1457% %
1458%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1459%
1460% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1461%
1462% The format of the DestroyImagePixelCache() method is:
1463%
1464% void DestroyImagePixelCache(Image *image)
1465%
1466% A description of each parameter follows:
1467%
1468% o image: the image.
1469%
1470*/
1471static void DestroyImagePixelCache(Image *image)
1472{
1473 assert(image != (Image *) NULL);
1474 assert(image->signature == MagickSignature);
1475 if (image->debug != MagickFalse)
1476 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1477 if (image->cache == (void *) NULL)
1478 return;
1479 image->cache=DestroyPixelCache(image->cache);
1480}
1481
1482/*
1483%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1484% %
1485% %
1486% %
1487+ D e s t r o y I m a g e P i x e l s %
1488% %
1489% %
1490% %
1491%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1492%
1493% DestroyImagePixels() deallocates memory associated with the pixel cache.
1494%
1495% The format of the DestroyImagePixels() method is:
1496%
1497% void DestroyImagePixels(Image *image)
1498%
1499% A description of each parameter follows:
1500%
1501% o image: the image.
1502%
1503*/
1504MagickExport void DestroyImagePixels(Image *image)
1505{
1506 CacheInfo
1507 *cache_info;
1508
1509 assert(image != (const Image *) NULL);
1510 assert(image->signature == MagickSignature);
1511 if (image->debug != MagickFalse)
1512 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1513 assert(image->cache != (Cache) NULL);
1514 cache_info=(CacheInfo *) image->cache;
1515 assert(cache_info->signature == MagickSignature);
1516 if (cache_info->methods.destroy_pixel_handler == (DestroyPixelHandler) NULL)
1517 return;
1518 cache_info->methods.destroy_pixel_handler(image);
1519}
1520
1521/*
1522%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1523% %
1524% %
1525% %
1526+ D e s t r o y P i x e l C a c h e %
1527% %
1528% %
1529% %
1530%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1531%
1532% DestroyPixelCache() deallocates memory associated with the pixel cache.
1533%
1534% The format of the DestroyPixelCache() method is:
1535%
1536% Cache DestroyPixelCache(Cache cache)
1537%
1538% A description of each parameter follows:
1539%
1540% o cache: the pixel cache.
1541%
1542*/
1543
1544static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1545{
1546 switch (cache_info->type)
1547 {
1548 case MemoryCache:
1549 {
1550 if (cache_info->mapped == MagickFalse)
1551 cache_info->pixels=(PixelPacket *) RelinquishMagickMemory(
1552 cache_info->pixels);
1553 else
1554 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,
1555 (size_t) cache_info->length);
1556 RelinquishMagickResource(MemoryResource,cache_info->length);
1557 break;
1558 }
1559 case MapCache:
1560 {
1561 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,(size_t)
1562 cache_info->length);
1563 RelinquishMagickResource(MapResource,cache_info->length);
1564 }
1565 case DiskCache:
1566 {
1567 if (cache_info->file != -1)
1568 (void) ClosePixelCacheOnDisk(cache_info);
1569 RelinquishMagickResource(DiskResource,cache_info->length);
1570 break;
1571 }
1572 default:
1573 break;
1574 }
1575 cache_info->type=UndefinedCache;
1576 cache_info->mapped=MagickFalse;
1577 cache_info->indexes=(IndexPacket *) NULL;
1578}
1579
1580MagickExport Cache DestroyPixelCache(Cache cache)
1581{
1582 CacheInfo
1583 *cache_info;
1584
cristy3ed852e2009-09-05 21:47:34 +00001585 assert(cache != (Cache) NULL);
1586 cache_info=(CacheInfo *) cache;
1587 assert(cache_info->signature == MagickSignature);
1588 if (cache_info->debug != MagickFalse)
1589 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1590 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001591 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001592 cache_info->reference_count--;
1593 if (cache_info->reference_count != 0)
1594 {
cristyf84a1932010-01-03 18:00:18 +00001595 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001596 return((Cache) NULL);
1597 }
cristyf84a1932010-01-03 18:00:18 +00001598 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001599 if (cache_resources != (SplayTreeInfo *) NULL)
1600 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
cristy5b8de732009-09-10 23:50:40 +00001601 if (cache_info->debug != MagickFalse)
1602 {
1603 char
1604 message[MaxTextExtent];
1605
1606 (void) FormatMagickString(message,MaxTextExtent,"destroy %s",
1607 cache_info->filename);
1608 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1609 }
cristyc2e1bdd2009-09-10 23:43:34 +00001610 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1611 (cache_info->type != DiskCache)))
1612 RelinquishPixelCachePixels(cache_info);
1613 else
1614 {
1615 RelinquishPixelCachePixels(cache_info);
1616 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1617 }
cristy3ed852e2009-09-05 21:47:34 +00001618 *cache_info->cache_filename='\0';
1619 if (cache_info->nexus_info != (NexusInfo **) NULL)
1620 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1621 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001622 if (cache_info->random_info != (RandomInfo *) NULL)
1623 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001624 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1625 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1626 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1627 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001628 cache_info->signature=(~MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001629 cache_info=(CacheInfo *) RelinquishAlignedMemory(cache_info);
1630 cache=(Cache) NULL;
1631 return(cache);
1632}
1633
1634/*
1635%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1636% %
1637% %
1638% %
1639+ D e s t r o y P i x e l C a c h e N e x u s %
1640% %
1641% %
1642% %
1643%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1644%
1645% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1646%
1647% The format of the DestroyPixelCacheNexus() method is:
1648%
1649% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001650% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001651%
1652% A description of each parameter follows:
1653%
1654% o nexus_info: the nexus to destroy.
1655%
1656% o number_threads: the number of nexus threads.
1657%
1658*/
1659
1660static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1661{
1662 if (nexus_info->mapped == MagickFalse)
1663 (void) RelinquishMagickMemory(nexus_info->cache);
1664 else
1665 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1666 nexus_info->cache=(PixelPacket *) NULL;
1667 nexus_info->pixels=(PixelPacket *) NULL;
1668 nexus_info->indexes=(IndexPacket *) NULL;
1669 nexus_info->length=0;
1670 nexus_info->mapped=MagickFalse;
1671}
1672
1673MagickExport NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001674 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001675{
cristybb503372010-05-27 20:51:26 +00001676 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001677 i;
1678
1679 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001680 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001681 {
1682 if (nexus_info[i]->cache != (PixelPacket *) NULL)
1683 RelinquishCacheNexusPixels(nexus_info[i]);
1684 nexus_info[i]->signature=(~MagickSignature);
1685 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
1686 }
1687 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
1688 return(nexus_info);
1689}
1690
1691/*
1692%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1693% %
1694% %
1695% %
cristy3ed852e2009-09-05 21:47:34 +00001696+ 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 %
1697% %
1698% %
1699% %
1700%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1701%
1702% GetAuthenticIndexesFromCache() returns the indexes associated with the last
1703% call to QueueAuthenticPixelsCache() or GetAuthenticPixelsCache().
1704%
1705% The format of the GetAuthenticIndexesFromCache() method is:
1706%
1707% IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1708%
1709% A description of each parameter follows:
1710%
1711% o image: the image.
1712%
1713*/
1714static IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1715{
1716 CacheInfo
1717 *cache_info;
1718
1719 IndexPacket
1720 *indexes;
1721
cristybb503372010-05-27 20:51:26 +00001722 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001723 id;
1724
1725 if (image->debug != MagickFalse)
1726 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1727 cache_info=(CacheInfo *) image->cache;
1728 id=GetOpenMPThreadId();
cristybb503372010-05-27 20:51:26 +00001729 assert(id < (ssize_t) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001730 indexes=GetPixelCacheNexusIndexes(image->cache,cache_info->nexus_info[id]);
1731 return(indexes);
1732}
1733
1734/*
1735%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1736% %
1737% %
1738% %
1739% G e t A u t h e n t i c I n d e x Q u e u e %
1740% %
1741% %
1742% %
1743%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1744%
1745% GetAuthenticIndexQueue() returns the authentic black channel or the colormap
1746% indexes associated with the last call to QueueAuthenticPixels() or
1747% GetVirtualPixels(). NULL is returned if the black channel or colormap
1748% indexes are not available.
1749%
1750% The format of the GetAuthenticIndexQueue() method is:
1751%
1752% IndexPacket *GetAuthenticIndexQueue(const Image *image)
1753%
1754% A description of each parameter follows:
1755%
1756% o image: the image.
1757%
1758*/
1759MagickExport IndexPacket *GetAuthenticIndexQueue(const Image *image)
1760{
1761 CacheInfo
1762 *cache_info;
1763
1764 assert(image != (const Image *) NULL);
1765 assert(image->signature == MagickSignature);
1766 if (image->debug != MagickFalse)
1767 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1768 assert(image->cache != (Cache) NULL);
1769 cache_info=(CacheInfo *) image->cache;
1770 assert(cache_info->signature == MagickSignature);
1771 if (cache_info->methods.get_authentic_indexes_from_handler ==
1772 (GetAuthenticIndexesFromHandler) NULL)
1773 return((IndexPacket *) NULL);
1774 return(cache_info->methods.get_authentic_indexes_from_handler(image));
1775}
1776
1777/*
1778%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1779% %
1780% %
1781% %
1782+ 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 %
1783% %
1784% %
1785% %
1786%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1787%
1788% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1789% disk pixel cache as defined by the geometry parameters. A pointer to the
1790% pixels is returned if the pixels are transferred, otherwise a NULL is
1791% returned.
1792%
1793% The format of the GetAuthenticPixelCacheNexus() method is:
1794%
cristybb503372010-05-27 20:51:26 +00001795% PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1796% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001797% NexusInfo *nexus_info,ExceptionInfo *exception)
1798%
1799% A description of each parameter follows:
1800%
1801% o image: the image.
1802%
1803% o x,y,columns,rows: These values define the perimeter of a region of
1804% pixels.
1805%
1806% o nexus_info: the cache nexus to return.
1807%
1808% o exception: return any errors or warnings in this structure.
1809%
1810*/
1811
1812static inline MagickBooleanType IsNexusInCore(const CacheInfo *cache_info,
1813 NexusInfo *nexus_info)
1814{
1815 MagickOffsetType
1816 offset;
1817
cristy73724512010-04-12 14:43:14 +00001818 if (cache_info->type == PingCache)
1819 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001820 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1821 nexus_info->region.x;
1822 if (nexus_info->pixels != (cache_info->pixels+offset))
1823 return(MagickFalse);
1824 return(MagickTrue);
1825}
1826
cristybb503372010-05-27 20:51:26 +00001827MagickExport PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1828 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001829 NexusInfo *nexus_info,ExceptionInfo *exception)
1830{
1831 CacheInfo
1832 *cache_info;
1833
1834 PixelPacket
1835 *pixels;
1836
1837 /*
1838 Transfer pixels from the cache.
1839 */
1840 assert(image != (Image *) NULL);
1841 assert(image->signature == MagickSignature);
1842 if (image->debug != MagickFalse)
1843 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1844 pixels=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
1845 if (pixels == (PixelPacket *) NULL)
1846 return((PixelPacket *) NULL);
1847 cache_info=(CacheInfo *) image->cache;
1848 assert(cache_info->signature == MagickSignature);
1849 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
1850 return(pixels);
1851 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1852 return((PixelPacket *) NULL);
1853 if (cache_info->active_index_channel != MagickFalse)
1854 if (ReadPixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse)
1855 return((PixelPacket *) NULL);
1856 return(pixels);
1857}
1858
1859/*
1860%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1861% %
1862% %
1863% %
1864+ 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 %
1865% %
1866% %
1867% %
1868%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1869%
1870% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1871% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1872%
1873% The format of the GetAuthenticPixelsFromCache() method is:
1874%
1875% PixelPacket *GetAuthenticPixelsFromCache(const Image image)
1876%
1877% A description of each parameter follows:
1878%
1879% o image: the image.
1880%
1881*/
1882static PixelPacket *GetAuthenticPixelsFromCache(const Image *image)
1883{
1884 CacheInfo
1885 *cache_info;
1886
cristybb503372010-05-27 20:51:26 +00001887 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001888 id;
1889
1890 PixelPacket
1891 *pixels;
1892
1893 if (image->debug != MagickFalse)
1894 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1895 cache_info=(CacheInfo *) image->cache;
1896 id=GetOpenMPThreadId();
cristybb503372010-05-27 20:51:26 +00001897 assert(id < (ssize_t) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001898 pixels=GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]);
1899 return(pixels);
1900}
1901
1902/*
1903%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1904% %
1905% %
1906% %
1907% G e t A u t h e n t i c P i x e l Q u e u e %
1908% %
1909% %
1910% %
1911%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1912%
1913% GetAuthenticPixelQueue() returns the authentic pixels associated with the
1914% last call to QueueAuthenticPixels() or GetAuthenticPixels().
1915%
1916% The format of the GetAuthenticPixelQueue() method is:
1917%
1918% PixelPacket *GetAuthenticPixelQueue(const Image image)
1919%
1920% A description of each parameter follows:
1921%
1922% o image: the image.
1923%
1924*/
1925MagickExport PixelPacket *GetAuthenticPixelQueue(const Image *image)
1926{
1927 CacheInfo
1928 *cache_info;
1929
1930 assert(image != (const Image *) NULL);
1931 assert(image->signature == MagickSignature);
1932 if (image->debug != MagickFalse)
1933 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1934 assert(image->cache != (Cache) NULL);
1935 cache_info=(CacheInfo *) image->cache;
1936 assert(cache_info->signature == MagickSignature);
1937 if (cache_info->methods.get_authentic_pixels_from_handler ==
1938 (GetAuthenticPixelsFromHandler) NULL)
1939 return((PixelPacket *) NULL);
1940 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1941}
1942
1943/*
1944%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1945% %
1946% %
1947% %
1948% G e t A u t h e n t i c P i x e l s %
1949% %
1950% %
1951% %
1952%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1953%
1954% GetAuthenticPixels() obtains a pixel region for read/write access. If the
1955% region is successfully accessed, a pointer to a PixelPacket array
1956% representing the region is returned, otherwise NULL is returned.
1957%
1958% The returned pointer may point to a temporary working copy of the pixels
1959% or it may point to the original pixels in memory. Performance is maximized
1960% if the selected region is part of one row, or one or more full rows, since
1961% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001962% if the image is in memory, or in a memory-mapped file. The returned pointer
1963% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001964%
1965% Pixels accessed via the returned pointer represent a simple array of type
1966% PixelPacket. If the image type is CMYK or if the storage class is
1967% PseduoClass, call GetAuthenticIndexQueue() after invoking
1968% GetAuthenticPixels() to obtain the black color component or colormap indexes
1969% (of type IndexPacket) corresponding to the region. Once the PixelPacket
1970% (and/or IndexPacket) array has been updated, the changes must be saved back
1971% to the underlying image using SyncAuthenticPixels() or they may be lost.
1972%
1973% The format of the GetAuthenticPixels() method is:
1974%
cristy5f959472010-05-27 22:19:46 +00001975% PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1976% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001977% ExceptionInfo *exception)
1978%
1979% A description of each parameter follows:
1980%
1981% o image: the image.
1982%
1983% o x,y,columns,rows: These values define the perimeter of a region of
1984% pixels.
1985%
1986% o exception: return any errors or warnings in this structure.
1987%
1988*/
cristybb503372010-05-27 20:51:26 +00001989MagickExport PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1990 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001991 ExceptionInfo *exception)
1992{
1993 CacheInfo
1994 *cache_info;
1995
1996 PixelPacket
1997 *pixels;
1998
1999 assert(image != (Image *) NULL);
2000 assert(image->signature == MagickSignature);
2001 if (image->debug != MagickFalse)
2002 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2003 assert(image->cache != (Cache) NULL);
2004 cache_info=(CacheInfo *) image->cache;
2005 assert(cache_info->signature == MagickSignature);
2006 if (cache_info->methods.get_authentic_pixels_handler ==
2007 (GetAuthenticPixelsHandler) NULL)
2008 return((PixelPacket *) NULL);
2009 pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
2010 rows,exception);
2011 return(pixels);
2012}
2013
2014/*
2015%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2016% %
2017% %
2018% %
2019+ G e t A u t h e n t i c P i x e l s C a c h e %
2020% %
2021% %
2022% %
2023%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2024%
2025% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
2026% as defined by the geometry parameters. A pointer to the pixels is returned
2027% if the pixels are transferred, otherwise a NULL is returned.
2028%
2029% The format of the GetAuthenticPixelsCache() method is:
2030%
cristybb503372010-05-27 20:51:26 +00002031% PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
2032% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00002033% ExceptionInfo *exception)
2034%
2035% A description of each parameter follows:
2036%
2037% o image: the image.
2038%
2039% o x,y,columns,rows: These values define the perimeter of a region of
2040% pixels.
2041%
2042% o exception: return any errors or warnings in this structure.
2043%
2044*/
cristybb503372010-05-27 20:51:26 +00002045static PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
2046 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00002047 ExceptionInfo *exception)
2048{
2049 CacheInfo
2050 *cache_info;
2051
cristybb503372010-05-27 20:51:26 +00002052 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002053 id;
2054
2055 PixelPacket
2056 *pixels;
2057
2058 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
2059 if (cache_info == (Cache) NULL)
2060 return((PixelPacket *) NULL);
2061 id=GetOpenMPThreadId();
cristybb503372010-05-27 20:51:26 +00002062 assert(id < (ssize_t) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00002063 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
2064 cache_info->nexus_info[id],exception);
2065 return(pixels);
2066}
2067
2068/*
2069%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2070% %
2071% %
2072% %
2073+ G e t I m a g e E x t e n t %
2074% %
2075% %
2076% %
2077%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2078%
2079% GetImageExtent() returns the extent of the pixels associated with the
2080% last call to QueueAuthenticPixels() or GetAuthenticPixels().
2081%
2082% The format of the GetImageExtent() method is:
2083%
2084% MagickSizeType GetImageExtent(const Image *image)
2085%
2086% A description of each parameter follows:
2087%
2088% o image: the image.
2089%
2090*/
2091MagickExport MagickSizeType GetImageExtent(const Image *image)
2092{
2093 CacheInfo
2094 *cache_info;
2095
cristybb503372010-05-27 20:51:26 +00002096 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002097 id;
2098
2099 MagickSizeType
2100 extent;
2101
2102 assert(image != (Image *) NULL);
2103 assert(image->signature == MagickSignature);
2104 if (image->debug != MagickFalse)
2105 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2106 assert(image->cache != (Cache) NULL);
2107 cache_info=(CacheInfo *) image->cache;
2108 assert(cache_info->signature == MagickSignature);
2109 id=GetOpenMPThreadId();
cristybb503372010-05-27 20:51:26 +00002110 assert(id < (ssize_t) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00002111 extent=GetPixelCacheNexusExtent(image->cache,cache_info->nexus_info[id]);
2112 return(extent);
2113}
2114
2115/*
2116%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2117% %
2118% %
2119% %
2120+ G e t I m a g e P i x e l C a c h e %
2121% %
2122% %
2123% %
2124%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2125%
2126% GetImagePixelCache() ensures that there is only a single reference to the
2127% pixel cache to be modified, updating the provided cache pointer to point to
2128% a clone of the original pixel cache if necessary.
2129%
2130% The format of the GetImagePixelCache method is:
2131%
2132% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2133% ExceptionInfo *exception)
2134%
2135% A description of each parameter follows:
2136%
2137% o image: the image.
2138%
2139% o clone: any value other than MagickFalse clones the cache pixels.
2140%
2141% o exception: return any errors or warnings in this structure.
2142%
2143*/
cristy3ed852e2009-09-05 21:47:34 +00002144static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
2145{
2146 CacheInfo
2147 *cache_info;
2148
2149 /*
2150 Does the image match the pixel cache morphology?
2151 */
2152 cache_info=(CacheInfo *) image->cache;
2153 if ((image->storage_class != cache_info->storage_class) ||
2154 (image->colorspace != cache_info->colorspace) ||
2155 (image->columns != cache_info->columns) ||
2156 (image->rows != cache_info->rows) ||
2157 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2158 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2159 return(MagickFalse);
2160 return(MagickTrue);
2161}
2162
2163MagickExport Cache GetImagePixelCache(Image *image,
2164 const MagickBooleanType clone,ExceptionInfo *exception)
2165{
2166 CacheInfo
2167 *cache_info;
2168
cristy3ed852e2009-09-05 21:47:34 +00002169 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00002170 destroy,
cristy3ed852e2009-09-05 21:47:34 +00002171 status;
2172
cristy50a10922010-02-15 18:35:25 +00002173 static MagickSizeType
2174 time_limit = 0;
2175
cristy1ea34962010-07-01 19:49:21 +00002176 static time_t
cristya21afde2010-07-02 00:45:40 +00002177 cache_genesis = 0;
cristy1ea34962010-07-01 19:49:21 +00002178
cristy3ed852e2009-09-05 21:47:34 +00002179 if (image->debug != MagickFalse)
2180 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristyc4f9f132010-03-04 18:50:01 +00002181 status=MagickTrue;
2182 LockSemaphoreInfo(image->semaphore);
cristy1ea34962010-07-01 19:49:21 +00002183 if (time_limit == 0)
2184 {
2185 time_limit=GetMagickResourceLimit(TimeResource);
cristya21afde2010-07-02 00:45:40 +00002186 cache_genesis=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00002187 }
2188 if ((time_limit != MagickResourceInfinity) &&
cristya21afde2010-07-02 00:45:40 +00002189 ((MagickSizeType) (time((time_t *) NULL)-cache_genesis) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00002190 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00002191 assert(image->cache != (Cache) NULL);
2192 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002193 destroy=MagickFalse;
cristy01b7eb02009-09-10 23:10:14 +00002194 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002195 {
cristyaaa0cb62010-02-15 17:47:27 +00002196 LockSemaphoreInfo(cache_info->semaphore);
2197 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002198 {
cristyaaa0cb62010-02-15 17:47:27 +00002199 Image
2200 clone_image;
2201
2202 CacheInfo
2203 *clone_info;
2204
2205 /*
2206 Clone pixel cache.
2207 */
2208 clone_image=(*image);
2209 clone_image.cache=ClonePixelCache(cache_info);
2210 clone_info=(CacheInfo *) clone_image.cache;
2211 status=ClonePixelCacheNexus(cache_info,clone_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002212 if (status != MagickFalse)
2213 {
cristyaaa0cb62010-02-15 17:47:27 +00002214 status=OpenPixelCache(&clone_image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00002215 if (status != MagickFalse)
2216 {
cristyaaa0cb62010-02-15 17:47:27 +00002217 if (clone != MagickFalse)
2218 status=ClonePixelCachePixels(clone_info,cache_info,
2219 exception);
2220 if (status != MagickFalse)
2221 {
2222 destroy=MagickTrue;
2223 image->cache=clone_image.cache;
2224 }
cristy3ed852e2009-09-05 21:47:34 +00002225 }
2226 }
2227 }
cristyaaa0cb62010-02-15 17:47:27 +00002228 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002229 }
cristy4320e0e2009-09-10 15:00:08 +00002230 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002231 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002232 if (status != MagickFalse)
2233 {
2234 /*
2235 Ensure the image matches the pixel cache morphology.
2236 */
2237 image->taint=MagickTrue;
2238 image->type=UndefinedType;
cristydd438462010-05-06 13:44:04 +00002239 if (image->colorspace == GRAYColorspace)
2240 image->colorspace=RGBColorspace;
cristy3ed852e2009-09-05 21:47:34 +00002241 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2242 status=OpenPixelCache(image,IOMode,exception);
2243 }
cristyf84a1932010-01-03 18:00:18 +00002244 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002245 if (status == MagickFalse)
2246 return((Cache) NULL);
2247 return(image->cache);
2248}
2249
2250/*
2251%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2252% %
2253% %
2254% %
2255% G e t O n e A u t h e n t i c P i x e l %
2256% %
2257% %
2258% %
2259%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2260%
2261% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2262% location. The image background color is returned if an error occurs.
2263%
2264% The format of the GetOneAuthenticPixel() method is:
2265%
cristybb503372010-05-27 20:51:26 +00002266% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2267% const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002268%
2269% A description of each parameter follows:
2270%
2271% o image: the image.
2272%
2273% o x,y: These values define the location of the pixel to return.
2274%
2275% o pixel: return a pixel at the specified (x,y) location.
2276%
2277% o exception: return any errors or warnings in this structure.
2278%
2279*/
cristyacbbb7c2010-06-30 18:56:48 +00002280MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2281 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002282{
2283 CacheInfo
2284 *cache_info;
2285
2286 GetOneAuthenticPixelFromHandler
2287 get_one_authentic_pixel_from_handler;
2288
2289 MagickBooleanType
2290 status;
2291
2292 assert(image != (Image *) NULL);
2293 assert(image->signature == MagickSignature);
2294 if (image->debug != MagickFalse)
2295 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2296 assert(image->cache != (Cache) NULL);
2297 cache_info=(CacheInfo *) image->cache;
2298 assert(cache_info->signature == MagickSignature);
2299 *pixel=image->background_color;
2300 get_one_authentic_pixel_from_handler=
2301 cache_info->methods.get_one_authentic_pixel_from_handler;
2302 if (get_one_authentic_pixel_from_handler ==
2303 (GetOneAuthenticPixelFromHandler) NULL)
2304 return(MagickFalse);
2305 status=cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2306 pixel,exception);
2307 return(status);
2308}
2309
2310/*
2311%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2312% %
2313% %
2314% %
2315+ 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 %
2316% %
2317% %
2318% %
2319%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2320%
2321% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2322% location. The image background color is returned if an error occurs.
2323%
2324% The format of the GetOneAuthenticPixelFromCache() method is:
2325%
2326% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy5f959472010-05-27 22:19:46 +00002327% const ssize_t x,const ssize_t y,PixelPacket *pixel,
2328% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002329%
2330% A description of each parameter follows:
2331%
2332% o image: the image.
2333%
2334% o x,y: These values define the location of the pixel to return.
2335%
2336% o pixel: return a pixel at the specified (x,y) location.
2337%
2338% o exception: return any errors or warnings in this structure.
2339%
2340*/
2341static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristybb503372010-05-27 20:51:26 +00002342 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002343{
2344 PixelPacket
2345 *pixels;
2346
2347 if (image->debug != MagickFalse)
2348 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2349 *pixel=image->background_color;
2350 pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2351 if (pixels == (PixelPacket *) NULL)
2352 return(MagickFalse);
2353 *pixel=(*pixels);
2354 return(MagickTrue);
2355}
2356
2357/*
2358%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2359% %
2360% %
2361% %
2362% G e t O n e V i r t u a l M a g i c k P i x e l %
2363% %
2364% %
2365% %
2366%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2367%
2368% GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2369% location. The image background color is returned if an error occurs. If
2370% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2371%
2372% The format of the GetOneVirtualMagickPixel() method is:
2373%
2374% MagickBooleanType GetOneVirtualMagickPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002375% const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
cristy3ed852e2009-09-05 21:47:34 +00002376% ExceptionInfo exception)
2377%
2378% A description of each parameter follows:
2379%
2380% o image: the image.
2381%
2382% o x,y: these values define the location of the pixel to return.
2383%
2384% o pixel: return a pixel at the specified (x,y) location.
2385%
2386% o exception: return any errors or warnings in this structure.
2387%
2388*/
2389MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
cristyacbbb7c2010-06-30 18:56:48 +00002390 const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
2391 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002392{
2393 CacheInfo
2394 *cache_info;
2395
2396 register const IndexPacket
2397 *indexes;
2398
2399 register const PixelPacket
2400 *p;
2401
2402 assert(image != (const Image *) NULL);
2403 assert(image->signature == MagickSignature);
2404 assert(image->cache != (Cache) NULL);
2405 cache_info=(CacheInfo *) image->cache;
2406 assert(cache_info->signature == MagickSignature);
2407 GetMagickPixelPacket(image,pixel);
2408 p=GetVirtualPixelCache(image,GetPixelCacheVirtualMethod(image),x,y,1,1,
2409 exception);
2410 if (p == (const PixelPacket *) NULL)
2411 return(MagickFalse);
2412 indexes=GetVirtualIndexQueue(image);
2413 SetMagickPixelPacket(image,p,indexes,pixel);
2414 return(MagickTrue);
2415}
2416
2417/*
2418%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2419% %
2420% %
2421% %
2422% G e t O n e V i r t u a l M e t h o d P i x e l %
2423% %
2424% %
2425% %
2426%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2427%
2428% GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2429% location as defined by specified pixel method. The image background color
2430% is returned if an error occurs. If you plan to modify the pixel, use
2431% GetOneAuthenticPixel() instead.
2432%
2433% The format of the GetOneVirtualMethodPixel() method is:
2434%
2435% MagickBooleanType GetOneVirtualMethodPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002436% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2437% const ssize_t y,Pixelpacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002438%
2439% A description of each parameter follows:
2440%
2441% o image: the image.
2442%
2443% o virtual_pixel_method: the virtual pixel method.
2444%
2445% o x,y: These values define the location of the pixel to return.
2446%
2447% o pixel: return a pixel at the specified (x,y) location.
2448%
2449% o exception: return any errors or warnings in this structure.
2450%
2451*/
2452MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002453 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002454 PixelPacket *pixel,ExceptionInfo *exception)
2455{
2456 GetOneVirtualPixelFromHandler
2457 get_one_virtual_pixel_from_handler;
2458
2459 CacheInfo
2460 *cache_info;
2461
2462 MagickBooleanType
2463 status;
2464
2465 assert(image != (const Image *) NULL);
2466 assert(image->signature == MagickSignature);
2467 assert(image->cache != (Cache) NULL);
2468 cache_info=(CacheInfo *) image->cache;
2469 assert(cache_info->signature == MagickSignature);
2470 *pixel=image->background_color;
2471 get_one_virtual_pixel_from_handler=
2472 cache_info->methods.get_one_virtual_pixel_from_handler;
2473 if (get_one_virtual_pixel_from_handler ==
2474 (GetOneVirtualPixelFromHandler) NULL)
2475 return(MagickFalse);
2476 status=get_one_virtual_pixel_from_handler(image,virtual_pixel_method,x,y,
2477 pixel,exception);
2478 return(status);
2479}
2480
2481/*
2482%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2483% %
2484% %
2485% %
2486% G e t O n e V i r t u a l P i x e l %
2487% %
2488% %
2489% %
2490%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2491%
2492% GetOneVirtualPixel() returns a single virtual pixel at the specified
2493% (x,y) location. The image background color is returned if an error occurs.
2494% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2495%
2496% The format of the GetOneVirtualPixel() method is:
2497%
cristybb503372010-05-27 20:51:26 +00002498% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2499% const ssize_t y,PixelPacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002500%
2501% A description of each parameter follows:
2502%
2503% o image: the image.
2504%
2505% o x,y: These values define the location of the pixel to return.
2506%
2507% o pixel: return a pixel at the specified (x,y) location.
2508%
2509% o exception: return any errors or warnings in this structure.
2510%
2511*/
2512MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002513 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002514{
2515 GetOneVirtualPixelFromHandler
2516 get_one_virtual_pixel_from_handler;
2517
2518 CacheInfo
2519 *cache_info;
2520
2521 MagickBooleanType
2522 status;
2523
2524 assert(image != (const Image *) NULL);
2525 assert(image->signature == MagickSignature);
2526 assert(image->cache != (Cache) NULL);
2527 cache_info=(CacheInfo *) image->cache;
2528 assert(cache_info->signature == MagickSignature);
2529 *pixel=image->background_color;
2530 get_one_virtual_pixel_from_handler=
2531 cache_info->methods.get_one_virtual_pixel_from_handler;
2532 if (get_one_virtual_pixel_from_handler ==
2533 (GetOneVirtualPixelFromHandler) NULL)
2534 return(MagickFalse);
2535 status=get_one_virtual_pixel_from_handler(image,GetPixelCacheVirtualMethod(
2536 image),x,y,pixel,exception);
2537 return(status);
2538}
2539
2540/*
2541%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2542% %
2543% %
2544% %
2545+ 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 %
2546% %
2547% %
2548% %
2549%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2550%
2551% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2552% specified (x,y) location. The image background color is returned if an
2553% error occurs.
2554%
2555% The format of the GetOneVirtualPixelFromCache() method is:
2556%
2557% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristybb503372010-05-27 20:51:26 +00002558% const VirtualPixelPacket method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002559% PixelPacket *pixel,ExceptionInfo *exception)
2560%
2561% A description of each parameter follows:
2562%
2563% o image: the image.
2564%
2565% o virtual_pixel_method: the virtual pixel method.
2566%
2567% o x,y: These values define the location of the pixel to return.
2568%
2569% o pixel: return a pixel at the specified (x,y) location.
2570%
2571% o exception: return any errors or warnings in this structure.
2572%
2573*/
2574static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002575 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002576 PixelPacket *pixel,ExceptionInfo *exception)
2577{
2578 const PixelPacket
2579 *pixels;
2580
2581 *pixel=image->background_color;
2582 pixels=GetVirtualPixelCache(image,virtual_pixel_method,x,y,1UL,1UL,exception);
2583 if (pixels == (const PixelPacket *) NULL)
2584 return(MagickFalse);
2585 *pixel=(*pixels);
2586 return(MagickTrue);
2587}
2588
2589/*
2590%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2591% %
2592% %
2593% %
2594+ G e t P i x e l C a c h e C o l o r s p a c e %
2595% %
2596% %
2597% %
2598%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2599%
2600% GetPixelCacheColorspace() returns the class type of the pixel cache.
2601%
2602% The format of the GetPixelCacheColorspace() method is:
2603%
2604% Colorspace GetPixelCacheColorspace(Cache cache)
2605%
2606% A description of each parameter follows:
2607%
2608% o cache: the pixel cache.
2609%
2610*/
2611MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
2612{
2613 CacheInfo
2614 *cache_info;
2615
2616 assert(cache != (Cache) NULL);
2617 cache_info=(CacheInfo *) cache;
2618 assert(cache_info->signature == MagickSignature);
2619 if (cache_info->debug != MagickFalse)
2620 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2621 cache_info->filename);
2622 return(cache_info->colorspace);
2623}
2624
2625/*
2626%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2627% %
2628% %
2629% %
2630+ G e t P i x e l C a c h e M e t h o d s %
2631% %
2632% %
2633% %
2634%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2635%
2636% GetPixelCacheMethods() initializes the CacheMethods structure.
2637%
2638% The format of the GetPixelCacheMethods() method is:
2639%
2640% void GetPixelCacheMethods(CacheMethods *cache_methods)
2641%
2642% A description of each parameter follows:
2643%
2644% o cache_methods: Specifies a pointer to a CacheMethods structure.
2645%
2646*/
2647MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
2648{
2649 assert(cache_methods != (CacheMethods *) NULL);
2650 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2651 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2652 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2653 cache_methods->get_virtual_indexes_from_handler=GetVirtualIndexesFromCache;
2654 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2655 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2656 cache_methods->get_authentic_indexes_from_handler=
2657 GetAuthenticIndexesFromCache;
2658 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2659 cache_methods->get_one_authentic_pixel_from_handler=
2660 GetOneAuthenticPixelFromCache;
2661 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2662 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2663 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2664}
2665
2666/*
2667%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2668% %
2669% %
2670% %
2671+ G e t P i x e l C a c h e N e x u s E x t e n t %
2672% %
2673% %
2674% %
2675%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2676%
2677% GetPixelCacheNexusExtent() returns the extent of the pixels associated with
2678% the last call to SetPixelCacheNexusPixels() or GetPixelCacheNexusPixels().
2679%
2680% The format of the GetPixelCacheNexusExtent() method is:
2681%
2682% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2683% NexusInfo *nexus_info)
2684%
2685% A description of each parameter follows:
2686%
2687% o nexus_info: the nexus info.
2688%
2689*/
2690MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2691 NexusInfo *nexus_info)
2692{
2693 CacheInfo
2694 *cache_info;
2695
2696 MagickSizeType
2697 extent;
2698
2699 if (cache == (Cache) NULL)
2700 return(0);
2701 cache_info=(CacheInfo *) cache;
2702 assert(cache_info->signature == MagickSignature);
2703 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2704 if (extent == 0)
2705 return((MagickSizeType) cache_info->columns*cache_info->rows);
2706 return(extent);
2707}
2708
2709/*
2710%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2711% %
2712% %
2713% %
2714+ 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 %
2715% %
2716% %
2717% %
2718%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2719%
2720% GetPixelCacheNexusIndexes() returns the indexes associated with the
2721% specified cache nexus.
2722%
2723% The format of the GetPixelCacheNexusIndexes() method is:
2724%
2725% IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2726% NexusInfo *nexus_info)
2727%
2728% A description of each parameter follows:
2729%
2730% o cache: the pixel cache.
2731%
2732% o nexus_info: the cache nexus to return the colormap indexes.
2733%
2734*/
2735MagickExport IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2736 NexusInfo *nexus_info)
2737{
2738 CacheInfo
2739 *cache_info;
2740
2741 if (cache == (Cache) NULL)
2742 return((IndexPacket *) NULL);
2743 cache_info=(CacheInfo *) cache;
2744 assert(cache_info->signature == MagickSignature);
2745 if (cache_info->storage_class == UndefinedClass)
2746 return((IndexPacket *) NULL);
2747 return(nexus_info->indexes);
2748}
2749
2750/*
2751%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2752% %
2753% %
2754% %
2755+ G e t P i x e l C a c h e N e x u s P i x e l s %
2756% %
2757% %
2758% %
2759%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2760%
2761% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2762% cache nexus.
2763%
2764% The format of the GetPixelCacheNexusPixels() method is:
2765%
2766% PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2767% NexusInfo *nexus_info)
2768%
2769% A description of each parameter follows:
2770%
2771% o cache: the pixel cache.
2772%
2773% o nexus_info: the cache nexus to return the pixels.
2774%
2775*/
2776MagickExport PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2777 NexusInfo *nexus_info)
2778{
2779 CacheInfo
2780 *cache_info;
2781
2782 if (cache == (Cache) NULL)
2783 return((PixelPacket *) NULL);
2784 cache_info=(CacheInfo *) cache;
2785 assert(cache_info->signature == MagickSignature);
2786 if (cache_info->debug != MagickFalse)
2787 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2788 cache_info->filename);
2789 if (cache_info->storage_class == UndefinedClass)
2790 return((PixelPacket *) NULL);
2791 return(nexus_info->pixels);
2792}
2793
2794/*
2795%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2796% %
2797% %
2798% %
cristy056ba772010-01-02 23:33:54 +00002799+ G e t P i x e l C a c h e P i x e l s %
2800% %
2801% %
2802% %
2803%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2804%
2805% GetPixelCachePixels() returns the pixels associated with the specified image.
2806%
2807% The format of the GetPixelCachePixels() method is:
2808%
cristyf84a1932010-01-03 18:00:18 +00002809% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2810% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002811%
2812% A description of each parameter follows:
2813%
2814% o image: the image.
2815%
2816% o length: the pixel cache length.
2817%
cristyf84a1932010-01-03 18:00:18 +00002818% o exception: return any errors or warnings in this structure.
2819%
cristy056ba772010-01-02 23:33:54 +00002820*/
cristyf84a1932010-01-03 18:00:18 +00002821MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2822 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002823{
2824 CacheInfo
2825 *cache_info;
2826
2827 assert(image != (const Image *) NULL);
2828 assert(image->signature == MagickSignature);
2829 if (image->debug != MagickFalse)
2830 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2831 assert(image->cache != (Cache) NULL);
cristyc4c8d132010-01-07 01:58:38 +00002832 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
cristy056ba772010-01-02 23:33:54 +00002833 assert(cache_info->signature == MagickSignature);
2834 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002835 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002836 return((void *) NULL);
2837 *length=cache_info->length;
2838 return((void *) cache_info->pixels);
2839}
2840
2841/*
2842%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2843% %
2844% %
2845% %
cristyb32b90a2009-09-07 21:45:48 +00002846+ 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 +00002847% %
2848% %
2849% %
2850%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2851%
2852% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2853%
2854% The format of the GetPixelCacheStorageClass() method is:
2855%
2856% ClassType GetPixelCacheStorageClass(Cache cache)
2857%
2858% A description of each parameter follows:
2859%
2860% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2861%
2862% o cache: the pixel cache.
2863%
2864*/
2865MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
2866{
2867 CacheInfo
2868 *cache_info;
2869
2870 assert(cache != (Cache) NULL);
2871 cache_info=(CacheInfo *) cache;
2872 assert(cache_info->signature == MagickSignature);
2873 if (cache_info->debug != MagickFalse)
2874 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2875 cache_info->filename);
2876 return(cache_info->storage_class);
2877}
2878
2879/*
2880%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2881% %
2882% %
2883% %
cristyb32b90a2009-09-07 21:45:48 +00002884+ G e t P i x e l C a c h e T i l e S i z e %
2885% %
2886% %
2887% %
2888%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2889%
2890% GetPixelCacheTileSize() returns the pixel cache tile size.
2891%
2892% The format of the GetPixelCacheTileSize() method is:
2893%
cristybb503372010-05-27 20:51:26 +00002894% void GetPixelCacheTileSize(const Image *image,size_t *width,
2895% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002896%
2897% A description of each parameter follows:
2898%
2899% o image: the image.
2900%
2901% o width: the optimize cache tile width in pixels.
2902%
2903% o height: the optimize cache tile height in pixels.
2904%
2905*/
cristybb503372010-05-27 20:51:26 +00002906MagickExport void GetPixelCacheTileSize(const Image *image,size_t *width,
2907 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002908{
2909 CacheInfo
2910 *cache_info;
2911
2912 assert(image != (Image *) NULL);
2913 assert(image->signature == MagickSignature);
2914 if (image->debug != MagickFalse)
2915 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2916 assert(image->cache != (Cache) NULL);
2917 cache_info=(CacheInfo *) image->cache;
2918 assert(cache_info->signature == MagickSignature);
2919 *width=2048UL/sizeof(PixelPacket);
2920 if (GetPixelCacheType(image) == DiskCache)
cristydaa97692009-09-13 02:10:35 +00002921 *width=8192UL/sizeof(PixelPacket);
cristyb32b90a2009-09-07 21:45:48 +00002922 *height=(*width);
2923}
2924
2925/*
2926%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2927% %
2928% %
2929% %
2930+ G e t P i x e l C a c h e T y p e %
2931% %
2932% %
2933% %
2934%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2935%
2936% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2937%
2938% The format of the GetPixelCacheType() method is:
2939%
2940% CacheType GetPixelCacheType(const Image *image)
2941%
2942% A description of each parameter follows:
2943%
2944% o image: the image.
2945%
2946*/
2947MagickExport CacheType GetPixelCacheType(const Image *image)
2948{
2949 CacheInfo
2950 *cache_info;
2951
2952 assert(image != (Image *) NULL);
2953 assert(image->signature == MagickSignature);
2954 if (image->debug != MagickFalse)
2955 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2956 assert(image->cache != (Cache) NULL);
2957 cache_info=(CacheInfo *) image->cache;
2958 assert(cache_info->signature == MagickSignature);
2959 return(cache_info->type);
2960}
2961
2962/*
2963%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2964% %
2965% %
2966% %
cristy3ed852e2009-09-05 21:47:34 +00002967+ 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 %
2968% %
2969% %
2970% %
2971%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2972%
2973% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2974% pixel cache. A virtual pixel is any pixel access that is outside the
2975% boundaries of the image cache.
2976%
2977% The format of the GetPixelCacheVirtualMethod() method is:
2978%
2979% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2980%
2981% A description of each parameter follows:
2982%
2983% o image: the image.
2984%
2985*/
2986MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2987{
2988 CacheInfo
2989 *cache_info;
2990
2991 assert(image != (Image *) NULL);
2992 assert(image->signature == MagickSignature);
2993 if (image->debug != MagickFalse)
2994 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2995 assert(image->cache != (Cache) NULL);
2996 cache_info=(CacheInfo *) image->cache;
2997 assert(cache_info->signature == MagickSignature);
2998 return(cache_info->virtual_pixel_method);
2999}
3000
3001/*
3002%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3003% %
3004% %
3005% %
3006+ 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 %
3007% %
3008% %
3009% %
3010%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3011%
3012% GetVirtualIndexesFromCache() returns the indexes associated with the last
3013% call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3014%
3015% The format of the GetVirtualIndexesFromCache() method is:
3016%
3017% IndexPacket *GetVirtualIndexesFromCache(const Image *image)
3018%
3019% A description of each parameter follows:
3020%
3021% o image: the image.
3022%
3023*/
3024static const IndexPacket *GetVirtualIndexesFromCache(const Image *image)
3025{
3026 CacheInfo
3027 *cache_info;
3028
3029 const IndexPacket
3030 *indexes;
3031
cristybb503372010-05-27 20:51:26 +00003032 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003033 id;
3034
3035 if (image->debug != MagickFalse)
3036 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3037 cache_info=(CacheInfo *) image->cache;
3038 id=GetOpenMPThreadId();
cristybb503372010-05-27 20:51:26 +00003039 assert(id < (ssize_t) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00003040 indexes=GetVirtualIndexesFromNexus(image->cache,cache_info->nexus_info[id]);
3041 return(indexes);
3042}
3043
3044/*
3045%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3046% %
3047% %
3048% %
3049+ 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 %
3050% %
3051% %
3052% %
3053%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3054%
3055% GetVirtualIndexesFromNexus() returns the indexes associated with the
3056% specified cache nexus.
3057%
3058% The format of the GetVirtualIndexesFromNexus() method is:
3059%
3060% const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
3061% NexusInfo *nexus_info)
3062%
3063% A description of each parameter follows:
3064%
3065% o cache: the pixel cache.
3066%
3067% o nexus_info: the cache nexus to return the colormap indexes.
3068%
3069*/
3070MagickExport const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
3071 NexusInfo *nexus_info)
3072{
3073 CacheInfo
3074 *cache_info;
3075
3076 if (cache == (Cache) NULL)
3077 return((IndexPacket *) NULL);
3078 cache_info=(CacheInfo *) cache;
3079 assert(cache_info->signature == MagickSignature);
3080 if (cache_info->storage_class == UndefinedClass)
3081 return((IndexPacket *) NULL);
3082 return(nexus_info->indexes);
3083}
3084
3085/*
3086%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3087% %
3088% %
3089% %
3090% G e t V i r t u a l I n d e x Q u e u e %
3091% %
3092% %
3093% %
3094%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3095%
3096% GetVirtualIndexQueue() returns the virtual black channel or the
3097% colormap indexes associated with the last call to QueueAuthenticPixels() or
3098% GetVirtualPixels(). NULL is returned if the black channel or colormap
3099% indexes are not available.
3100%
3101% The format of the GetVirtualIndexQueue() method is:
3102%
3103% const IndexPacket *GetVirtualIndexQueue(const Image *image)
3104%
3105% A description of each parameter follows:
3106%
3107% o image: the image.
3108%
3109*/
3110MagickExport const IndexPacket *GetVirtualIndexQueue(const Image *image)
3111{
3112 CacheInfo
3113 *cache_info;
3114
3115 assert(image != (const Image *) NULL);
3116 assert(image->signature == MagickSignature);
3117 if (image->debug != MagickFalse)
3118 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3119 assert(image->cache != (Cache) NULL);
3120 cache_info=(CacheInfo *) image->cache;
3121 assert(cache_info->signature == MagickSignature);
3122 if (cache_info->methods.get_virtual_indexes_from_handler ==
3123 (GetVirtualIndexesFromHandler) NULL)
3124 return((IndexPacket *) NULL);
3125 return(cache_info->methods.get_virtual_indexes_from_handler(image));
3126}
3127
3128/*
3129%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3130% %
3131% %
3132% %
3133+ 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 %
3134% %
3135% %
3136% %
3137%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3138%
3139% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3140% pixel cache as defined by the geometry parameters. A pointer to the pixels
3141% is returned if the pixels are transferred, otherwise a NULL is returned.
3142%
3143% The format of the GetVirtualPixelsFromNexus() method is:
3144%
3145% PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003146% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00003147% const size_t columns,const size_t rows,NexusInfo *nexus_info,
3148% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003149%
3150% A description of each parameter follows:
3151%
3152% o image: the image.
3153%
3154% o virtual_pixel_method: the virtual pixel method.
3155%
3156% o x,y,columns,rows: These values define the perimeter of a region of
3157% pixels.
3158%
3159% o nexus_info: the cache nexus to acquire.
3160%
3161% o exception: return any errors or warnings in this structure.
3162%
3163*/
3164
cristybb503372010-05-27 20:51:26 +00003165static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003166 DitherMatrix[64] =
3167 {
3168 0, 48, 12, 60, 3, 51, 15, 63,
3169 32, 16, 44, 28, 35, 19, 47, 31,
3170 8, 56, 4, 52, 11, 59, 7, 55,
3171 40, 24, 36, 20, 43, 27, 39, 23,
3172 2, 50, 14, 62, 1, 49, 13, 61,
3173 34, 18, 46, 30, 33, 17, 45, 29,
3174 10, 58, 6, 54, 9, 57, 5, 53,
3175 42, 26, 38, 22, 41, 25, 37, 21
3176 };
3177
cristybb503372010-05-27 20:51:26 +00003178static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003179{
cristybb503372010-05-27 20:51:26 +00003180 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003181 index;
3182
3183 index=x+DitherMatrix[x & 0x07]-32L;
3184 if (index < 0L)
3185 return(0L);
cristybb503372010-05-27 20:51:26 +00003186 if (index >= (ssize_t) columns)
3187 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00003188 return(index);
3189}
3190
cristybb503372010-05-27 20:51:26 +00003191static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003192{
cristybb503372010-05-27 20:51:26 +00003193 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003194 index;
3195
3196 index=y+DitherMatrix[y & 0x07]-32L;
3197 if (index < 0L)
3198 return(0L);
cristybb503372010-05-27 20:51:26 +00003199 if (index >= (ssize_t) rows)
3200 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00003201 return(index);
3202}
3203
cristybb503372010-05-27 20:51:26 +00003204static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003205{
3206 if (x < 0L)
3207 return(0L);
cristybb503372010-05-27 20:51:26 +00003208 if (x >= (ssize_t) columns)
3209 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003210 return(x);
3211}
3212
cristybb503372010-05-27 20:51:26 +00003213static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003214{
3215 if (y < 0L)
3216 return(0L);
cristybb503372010-05-27 20:51:26 +00003217 if (y >= (ssize_t) rows)
3218 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003219 return(y);
3220}
3221
cristybb503372010-05-27 20:51:26 +00003222static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003223{
cristybb503372010-05-27 20:51:26 +00003224 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003225}
3226
cristybb503372010-05-27 20:51:26 +00003227static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003228{
cristybb503372010-05-27 20:51:26 +00003229 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003230}
3231
3232/*
3233 VirtualPixelModulo() computes the remainder of dividing offset by extent. It
3234 returns not only the quotient (tile the offset falls in) but also the positive
3235 remainer within that tile such that 0 <= remainder < extent. This method is
3236 essentially a ldiv() using a floored modulo division rather than the normal
3237 default truncated modulo division.
3238*/
cristybb503372010-05-27 20:51:26 +00003239static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3240 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003241{
3242 MagickModulo
3243 modulo;
3244
cristybb503372010-05-27 20:51:26 +00003245 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003246 if (offset < 0L)
3247 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003248 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003249 return(modulo);
3250}
3251
3252MagickExport const PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003253 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3254 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003255 ExceptionInfo *exception)
3256{
3257 CacheInfo
3258 *cache_info;
3259
cristyc3ec0d42010-04-07 01:18:08 +00003260 IndexPacket
3261 virtual_index;
3262
cristy3ed852e2009-09-05 21:47:34 +00003263 MagickOffsetType
3264 offset;
3265
3266 MagickSizeType
3267 length,
3268 number_pixels;
3269
3270 NexusInfo
3271 **virtual_nexus;
3272
3273 PixelPacket
3274 *pixels,
3275 virtual_pixel;
3276
3277 RectangleInfo
3278 region;
3279
3280 register const IndexPacket
cristyc3ec0d42010-04-07 01:18:08 +00003281 *restrict virtual_indexes;
cristy3ed852e2009-09-05 21:47:34 +00003282
3283 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003284 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003285
3286 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003287 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003288
cristybb503372010-05-27 20:51:26 +00003289 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003290 u,
3291 v;
3292
3293 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003294 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003295
3296 /*
3297 Acquire pixels.
3298 */
3299 if (image->debug != MagickFalse)
3300 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3301 cache_info=(CacheInfo *) image->cache;
cristy4cfbb3f2010-03-14 20:40:23 +00003302 if (cache_info->type == UndefinedCache)
cristy3ed852e2009-09-05 21:47:34 +00003303 return((const PixelPacket *) NULL);
3304 region.x=x;
3305 region.y=y;
3306 region.width=columns;
3307 region.height=rows;
3308 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
3309 if (pixels == (PixelPacket *) NULL)
3310 return((const PixelPacket *) NULL);
cristydf415c82010-03-11 16:47:50 +00003311 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3312 nexus_info->region.x;
3313 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3314 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003315 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3316 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003317 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3318 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003319 {
3320 MagickBooleanType
3321 status;
3322
3323 /*
3324 Pixel request is inside cache extents.
3325 */
3326 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
3327 return(pixels);
3328 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3329 if (status == MagickFalse)
3330 return((const PixelPacket *) NULL);
3331 if ((cache_info->storage_class == PseudoClass) ||
3332 (cache_info->colorspace == CMYKColorspace))
3333 {
3334 status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
3335 if (status == MagickFalse)
3336 return((const PixelPacket *) NULL);
3337 }
3338 return(pixels);
3339 }
3340 /*
3341 Pixel request is outside cache extents.
3342 */
3343 q=pixels;
3344 indexes=GetPixelCacheNexusIndexes(cache_info,nexus_info);
3345 virtual_nexus=AcquirePixelCacheNexus(1);
3346 if (virtual_nexus == (NexusInfo **) NULL)
3347 {
3348 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3349 "UnableToGetCacheNexus","`%s'",image->filename);
3350 return((const PixelPacket *) NULL);
3351 }
3352 switch (virtual_pixel_method)
3353 {
3354 case BlackVirtualPixelMethod:
3355 {
cristy4789f0d2010-01-10 00:01:06 +00003356 SetRedPixelComponent(&virtual_pixel,0);
3357 SetGreenPixelComponent(&virtual_pixel,0);
3358 SetBluePixelComponent(&virtual_pixel,0);
3359 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003360 break;
3361 }
3362 case GrayVirtualPixelMethod:
3363 {
cristy4789f0d2010-01-10 00:01:06 +00003364 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3365 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3366 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3367 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003368 break;
3369 }
3370 case TransparentVirtualPixelMethod:
3371 {
cristy4789f0d2010-01-10 00:01:06 +00003372 SetRedPixelComponent(&virtual_pixel,0);
3373 SetGreenPixelComponent(&virtual_pixel,0);
3374 SetBluePixelComponent(&virtual_pixel,0);
3375 SetOpacityPixelComponent(&virtual_pixel,TransparentOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003376 break;
3377 }
3378 case MaskVirtualPixelMethod:
3379 case WhiteVirtualPixelMethod:
3380 {
cristy4789f0d2010-01-10 00:01:06 +00003381 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3382 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3383 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3384 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003385 break;
3386 }
3387 default:
3388 {
3389 virtual_pixel=image->background_color;
3390 break;
3391 }
3392 }
cristyc3ec0d42010-04-07 01:18:08 +00003393 virtual_index=0;
cristybb503372010-05-27 20:51:26 +00003394 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003395 {
cristybb503372010-05-27 20:51:26 +00003396 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003397 {
3398 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003399 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003400 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3401 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003402 {
3403 MagickModulo
3404 x_modulo,
3405 y_modulo;
3406
3407 /*
3408 Transfer a single pixel.
3409 */
3410 length=(MagickSizeType) 1;
3411 switch (virtual_pixel_method)
3412 {
3413 case BackgroundVirtualPixelMethod:
3414 case ConstantVirtualPixelMethod:
3415 case BlackVirtualPixelMethod:
3416 case GrayVirtualPixelMethod:
3417 case TransparentVirtualPixelMethod:
3418 case MaskVirtualPixelMethod:
3419 case WhiteVirtualPixelMethod:
3420 {
3421 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003422 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003423 break;
3424 }
3425 case EdgeVirtualPixelMethod:
3426 default:
3427 {
3428 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003429 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003430 1UL,1UL,virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003431 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3432 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003433 break;
3434 }
3435 case RandomVirtualPixelMethod:
3436 {
3437 if (cache_info->random_info == (RandomInfo *) NULL)
3438 cache_info->random_info=AcquireRandomInfo();
3439 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003440 RandomX(cache_info->random_info,cache_info->columns),
3441 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003442 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003443 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3444 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003445 break;
3446 }
3447 case DitherVirtualPixelMethod:
3448 {
3449 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003450 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003451 1UL,1UL,virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003452 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3453 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003454 break;
3455 }
3456 case TileVirtualPixelMethod:
3457 {
3458 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3459 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3460 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3461 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3462 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003463 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3464 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003465 break;
3466 }
3467 case MirrorVirtualPixelMethod:
3468 {
3469 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3470 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003471 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003472 x_modulo.remainder-1L;
3473 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3474 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003475 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003476 y_modulo.remainder-1L;
3477 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3478 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3479 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003480 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3481 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003482 break;
3483 }
3484 case CheckerTileVirtualPixelMethod:
3485 {
3486 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3487 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3488 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3489 {
3490 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003491 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003492 break;
3493 }
3494 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3495 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3496 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003497 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3498 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003499 break;
3500 }
3501 case HorizontalTileVirtualPixelMethod:
3502 {
cristybb503372010-05-27 20:51:26 +00003503 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003504 {
3505 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003506 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003507 break;
3508 }
3509 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3510 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3511 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3512 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3513 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003514 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3515 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003516 break;
3517 }
3518 case VerticalTileVirtualPixelMethod:
3519 {
cristybb503372010-05-27 20:51:26 +00003520 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
cristy3ed852e2009-09-05 21:47:34 +00003521 {
3522 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003523 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003524 break;
3525 }
3526 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3527 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3528 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3529 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3530 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003531 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3532 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003533 break;
3534 }
3535 case HorizontalTileEdgeVirtualPixelMethod:
3536 {
3537 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3538 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003539 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003540 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003541 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3542 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003543 break;
3544 }
3545 case VerticalTileEdgeVirtualPixelMethod:
3546 {
3547 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3548 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003549 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003550 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003551 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3552 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003553 break;
3554 }
3555 }
3556 if (p == (const PixelPacket *) NULL)
3557 break;
3558 *q++=(*p);
cristyc3ec0d42010-04-07 01:18:08 +00003559 if ((indexes != (IndexPacket *) NULL) &&
3560 (virtual_indexes != (const IndexPacket *) NULL))
3561 *indexes++=(*virtual_indexes);
cristy3ed852e2009-09-05 21:47:34 +00003562 continue;
3563 }
3564 /*
3565 Transfer a run of pixels.
3566 */
3567 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,
cristybb503372010-05-27 20:51:26 +00003568 (size_t) length,1UL,virtual_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003569 if (p == (const PixelPacket *) NULL)
3570 break;
cristyc3ec0d42010-04-07 01:18:08 +00003571 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003572 (void) CopyMagickMemory(q,p,(size_t) length*sizeof(*p));
3573 q+=length;
cristyc3ec0d42010-04-07 01:18:08 +00003574 if ((indexes != (IndexPacket *) NULL) &&
3575 (virtual_indexes != (const IndexPacket *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003576 {
cristyc3ec0d42010-04-07 01:18:08 +00003577 (void) CopyMagickMemory(indexes,virtual_indexes,(size_t) length*
3578 sizeof(*virtual_indexes));
3579 indexes+=length;
cristy3ed852e2009-09-05 21:47:34 +00003580 }
3581 }
3582 }
3583 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3584 return(pixels);
3585}
3586
3587/*
3588%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3589% %
3590% %
3591% %
3592+ G e t V i r t u a l P i x e l C a c h e %
3593% %
3594% %
3595% %
3596%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3597%
3598% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3599% cache as defined by the geometry parameters. A pointer to the pixels
3600% is returned if the pixels are transferred, otherwise a NULL is returned.
3601%
3602% The format of the GetVirtualPixelCache() method is:
3603%
3604% const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003605% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3606% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003607% ExceptionInfo *exception)
3608%
3609% A description of each parameter follows:
3610%
3611% o image: the image.
3612%
3613% o virtual_pixel_method: the virtual pixel method.
3614%
3615% o x,y,columns,rows: These values define the perimeter of a region of
3616% pixels.
3617%
3618% o exception: return any errors or warnings in this structure.
3619%
3620*/
3621static const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003622 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3623 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003624{
3625 CacheInfo
3626 *cache_info;
3627
3628 const PixelPacket
3629 *pixels;
3630
cristybb503372010-05-27 20:51:26 +00003631 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003632 id;
3633
3634 if (image->debug != MagickFalse)
3635 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3636 cache_info=(CacheInfo *) image->cache;
3637 id=GetOpenMPThreadId();
cristybb503372010-05-27 20:51:26 +00003638 assert(id < (ssize_t) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00003639 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3640 cache_info->nexus_info[id],exception);
3641 return(pixels);
3642}
3643
3644/*
3645%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3646% %
3647% %
3648% %
3649% G e t V i r t u a l P i x e l Q u e u e %
3650% %
3651% %
3652% %
3653%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3654%
3655% GetVirtualPixelQueue() returns the virtual pixels associated with the
3656% last call to QueueAuthenticPixels() or GetVirtualPixels().
3657%
3658% The format of the GetVirtualPixelQueue() method is:
3659%
3660% const PixelPacket *GetVirtualPixelQueue(const Image image)
3661%
3662% A description of each parameter follows:
3663%
3664% o image: the image.
3665%
3666*/
3667MagickExport const PixelPacket *GetVirtualPixelQueue(const Image *image)
3668{
3669 CacheInfo
3670 *cache_info;
3671
3672 assert(image != (const Image *) NULL);
3673 assert(image->signature == MagickSignature);
3674 if (image->debug != MagickFalse)
3675 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3676 assert(image->cache != (Cache) NULL);
3677 cache_info=(CacheInfo *) image->cache;
3678 assert(cache_info->signature == MagickSignature);
3679 if (cache_info->methods.get_virtual_pixels_handler ==
3680 (GetVirtualPixelsHandler) NULL)
3681 return((PixelPacket *) NULL);
3682 return(cache_info->methods.get_virtual_pixels_handler(image));
3683}
3684
3685/*
3686%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3687% %
3688% %
3689% %
3690% G e t V i r t u a l P i x e l s %
3691% %
3692% %
3693% %
3694%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3695%
3696% GetVirtualPixels() returns an immutable pixel region. If the
3697% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003698% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003699% copy of the pixels or it may point to the original pixels in memory.
3700% Performance is maximized if the selected region is part of one row, or one
3701% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003702% (without a copy) if the image is in memory, or in a memory-mapped file. The
3703% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003704%
3705% Pixels accessed via the returned pointer represent a simple array of type
3706% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
3707% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access
3708% the black color component or to obtain the colormap indexes (of type
3709% IndexPacket) corresponding to the region.
3710%
3711% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3712%
3713% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3714% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3715% GetCacheViewAuthenticPixels() instead.
3716%
3717% The format of the GetVirtualPixels() method is:
3718%
cristybb503372010-05-27 20:51:26 +00003719% const PixelPacket *GetVirtualPixels(const Image *image,const ssize_t x,
3720% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003721% ExceptionInfo *exception)
3722%
3723% A description of each parameter follows:
3724%
3725% o image: the image.
3726%
3727% o x,y,columns,rows: These values define the perimeter of a region of
3728% pixels.
3729%
3730% o exception: return any errors or warnings in this structure.
3731%
3732*/
3733MagickExport const PixelPacket *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003734 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3735 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003736{
3737 CacheInfo
3738 *cache_info;
3739
3740 const PixelPacket
3741 *pixels;
3742
3743 assert(image != (const Image *) NULL);
3744 assert(image->signature == MagickSignature);
3745 if (image->debug != MagickFalse)
3746 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3747 assert(image->cache != (Cache) NULL);
3748 cache_info=(CacheInfo *) image->cache;
3749 assert(cache_info->signature == MagickSignature);
3750 if (cache_info->methods.get_virtual_pixel_handler ==
3751 (GetVirtualPixelHandler) NULL)
3752 return((const PixelPacket *) NULL);
3753 pixels=cache_info->methods.get_virtual_pixel_handler(image,
3754 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception);
3755 return(pixels);
3756}
3757
3758/*
3759%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3760% %
3761% %
3762% %
3763+ G e t V i r t u a l P i x e l s F r o m C a c h e %
3764% %
3765% %
3766% %
3767%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3768%
3769% GetVirtualPixelsCache() returns the pixels associated with the last call
3770% to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3771%
3772% The format of the GetVirtualPixelsCache() method is:
3773%
3774% PixelPacket *GetVirtualPixelsCache(const Image *image)
3775%
3776% A description of each parameter follows:
3777%
3778% o image: the image.
3779%
3780*/
3781static const PixelPacket *GetVirtualPixelsCache(const Image *image)
3782{
3783 CacheInfo
3784 *cache_info;
3785
3786 const PixelPacket
3787 *pixels;
3788
cristybb503372010-05-27 20:51:26 +00003789 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003790 id;
3791
3792 if (image->debug != MagickFalse)
3793 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3794 cache_info=(CacheInfo *) image->cache;
3795 id=GetOpenMPThreadId();
cristybb503372010-05-27 20:51:26 +00003796 assert(id < (ssize_t) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00003797 pixels=GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]);
3798 return(pixels);
3799}
3800
3801/*
3802%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3803% %
3804% %
3805% %
3806+ G e t V i r t u a l P i x e l s N e x u s %
3807% %
3808% %
3809% %
3810%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3811%
3812% GetVirtualPixelsNexus() returns the pixels associated with the specified
3813% cache nexus.
3814%
3815% The format of the GetVirtualPixelsNexus() method is:
3816%
3817% const IndexPacket *GetVirtualPixelsNexus(const Cache cache,
3818% NexusInfo *nexus_info)
3819%
3820% A description of each parameter follows:
3821%
3822% o cache: the pixel cache.
3823%
3824% o nexus_info: the cache nexus to return the colormap pixels.
3825%
3826*/
3827MagickExport const PixelPacket *GetVirtualPixelsNexus(const Cache cache,
3828 NexusInfo *nexus_info)
3829{
3830 CacheInfo
3831 *cache_info;
3832
3833 if (cache == (Cache) NULL)
3834 return((PixelPacket *) NULL);
3835 cache_info=(CacheInfo *) cache;
3836 assert(cache_info->signature == MagickSignature);
3837 if (cache_info->storage_class == UndefinedClass)
3838 return((PixelPacket *) NULL);
3839 return((const PixelPacket *) nexus_info->pixels);
3840}
3841
3842/*
3843%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3844% %
3845% %
3846% %
3847+ M a s k P i x e l C a c h e N e x u s %
3848% %
3849% %
3850% %
3851%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3852%
3853% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3854% The method returns MagickTrue if the pixel region is masked, otherwise
3855% MagickFalse.
3856%
3857% The format of the MaskPixelCacheNexus() method is:
3858%
3859% MagickBooleanType MaskPixelCacheNexus(Image *image,
3860% NexusInfo *nexus_info,ExceptionInfo *exception)
3861%
3862% A description of each parameter follows:
3863%
3864% o image: the image.
3865%
3866% o nexus_info: the cache nexus to clip.
3867%
3868% o exception: return any errors or warnings in this structure.
3869%
3870*/
3871
3872static inline void MagickPixelCompositeMask(const MagickPixelPacket *p,
3873 const MagickRealType alpha,const MagickPixelPacket *q,
3874 const MagickRealType beta,MagickPixelPacket *composite)
3875{
3876 MagickRealType
3877 gamma;
3878
3879 if (alpha == TransparentOpacity)
3880 {
3881 *composite=(*q);
3882 return;
3883 }
3884 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3885 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3886 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3887 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3888 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3889 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3890 composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
3891}
3892
3893static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3894 ExceptionInfo *exception)
3895{
3896 CacheInfo
3897 *cache_info;
3898
3899 MagickPixelPacket
3900 alpha,
3901 beta;
3902
3903 MagickSizeType
3904 number_pixels;
3905
3906 NexusInfo
3907 **clip_nexus,
3908 **image_nexus;
3909
3910 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003911 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003912
3913 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003914 *restrict nexus_indexes,
3915 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003916
cristybb503372010-05-27 20:51:26 +00003917 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003918 i;
3919
3920 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003921 *restrict p,
3922 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003923
3924 /*
3925 Apply clip mask.
3926 */
3927 if (image->debug != MagickFalse)
3928 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3929 if (image->mask == (Image *) NULL)
3930 return(MagickFalse);
3931 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
3932 if (cache_info == (Cache) NULL)
3933 return(MagickFalse);
3934 image_nexus=AcquirePixelCacheNexus(1);
3935 clip_nexus=AcquirePixelCacheNexus(1);
3936 if ((image_nexus == (NexusInfo **) NULL) ||
3937 (clip_nexus == (NexusInfo **) NULL))
3938 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy09449f72010-01-23 03:08:36 +00003939 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,
3940 nexus_info->region.y,nexus_info->region.width,nexus_info->region.height,
3941 image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003942 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
3943 q=nexus_info->pixels;
3944 nexus_indexes=nexus_info->indexes;
3945 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3946 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3947 nexus_info->region.height,clip_nexus[0],&image->exception);
3948 GetMagickPixelPacket(image,&alpha);
3949 GetMagickPixelPacket(image,&beta);
3950 number_pixels=(MagickSizeType) nexus_info->region.width*
3951 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +00003952 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +00003953 {
3954 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
3955 break;
3956 SetMagickPixelPacket(image,p,indexes+i,&alpha);
3957 SetMagickPixelPacket(image,q,nexus_indexes+i,&beta);
3958 MagickPixelCompositeMask(&beta,(MagickRealType) PixelIntensityToQuantum(r),
3959 &alpha,alpha.opacity,&beta);
cristyce70c172010-01-07 17:15:30 +00003960 q->red=ClampToQuantum(beta.red);
3961 q->green=ClampToQuantum(beta.green);
3962 q->blue=ClampToQuantum(beta.blue);
3963 q->opacity=ClampToQuantum(beta.opacity);
cristy3ed852e2009-09-05 21:47:34 +00003964 if (cache_info->active_index_channel != MagickFalse)
3965 nexus_indexes[i]=indexes[i];
3966 p++;
3967 q++;
3968 r++;
3969 }
3970 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3971 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +00003972 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003973 return(MagickFalse);
3974 return(MagickTrue);
3975}
3976
3977/*
3978%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3979% %
3980% %
3981% %
3982+ O p e n P i x e l C a c h e %
3983% %
3984% %
3985% %
3986%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3987%
3988% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3989% dimensions, allocating space for the image pixels and optionally the
3990% colormap indexes, and memory mapping the cache if it is disk based. The
3991% cache nexus array is initialized as well.
3992%
3993% The format of the OpenPixelCache() method is:
3994%
3995% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3996% ExceptionInfo *exception)
3997%
3998% A description of each parameter follows:
3999%
4000% o image: the image.
4001%
4002% o mode: ReadMode, WriteMode, or IOMode.
4003%
4004% o exception: return any errors or warnings in this structure.
4005%
4006*/
4007
cristyd43a46b2010-01-21 02:13:41 +00004008static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00004009{
4010 cache_info->mapped=MagickFalse;
4011 cache_info->pixels=(PixelPacket *) AcquireMagickMemory((size_t)
4012 cache_info->length);
4013 if (cache_info->pixels == (PixelPacket *) NULL)
4014 {
4015 cache_info->mapped=MagickTrue;
4016 cache_info->pixels=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
4017 cache_info->length);
4018 }
4019}
4020
4021static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
4022{
4023 CacheInfo
4024 *cache_info;
4025
4026 MagickOffsetType
4027 count,
4028 extent,
4029 offset;
4030
4031 cache_info=(CacheInfo *) image->cache;
4032 if (image->debug != MagickFalse)
4033 {
4034 char
4035 format[MaxTextExtent],
4036 message[MaxTextExtent];
4037
cristyb9080c92009-12-01 20:13:26 +00004038 (void) FormatMagickSize(length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00004039 (void) FormatMagickString(message,MaxTextExtent,
cristy2ce15c92010-03-12 14:03:41 +00004040 "extend %s (%s[%d], disk, %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00004041 cache_info->cache_filename,cache_info->file,format);
4042 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4043 }
4044 if (length != (MagickSizeType) ((MagickOffsetType) length))
4045 return(MagickFalse);
4046 extent=(MagickOffsetType) MagickSeek(cache_info->file,0,SEEK_END);
4047 if (extent < 0)
4048 return(MagickFalse);
4049 if ((MagickSizeType) extent >= length)
4050 return(MagickTrue);
4051 offset=(MagickOffsetType) length-1;
4052 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
4053 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
4054}
4055
4056static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
4057 ExceptionInfo *exception)
4058{
4059 char
4060 format[MaxTextExtent],
4061 message[MaxTextExtent];
4062
4063 CacheInfo
4064 *cache_info,
4065 source_info;
4066
4067 MagickSizeType
4068 length,
4069 number_pixels;
4070
4071 MagickStatusType
4072 status;
4073
4074 size_t
4075 packet_size;
4076
cristybb503372010-05-27 20:51:26 +00004077 size_t
cristy3ed852e2009-09-05 21:47:34 +00004078 columns;
4079
4080 if (image->debug != MagickFalse)
4081 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4082 if ((image->columns == 0) || (image->rows == 0))
4083 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
4084 cache_info=(CacheInfo *) image->cache;
4085 source_info=(*cache_info);
4086 source_info.file=(-1);
cristye8c25f92010-06-03 00:53:06 +00004087 (void) FormatMagickString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
4088 image->filename,(double) GetImageIndexInList(image));
cristy87528ea2009-09-10 14:53:56 +00004089 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +00004090 cache_info->rows=image->rows;
4091 cache_info->columns=image->columns;
4092 cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
4093 (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
cristy73724512010-04-12 14:43:14 +00004094 if (image->ping != MagickFalse)
4095 {
4096 cache_info->storage_class=image->storage_class;
4097 cache_info->colorspace=image->colorspace;
4098 cache_info->type=PingCache;
4099 cache_info->pixels=(PixelPacket *) NULL;
4100 cache_info->indexes=(IndexPacket *) NULL;
4101 cache_info->length=0;
4102 return(MagickTrue);
4103 }
cristy3ed852e2009-09-05 21:47:34 +00004104 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4105 packet_size=sizeof(PixelPacket);
4106 if (cache_info->active_index_channel != MagickFalse)
4107 packet_size+=sizeof(IndexPacket);
4108 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00004109 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00004110 if (cache_info->columns != columns)
4111 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4112 image->filename);
4113 cache_info->length=length;
4114 status=AcquireMagickResource(AreaResource,cache_info->length);
4115 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4116 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4117 {
4118 status=AcquireMagickResource(MemoryResource,cache_info->length);
4119 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4120 (cache_info->type == MemoryCache))
4121 {
cristyd43a46b2010-01-21 02:13:41 +00004122 AllocatePixelCachePixels(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004123 if (cache_info->pixels == (PixelPacket *) NULL)
4124 cache_info->pixels=source_info.pixels;
4125 else
4126 {
4127 /*
4128 Create memory pixel cache.
4129 */
4130 if (image->debug != MagickFalse)
4131 {
cristy97e7a572009-12-05 15:07:53 +00004132 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004133 format);
cristy3ed852e2009-09-05 21:47:34 +00004134 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004135 "open %s (%s memory, %.20gx%.20g %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00004136 cache_info->mapped != MagickFalse ? "anonymous" : "heap",
cristye8c25f92010-06-03 00:53:06 +00004137 (double) cache_info->columns,(double) cache_info->rows,
4138 format);
cristy3ed852e2009-09-05 21:47:34 +00004139 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4140 message);
4141 }
4142 cache_info->storage_class=image->storage_class;
4143 cache_info->colorspace=image->colorspace;
4144 cache_info->type=MemoryCache;
4145 cache_info->indexes=(IndexPacket *) NULL;
4146 if (cache_info->active_index_channel != MagickFalse)
4147 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4148 number_pixels);
4149 if (source_info.storage_class != UndefinedClass)
4150 {
4151 status|=ClonePixelCachePixels(cache_info,&source_info,
4152 exception);
4153 RelinquishPixelCachePixels(&source_info);
4154 }
4155 return(MagickTrue);
4156 }
4157 }
4158 RelinquishMagickResource(MemoryResource,cache_info->length);
4159 }
4160 /*
4161 Create pixel cache on disk.
4162 */
4163 status=AcquireMagickResource(DiskResource,cache_info->length);
4164 if (status == MagickFalse)
4165 {
4166 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4167 "CacheResourcesExhausted","`%s'",image->filename);
4168 return(MagickFalse);
4169 }
4170 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4171 {
4172 RelinquishMagickResource(DiskResource,cache_info->length);
4173 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4174 image->filename);
4175 return(MagickFalse);
4176 }
4177 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4178 cache_info->length);
4179 if (status == MagickFalse)
4180 {
4181 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4182 image->filename);
4183 return(MagickFalse);
4184 }
4185 cache_info->storage_class=image->storage_class;
4186 cache_info->colorspace=image->colorspace;
4187 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4188 status=AcquireMagickResource(AreaResource,cache_info->length);
4189 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4190 cache_info->type=DiskCache;
4191 else
4192 {
4193 status=AcquireMagickResource(MapResource,cache_info->length);
4194 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4195 (cache_info->type != MemoryCache))
4196 cache_info->type=DiskCache;
4197 else
4198 {
4199 cache_info->pixels=(PixelPacket *) MapBlob(cache_info->file,mode,
4200 cache_info->offset,(size_t) cache_info->length);
4201 if (cache_info->pixels == (PixelPacket *) NULL)
4202 {
4203 cache_info->pixels=source_info.pixels;
4204 cache_info->type=DiskCache;
4205 }
4206 else
4207 {
4208 /*
4209 Create file-backed memory-mapped pixel cache.
4210 */
4211 (void) ClosePixelCacheOnDisk(cache_info);
4212 cache_info->type=MapCache;
4213 cache_info->mapped=MagickTrue;
4214 cache_info->indexes=(IndexPacket *) NULL;
4215 if (cache_info->active_index_channel != MagickFalse)
4216 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4217 number_pixels);
4218 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4219 {
4220 status=ClonePixelCachePixels(cache_info,&source_info,
4221 exception);
4222 RelinquishPixelCachePixels(&source_info);
4223 }
4224 if (image->debug != MagickFalse)
4225 {
cristy97e7a572009-12-05 15:07:53 +00004226 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004227 format);
cristy3ed852e2009-09-05 21:47:34 +00004228 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004229 "open %s (%s[%d], memory-mapped, %.20gx%.20g %sB)",
cristy3ed852e2009-09-05 21:47:34 +00004230 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004231 cache_info->file,(double) cache_info->columns,(double)
4232 cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004233 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4234 message);
4235 }
4236 return(MagickTrue);
4237 }
4238 }
4239 RelinquishMagickResource(MapResource,cache_info->length);
4240 }
4241 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4242 {
4243 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4244 RelinquishPixelCachePixels(&source_info);
4245 }
4246 if (image->debug != MagickFalse)
4247 {
cristyb9080c92009-12-01 20:13:26 +00004248 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00004249 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004250 "open %s (%s[%d], disk, %.20gx%.20g %sB)",cache_info->filename,
4251 cache_info->cache_filename,cache_info->file,(double)
4252 cache_info->columns,(double) cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004253 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4254 }
4255 return(MagickTrue);
4256}
4257
4258/*
4259%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4260% %
4261% %
4262% %
4263+ P e r s i s t P i x e l C a c h e %
4264% %
4265% %
4266% %
4267%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4268%
4269% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4270% persistent pixel cache is one that resides on disk and is not destroyed
4271% when the program exits.
4272%
4273% The format of the PersistPixelCache() method is:
4274%
4275% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4276% const MagickBooleanType attach,MagickOffsetType *offset,
4277% ExceptionInfo *exception)
4278%
4279% A description of each parameter follows:
4280%
4281% o image: the image.
4282%
4283% o filename: the persistent pixel cache filename.
4284%
cristy01b7eb02009-09-10 23:10:14 +00004285% o attach: A value other than zero initializes the persistent pixel
4286% cache.
4287%
cristy3ed852e2009-09-05 21:47:34 +00004288% o initialize: A value other than zero initializes the persistent pixel
4289% cache.
4290%
4291% o offset: the offset in the persistent cache to store pixels.
4292%
4293% o exception: return any errors or warnings in this structure.
4294%
4295*/
4296MagickExport MagickBooleanType PersistPixelCache(Image *image,
4297 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4298 ExceptionInfo *exception)
4299{
4300 CacheInfo
4301 *cache_info,
4302 *clone_info;
4303
4304 Image
4305 clone_image;
4306
cristybb503372010-05-27 20:51:26 +00004307 ssize_t
cristy688f07b2009-09-27 15:19:13 +00004308 page_size;
cristy3ed852e2009-09-05 21:47:34 +00004309
4310 MagickBooleanType
4311 status;
4312
4313 assert(image != (Image *) NULL);
4314 assert(image->signature == MagickSignature);
4315 if (image->debug != MagickFalse)
4316 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4317 assert(image->cache != (void *) NULL);
4318 assert(filename != (const char *) NULL);
4319 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004320 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004321 cache_info=(CacheInfo *) image->cache;
4322 assert(cache_info->signature == MagickSignature);
4323 if (attach != MagickFalse)
4324 {
4325 /*
cristy01b7eb02009-09-10 23:10:14 +00004326 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004327 */
4328 if (image->debug != MagickFalse)
4329 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4330 "attach persistent cache");
4331 (void) CopyMagickString(cache_info->cache_filename,filename,
4332 MaxTextExtent);
4333 cache_info->type=DiskCache;
4334 cache_info->offset=(*offset);
4335 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4336 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004337 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004338 return(MagickTrue);
4339 }
cristy01b7eb02009-09-10 23:10:14 +00004340 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4341 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004342 {
cristyf84a1932010-01-03 18:00:18 +00004343 LockSemaphoreInfo(cache_info->semaphore);
cristy09449f72010-01-23 03:08:36 +00004344 if ((cache_info->mode != ReadMode) &&
4345 (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004346 (cache_info->reference_count == 1))
4347 {
4348 int
4349 status;
4350
4351 /*
cristy01b7eb02009-09-10 23:10:14 +00004352 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004353 */
4354 status=rename(cache_info->cache_filename,filename);
4355 if (status == 0)
4356 {
4357 (void) CopyMagickString(cache_info->cache_filename,filename,
4358 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004359 *offset+=cache_info->length+page_size-(cache_info->length %
4360 page_size);
cristyf84a1932010-01-03 18:00:18 +00004361 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004362 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004363 if (image->debug != MagickFalse)
4364 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4365 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004366 return(MagickTrue);
4367 }
4368 }
cristyf84a1932010-01-03 18:00:18 +00004369 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004370 }
4371 /*
cristy01b7eb02009-09-10 23:10:14 +00004372 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004373 */
4374 clone_image=(*image);
4375 clone_info=(CacheInfo *) clone_image.cache;
4376 image->cache=ClonePixelCache(cache_info);
4377 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4378 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4379 cache_info->type=DiskCache;
4380 cache_info->offset=(*offset);
4381 cache_info=(CacheInfo *) image->cache;
4382 status=ClonePixelCacheNexus(cache_info,clone_info,exception);
4383 if (status != MagickFalse)
4384 {
4385 status=OpenPixelCache(image,IOMode,exception);
4386 if (status != MagickFalse)
4387 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
4388 }
cristy688f07b2009-09-27 15:19:13 +00004389 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004390 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4391 return(status);
4392}
4393
4394/*
4395%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4396% %
4397% %
4398% %
4399+ Q u e u e A u t h e n t i c N e x u s %
4400% %
4401% %
4402% %
4403%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4404%
4405% QueueAuthenticNexus() allocates an region to store image pixels as defined
4406% by the region rectangle and returns a pointer to the region. This region is
4407% subsequently transferred from the pixel cache with
4408% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4409% pixels are transferred, otherwise a NULL is returned.
4410%
4411% The format of the QueueAuthenticNexus() method is:
4412%
cristy5f959472010-05-27 22:19:46 +00004413% PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
4414% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004415% NexusInfo *nexus_info,ExceptionInfo *exception)
4416%
4417% A description of each parameter follows:
4418%
4419% o image: the image.
4420%
4421% o x,y,columns,rows: These values define the perimeter of a region of
4422% pixels.
4423%
4424% o nexus_info: the cache nexus to set.
4425%
4426% o exception: return any errors or warnings in this structure.
4427%
4428*/
cristybb503372010-05-27 20:51:26 +00004429MagickExport PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy30097232010-07-01 02:16:30 +00004430 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
4431 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004432{
4433 CacheInfo
4434 *cache_info;
4435
4436 MagickOffsetType
4437 offset;
4438
4439 MagickSizeType
4440 number_pixels;
4441
4442 RectangleInfo
4443 region;
4444
4445 /*
4446 Validate pixel cache geometry.
4447 */
4448 cache_info=(CacheInfo *) image->cache;
4449 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4450 {
4451 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4452 "NoPixelsDefinedInCache","`%s'",image->filename);
4453 return((PixelPacket *) NULL);
4454 }
cristybb503372010-05-27 20:51:26 +00004455 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4456 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004457 {
4458 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4459 "PixelsAreNotAuthentic","`%s'",image->filename);
4460 return((PixelPacket *) NULL);
4461 }
4462 offset=(MagickOffsetType) y*cache_info->columns+x;
4463 if (offset < 0)
4464 return((PixelPacket *) NULL);
4465 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4466 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4467 if ((MagickSizeType) offset >= number_pixels)
4468 return((PixelPacket *) NULL);
4469 /*
4470 Return pixel cache.
4471 */
4472 region.x=x;
4473 region.y=y;
4474 region.width=columns;
4475 region.height=rows;
4476 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4477}
4478
4479/*
4480%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4481% %
4482% %
4483% %
4484+ 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 %
4485% %
4486% %
4487% %
4488%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4489%
4490% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4491% defined by the region rectangle and returns a pointer to the region. This
4492% region is subsequently transferred from the pixel cache with
4493% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4494% pixels are transferred, otherwise a NULL is returned.
4495%
4496% The format of the QueueAuthenticPixelsCache() method is:
4497%
cristybb503372010-05-27 20:51:26 +00004498% PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4499% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004500% ExceptionInfo *exception)
4501%
4502% A description of each parameter follows:
4503%
4504% o image: the image.
4505%
4506% o x,y,columns,rows: These values define the perimeter of a region of
4507% pixels.
4508%
4509% o exception: return any errors or warnings in this structure.
4510%
4511*/
cristybb503372010-05-27 20:51:26 +00004512static PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4513 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004514 ExceptionInfo *exception)
4515{
4516 CacheInfo
4517 *cache_info;
4518
cristybb503372010-05-27 20:51:26 +00004519 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004520 id;
4521
4522 PixelPacket
4523 *pixels;
4524
4525 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickFalse,exception);
4526 if (cache_info == (Cache) NULL)
4527 return((PixelPacket *) NULL);
4528 id=GetOpenMPThreadId();
cristybb503372010-05-27 20:51:26 +00004529 assert(id < (ssize_t) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00004530 pixels=QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4531 exception);
4532 return(pixels);
4533}
4534
4535/*
4536%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4537% %
4538% %
4539% %
4540% Q u e u e A u t h e n t i c P i x e l s %
4541% %
4542% %
4543% %
4544%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4545%
4546% QueueAuthenticPixels() queues a mutable pixel region. If the region is
4547% successfully intialized a pointer to a PixelPacket array representing the
4548% region is returned, otherwise NULL is returned. The returned pointer may
4549% point to a temporary working buffer for the pixels or it may point to the
4550% final location of the pixels in memory.
4551%
4552% Write-only access means that any existing pixel values corresponding to
4553% the region are ignored. This is useful if the initial image is being
4554% created from scratch, or if the existing pixel values are to be
4555% completely replaced without need to refer to their pre-existing values.
4556% The application is free to read and write the pixel buffer returned by
4557% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4558% initialize the pixel array values. Initializing pixel array values is the
4559% application's responsibility.
4560%
4561% Performance is maximized if the selected region is part of one row, or
4562% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004563% pixels in-place (without a copy) if the image is in memory, or in a
4564% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004565% by the user.
4566%
4567% Pixels accessed via the returned pointer represent a simple array of type
4568% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
4569% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
4570% the black color component or the colormap indexes (of type IndexPacket)
4571% corresponding to the region. Once the PixelPacket (and/or IndexPacket)
4572% array has been updated, the changes must be saved back to the underlying
4573% image using SyncAuthenticPixels() or they may be lost.
4574%
4575% The format of the QueueAuthenticPixels() method is:
4576%
cristy5f959472010-05-27 22:19:46 +00004577% PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4578% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004579% ExceptionInfo *exception)
4580%
4581% A description of each parameter follows:
4582%
4583% o image: the image.
4584%
4585% o x,y,columns,rows: These values define the perimeter of a region of
4586% pixels.
4587%
4588% o exception: return any errors or warnings in this structure.
4589%
4590*/
cristybb503372010-05-27 20:51:26 +00004591MagickExport PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4592 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004593 ExceptionInfo *exception)
4594{
4595 CacheInfo
4596 *cache_info;
4597
4598 PixelPacket
4599 *pixels;
4600
4601 assert(image != (Image *) NULL);
4602 assert(image->signature == MagickSignature);
4603 if (image->debug != MagickFalse)
4604 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4605 assert(image->cache != (Cache) NULL);
4606 cache_info=(CacheInfo *) image->cache;
4607 assert(cache_info->signature == MagickSignature);
4608 if (cache_info->methods.queue_authentic_pixels_handler ==
4609 (QueueAuthenticPixelsHandler) NULL)
4610 return((PixelPacket *) NULL);
4611 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4612 rows,exception);
4613 return(pixels);
4614}
4615
4616/*
4617%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4618% %
4619% %
4620% %
4621+ R e a d P i x e l C a c h e I n d e x e s %
4622% %
4623% %
4624% %
4625%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4626%
4627% ReadPixelCacheIndexes() reads colormap indexes from the specified region of
4628% the pixel cache.
4629%
4630% The format of the ReadPixelCacheIndexes() method is:
4631%
4632% MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4633% NexusInfo *nexus_info,ExceptionInfo *exception)
4634%
4635% A description of each parameter follows:
4636%
4637% o cache_info: the pixel cache.
4638%
4639% o nexus_info: the cache nexus to read the colormap indexes.
4640%
4641% o exception: return any errors or warnings in this structure.
4642%
4643*/
4644static MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4645 NexusInfo *nexus_info,ExceptionInfo *exception)
4646{
4647 MagickOffsetType
4648 count,
4649 offset;
4650
4651 MagickSizeType
4652 length,
4653 number_pixels;
4654
4655 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004656 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004657
cristybb503372010-05-27 20:51:26 +00004658 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004659 y;
4660
cristybb503372010-05-27 20:51:26 +00004661 size_t
cristy3ed852e2009-09-05 21:47:34 +00004662 rows;
4663
4664 if (cache_info->debug != MagickFalse)
4665 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4666 cache_info->filename);
4667 if (cache_info->active_index_channel == MagickFalse)
4668 return(MagickFalse);
4669 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4670 return(MagickTrue);
4671 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4672 nexus_info->region.x;
4673 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
4674 rows=nexus_info->region.height;
4675 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004676 q=nexus_info->indexes;
4677 switch (cache_info->type)
4678 {
4679 case MemoryCache:
4680 case MapCache:
4681 {
4682 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004683 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004684
4685 /*
4686 Read indexes from memory.
4687 */
cristydd341db2010-03-04 19:06:38 +00004688 if ((cache_info->columns == nexus_info->region.width) &&
4689 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4690 {
4691 length=number_pixels;
4692 rows=1UL;
4693 }
cristy3ed852e2009-09-05 21:47:34 +00004694 p=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00004695 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004696 {
4697 (void) CopyMagickMemory(q,p,(size_t) length);
4698 p+=cache_info->columns;
4699 q+=nexus_info->region.width;
4700 }
4701 break;
4702 }
4703 case DiskCache:
4704 {
4705 /*
4706 Read indexes from disk.
4707 */
4708 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4709 {
4710 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4711 cache_info->cache_filename);
4712 return(MagickFalse);
4713 }
cristydd341db2010-03-04 19:06:38 +00004714 if ((cache_info->columns == nexus_info->region.width) &&
4715 (number_pixels < MagickMaxBufferExtent))
4716 {
4717 length=number_pixels;
4718 rows=1UL;
4719 }
cristy3ed852e2009-09-05 21:47:34 +00004720 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004721 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004722 {
4723 count=ReadPixelCacheRegion(cache_info,cache_info->offset+number_pixels*
4724 sizeof(PixelPacket)+offset*sizeof(*q),length,(unsigned char *) q);
4725 if ((MagickSizeType) count < length)
4726 break;
4727 offset+=cache_info->columns;
4728 q+=nexus_info->region.width;
4729 }
cristybb503372010-05-27 20:51:26 +00004730 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004731 {
4732 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4733 cache_info->cache_filename);
4734 return(MagickFalse);
4735 }
4736 break;
4737 }
4738 default:
4739 break;
4740 }
4741 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004742 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004743 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004744 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004745 nexus_info->region.width,(double) nexus_info->region.height,(double)
4746 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004747 return(MagickTrue);
4748}
4749
4750/*
4751%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4752% %
4753% %
4754% %
4755+ R e a d P i x e l C a c h e P i x e l s %
4756% %
4757% %
4758% %
4759%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4760%
4761% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4762% cache.
4763%
4764% The format of the ReadPixelCachePixels() method is:
4765%
4766% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4767% NexusInfo *nexus_info,ExceptionInfo *exception)
4768%
4769% A description of each parameter follows:
4770%
4771% o cache_info: the pixel cache.
4772%
4773% o nexus_info: the cache nexus to read the pixels.
4774%
4775% o exception: return any errors or warnings in this structure.
4776%
4777*/
4778static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4779 NexusInfo *nexus_info,ExceptionInfo *exception)
4780{
4781 MagickOffsetType
4782 count,
4783 offset;
4784
4785 MagickSizeType
4786 length,
4787 number_pixels;
4788
cristybb503372010-05-27 20:51:26 +00004789 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004790 y;
4791
4792 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004793 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004794
cristybb503372010-05-27 20:51:26 +00004795 size_t
cristy3ed852e2009-09-05 21:47:34 +00004796 rows;
4797
4798 if (cache_info->debug != MagickFalse)
4799 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4800 cache_info->filename);
4801 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4802 return(MagickTrue);
4803 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4804 nexus_info->region.x;
4805 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
4806 rows=nexus_info->region.height;
4807 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004808 q=nexus_info->pixels;
4809 switch (cache_info->type)
4810 {
4811 case MemoryCache:
4812 case MapCache:
4813 {
4814 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004815 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004816
4817 /*
4818 Read pixels from memory.
4819 */
cristydd341db2010-03-04 19:06:38 +00004820 if ((cache_info->columns == nexus_info->region.width) &&
4821 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4822 {
4823 length=number_pixels;
4824 rows=1UL;
4825 }
cristy3ed852e2009-09-05 21:47:34 +00004826 p=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00004827 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004828 {
4829 (void) CopyMagickMemory(q,p,(size_t) length);
4830 p+=cache_info->columns;
4831 q+=nexus_info->region.width;
4832 }
4833 break;
4834 }
4835 case DiskCache:
4836 {
4837 /*
4838 Read pixels from disk.
4839 */
4840 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4841 {
4842 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4843 cache_info->cache_filename);
4844 return(MagickFalse);
4845 }
cristydd341db2010-03-04 19:06:38 +00004846 if ((cache_info->columns == nexus_info->region.width) &&
4847 (number_pixels < MagickMaxBufferExtent))
4848 {
4849 length=number_pixels;
4850 rows=1UL;
4851 }
cristybb503372010-05-27 20:51:26 +00004852 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004853 {
4854 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4855 sizeof(*q),length,(unsigned char *) q);
4856 if ((MagickSizeType) count < length)
4857 break;
4858 offset+=cache_info->columns;
4859 q+=nexus_info->region.width;
4860 }
cristybb503372010-05-27 20:51:26 +00004861 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004862 {
4863 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4864 cache_info->cache_filename);
4865 return(MagickFalse);
4866 }
4867 break;
4868 }
4869 default:
4870 break;
4871 }
4872 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004873 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004874 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004875 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004876 nexus_info->region.width,(double) nexus_info->region.height,(double)
4877 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004878 return(MagickTrue);
4879}
4880
4881/*
4882%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4883% %
4884% %
4885% %
4886+ R e f e r e n c e P i x e l C a c h e %
4887% %
4888% %
4889% %
4890%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4891%
4892% ReferencePixelCache() increments the reference count associated with the
4893% pixel cache returning a pointer to the cache.
4894%
4895% The format of the ReferencePixelCache method is:
4896%
4897% Cache ReferencePixelCache(Cache cache_info)
4898%
4899% A description of each parameter follows:
4900%
4901% o cache_info: the pixel cache.
4902%
4903*/
4904MagickExport Cache ReferencePixelCache(Cache cache)
4905{
4906 CacheInfo
4907 *cache_info;
4908
4909 assert(cache != (Cache *) NULL);
4910 cache_info=(CacheInfo *) cache;
4911 assert(cache_info->signature == MagickSignature);
4912 if (cache_info->debug != MagickFalse)
4913 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4914 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00004915 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004916 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004917 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004918 return(cache_info);
4919}
4920
4921/*
4922%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4923% %
4924% %
4925% %
4926+ S e t P i x e l C a c h e M e t h o d s %
4927% %
4928% %
4929% %
4930%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4931%
4932% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4933%
4934% The format of the SetPixelCacheMethods() method is:
4935%
4936% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4937%
4938% A description of each parameter follows:
4939%
4940% o cache: the pixel cache.
4941%
4942% o cache_methods: Specifies a pointer to a CacheMethods structure.
4943%
4944*/
4945MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4946{
4947 CacheInfo
4948 *cache_info;
4949
4950 GetOneAuthenticPixelFromHandler
4951 get_one_authentic_pixel_from_handler;
4952
4953 GetOneVirtualPixelFromHandler
4954 get_one_virtual_pixel_from_handler;
4955
4956 /*
4957 Set cache pixel methods.
4958 */
4959 assert(cache != (Cache) NULL);
4960 assert(cache_methods != (CacheMethods *) NULL);
4961 cache_info=(CacheInfo *) cache;
4962 assert(cache_info->signature == MagickSignature);
4963 if (cache_info->debug != MagickFalse)
4964 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4965 cache_info->filename);
4966 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4967 cache_info->methods.get_virtual_pixel_handler=
4968 cache_methods->get_virtual_pixel_handler;
4969 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4970 cache_info->methods.destroy_pixel_handler=
4971 cache_methods->destroy_pixel_handler;
4972 if (cache_methods->get_virtual_indexes_from_handler !=
4973 (GetVirtualIndexesFromHandler) NULL)
4974 cache_info->methods.get_virtual_indexes_from_handler=
4975 cache_methods->get_virtual_indexes_from_handler;
4976 if (cache_methods->get_authentic_pixels_handler !=
4977 (GetAuthenticPixelsHandler) NULL)
4978 cache_info->methods.get_authentic_pixels_handler=
4979 cache_methods->get_authentic_pixels_handler;
4980 if (cache_methods->queue_authentic_pixels_handler !=
4981 (QueueAuthenticPixelsHandler) NULL)
4982 cache_info->methods.queue_authentic_pixels_handler=
4983 cache_methods->queue_authentic_pixels_handler;
4984 if (cache_methods->sync_authentic_pixels_handler !=
4985 (SyncAuthenticPixelsHandler) NULL)
4986 cache_info->methods.sync_authentic_pixels_handler=
4987 cache_methods->sync_authentic_pixels_handler;
4988 if (cache_methods->get_authentic_pixels_from_handler !=
4989 (GetAuthenticPixelsFromHandler) NULL)
4990 cache_info->methods.get_authentic_pixels_from_handler=
4991 cache_methods->get_authentic_pixels_from_handler;
4992 if (cache_methods->get_authentic_indexes_from_handler !=
4993 (GetAuthenticIndexesFromHandler) NULL)
4994 cache_info->methods.get_authentic_indexes_from_handler=
4995 cache_methods->get_authentic_indexes_from_handler;
4996 get_one_virtual_pixel_from_handler=
4997 cache_info->methods.get_one_virtual_pixel_from_handler;
4998 if (get_one_virtual_pixel_from_handler !=
4999 (GetOneVirtualPixelFromHandler) NULL)
5000 cache_info->methods.get_one_virtual_pixel_from_handler=
5001 cache_methods->get_one_virtual_pixel_from_handler;
5002 get_one_authentic_pixel_from_handler=
5003 cache_methods->get_one_authentic_pixel_from_handler;
5004 if (get_one_authentic_pixel_from_handler !=
5005 (GetOneAuthenticPixelFromHandler) NULL)
5006 cache_info->methods.get_one_authentic_pixel_from_handler=
5007 cache_methods->get_one_authentic_pixel_from_handler;
5008}
5009
5010/*
5011%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5012% %
5013% %
5014% %
5015+ S e t P i x e l C a c h e N e x u s P i x e l s %
5016% %
5017% %
5018% %
5019%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5020%
5021% SetPixelCacheNexusPixels() defines the region of the cache for the
5022% specified cache nexus.
5023%
5024% The format of the SetPixelCacheNexusPixels() method is:
5025%
5026% PixelPacket SetPixelCacheNexusPixels(const Image *image,
5027% const RectangleInfo *region,NexusInfo *nexus_info,
5028% ExceptionInfo *exception)
5029%
5030% A description of each parameter follows:
5031%
5032% o image: the image.
5033%
5034% o region: A pointer to the RectangleInfo structure that defines the
5035% region of this particular cache nexus.
5036%
5037% o nexus_info: the cache nexus to set.
5038%
5039% o exception: return any errors or warnings in this structure.
5040%
5041*/
5042static PixelPacket *SetPixelCacheNexusPixels(const Image *image,
5043 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
5044{
5045 CacheInfo
5046 *cache_info;
5047
5048 MagickBooleanType
5049 status;
5050
cristy3ed852e2009-09-05 21:47:34 +00005051 MagickSizeType
5052 length,
5053 number_pixels;
5054
5055 if (image->debug != MagickFalse)
5056 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5057 cache_info=(CacheInfo *) image->cache;
5058 assert(cache_info->signature == MagickSignature);
5059 if (cache_info->type == UndefinedCache)
5060 return((PixelPacket *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00005061 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00005062 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
5063 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00005064 {
cristybb503372010-05-27 20:51:26 +00005065 ssize_t
cristybad067a2010-02-15 17:20:55 +00005066 x,
5067 y;
cristy3ed852e2009-09-05 21:47:34 +00005068
cristyeaedf062010-05-29 22:36:02 +00005069 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
5070 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00005071 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5072 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristy731c3532010-02-15 15:40:03 +00005073 ((nexus_info->region.height == 1UL) ||
5074 ((nexus_info->region.x == 0) &&
5075 ((nexus_info->region.width == cache_info->columns) ||
5076 ((nexus_info->region.width % cache_info->columns) == 0)))))
5077 {
5078 MagickOffsetType
5079 offset;
5080
5081 /*
5082 Pixels are accessed directly from memory.
5083 */
5084 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5085 nexus_info->region.x;
5086 nexus_info->pixels=cache_info->pixels+offset;
5087 nexus_info->indexes=(IndexPacket *) NULL;
5088 if (cache_info->active_index_channel != MagickFalse)
5089 nexus_info->indexes=cache_info->indexes+offset;
5090 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00005091 }
5092 }
5093 /*
5094 Pixels are stored in a cache region until they are synced to the cache.
5095 */
5096 number_pixels=(MagickSizeType) nexus_info->region.width*
5097 nexus_info->region.height;
5098 length=number_pixels*sizeof(PixelPacket);
5099 if (cache_info->active_index_channel != MagickFalse)
5100 length+=number_pixels*sizeof(IndexPacket);
5101 if (nexus_info->cache == (PixelPacket *) NULL)
5102 {
5103 nexus_info->length=length;
5104 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5105 if (status == MagickFalse)
5106 return((PixelPacket *) NULL);
5107 }
5108 else
5109 if (nexus_info->length != length)
5110 {
5111 RelinquishCacheNexusPixels(nexus_info);
5112 nexus_info->length=length;
5113 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5114 if (status == MagickFalse)
5115 return((PixelPacket *) NULL);
5116 }
5117 nexus_info->pixels=nexus_info->cache;
5118 nexus_info->indexes=(IndexPacket *) NULL;
5119 if (cache_info->active_index_channel != MagickFalse)
5120 nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
5121 return(nexus_info->pixels);
5122}
5123
5124/*
5125%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5126% %
5127% %
5128% %
5129% 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 %
5130% %
5131% %
5132% %
5133%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5134%
5135% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5136% pixel cache and returns the previous setting. A virtual pixel is any pixel
5137% access that is outside the boundaries of the image cache.
5138%
5139% The format of the SetPixelCacheVirtualMethod() method is:
5140%
5141% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5142% const VirtualPixelMethod virtual_pixel_method)
5143%
5144% A description of each parameter follows:
5145%
5146% o image: the image.
5147%
5148% o virtual_pixel_method: choose the type of virtual pixel.
5149%
5150*/
5151MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5152 const VirtualPixelMethod virtual_pixel_method)
5153{
5154 CacheInfo
5155 *cache_info;
5156
5157 VirtualPixelMethod
5158 method;
5159
5160 assert(image != (Image *) NULL);
5161 assert(image->signature == MagickSignature);
5162 if (image->debug != MagickFalse)
5163 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5164 assert(image->cache != (Cache) NULL);
5165 cache_info=(CacheInfo *) image->cache;
5166 assert(cache_info->signature == MagickSignature);
5167 method=cache_info->virtual_pixel_method;
5168 cache_info->virtual_pixel_method=virtual_pixel_method;
5169 return(method);
5170}
5171
5172/*
5173%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5174% %
5175% %
5176% %
5177+ 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 %
5178% %
5179% %
5180% %
5181%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5182%
5183% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5184% in-memory or disk cache. The method returns MagickTrue if the pixel region
5185% is synced, otherwise MagickFalse.
5186%
5187% The format of the SyncAuthenticPixelCacheNexus() method is:
5188%
5189% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5190% NexusInfo *nexus_info,ExceptionInfo *exception)
5191%
5192% A description of each parameter follows:
5193%
5194% o image: the image.
5195%
5196% o nexus_info: the cache nexus to sync.
5197%
5198% o exception: return any errors or warnings in this structure.
5199%
5200*/
5201MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5202 NexusInfo *nexus_info,ExceptionInfo *exception)
5203{
5204 CacheInfo
5205 *cache_info;
5206
5207 MagickBooleanType
5208 status;
5209
5210 /*
5211 Transfer pixels to the cache.
5212 */
5213 assert(image != (Image *) NULL);
5214 assert(image->signature == MagickSignature);
5215 if (image->debug != MagickFalse)
5216 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5217 if (image->cache == (Cache) NULL)
5218 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5219 cache_info=(CacheInfo *) image->cache;
5220 if (cache_info->type == UndefinedCache)
5221 return(MagickFalse);
5222 if ((image->clip_mask != (Image *) NULL) &&
5223 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5224 return(MagickFalse);
5225 if ((image->mask != (Image *) NULL) &&
5226 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5227 return(MagickFalse);
5228 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5229 return(MagickTrue);
5230 assert(cache_info->signature == MagickSignature);
5231 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5232 if ((cache_info->active_index_channel != MagickFalse) &&
5233 (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
5234 return(MagickFalse);
5235 return(status);
5236}
5237
5238/*
5239%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5240% %
5241% %
5242% %
5243+ S y n c A u t h e n t i c P i x e l C a c h e %
5244% %
5245% %
5246% %
5247%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5248%
5249% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5250% or disk cache. The method returns MagickTrue if the pixel region is synced,
5251% otherwise MagickFalse.
5252%
5253% The format of the SyncAuthenticPixelsCache() method is:
5254%
5255% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5256% ExceptionInfo *exception)
5257%
5258% A description of each parameter follows:
5259%
5260% o image: the image.
5261%
5262% o exception: return any errors or warnings in this structure.
5263%
5264*/
5265static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5266 ExceptionInfo *exception)
5267{
5268 CacheInfo
5269 *cache_info;
5270
cristybb503372010-05-27 20:51:26 +00005271 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005272 id;
5273
5274 MagickBooleanType
5275 status;
5276
5277 cache_info=(CacheInfo *) image->cache;
5278 id=GetOpenMPThreadId();
cristybb503372010-05-27 20:51:26 +00005279 assert(id < (ssize_t) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00005280 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5281 exception);
5282 return(status);
5283}
5284
5285/*
5286%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5287% %
5288% %
5289% %
5290% S y n c A u t h e n t i c P i x e l s %
5291% %
5292% %
5293% %
5294%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5295%
5296% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5297% The method returns MagickTrue if the pixel region is flushed, otherwise
5298% MagickFalse.
5299%
5300% The format of the SyncAuthenticPixels() method is:
5301%
5302% MagickBooleanType SyncAuthenticPixels(Image *image,
5303% ExceptionInfo *exception)
5304%
5305% A description of each parameter follows:
5306%
5307% o image: the image.
5308%
5309% o exception: return any errors or warnings in this structure.
5310%
5311*/
5312MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5313 ExceptionInfo *exception)
5314{
5315 CacheInfo
5316 *cache_info;
5317
5318 assert(image != (Image *) NULL);
5319 assert(image->signature == MagickSignature);
5320 if (image->debug != MagickFalse)
5321 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5322 assert(image->cache != (Cache) NULL);
5323 cache_info=(CacheInfo *) image->cache;
5324 assert(cache_info->signature == MagickSignature);
5325 if (cache_info->methods.sync_authentic_pixels_handler ==
5326 (SyncAuthenticPixelsHandler) NULL)
5327 return(MagickFalse);
5328 return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
5329}
5330
5331/*
5332%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5333% %
5334% %
5335% %
5336+ W r i t e P i x e l C a c h e I n d e x e s %
5337% %
5338% %
5339% %
5340%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5341%
5342% WritePixelCacheIndexes() writes the colormap indexes to the specified
5343% region of the pixel cache.
5344%
5345% The format of the WritePixelCacheIndexes() method is:
5346%
5347% MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5348% NexusInfo *nexus_info,ExceptionInfo *exception)
5349%
5350% A description of each parameter follows:
5351%
5352% o cache_info: the pixel cache.
5353%
5354% o nexus_info: the cache nexus to write the colormap indexes.
5355%
5356% o exception: return any errors or warnings in this structure.
5357%
5358*/
5359static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5360 NexusInfo *nexus_info,ExceptionInfo *exception)
5361{
5362 MagickOffsetType
5363 count,
5364 offset;
5365
5366 MagickSizeType
5367 length,
5368 number_pixels;
5369
5370 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005371 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005372
cristybb503372010-05-27 20:51:26 +00005373 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005374 y;
5375
cristybb503372010-05-27 20:51:26 +00005376 size_t
cristy3ed852e2009-09-05 21:47:34 +00005377 rows;
5378
5379 if (cache_info->debug != MagickFalse)
5380 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
5381 cache_info->filename);
5382 if (cache_info->active_index_channel == MagickFalse)
5383 return(MagickFalse);
5384 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5385 return(MagickTrue);
5386 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5387 nexus_info->region.x;
5388 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
5389 rows=nexus_info->region.height;
5390 number_pixels=(MagickSizeType) length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005391 p=nexus_info->indexes;
5392 switch (cache_info->type)
5393 {
5394 case MemoryCache:
5395 case MapCache:
5396 {
5397 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005398 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005399
5400 /*
5401 Write indexes to memory.
5402 */
cristydd341db2010-03-04 19:06:38 +00005403 if ((cache_info->columns == nexus_info->region.width) &&
5404 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5405 {
5406 length=number_pixels;
5407 rows=1UL;
5408 }
cristy3ed852e2009-09-05 21:47:34 +00005409 q=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00005410 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005411 {
5412 (void) CopyMagickMemory(q,p,(size_t) length);
5413 p+=nexus_info->region.width;
5414 q+=cache_info->columns;
5415 }
5416 break;
5417 }
5418 case DiskCache:
5419 {
5420 /*
5421 Write indexes to disk.
5422 */
5423 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5424 {
5425 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5426 cache_info->cache_filename);
5427 return(MagickFalse);
5428 }
cristydd341db2010-03-04 19:06:38 +00005429 if ((cache_info->columns == nexus_info->region.width) &&
5430 (number_pixels < MagickMaxBufferExtent))
5431 {
5432 length=number_pixels;
5433 rows=1UL;
5434 }
cristy3ed852e2009-09-05 21:47:34 +00005435 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005436 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005437 {
5438 count=WritePixelCacheRegion(cache_info,cache_info->offset+number_pixels*
5439 sizeof(PixelPacket)+offset*sizeof(*p),length,
5440 (const unsigned char *) p);
5441 if ((MagickSizeType) count < length)
5442 break;
5443 p+=nexus_info->region.width;
5444 offset+=cache_info->columns;
5445 }
cristybb503372010-05-27 20:51:26 +00005446 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005447 {
5448 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5449 cache_info->cache_filename);
5450 return(MagickFalse);
5451 }
5452 break;
5453 }
5454 default:
5455 break;
5456 }
5457 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005458 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005459 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005460 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005461 nexus_info->region.width,(double) nexus_info->region.height,(double)
5462 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005463 return(MagickTrue);
5464}
5465
5466/*
5467%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5468% %
5469% %
5470% %
5471+ W r i t e C a c h e P i x e l s %
5472% %
5473% %
5474% %
5475%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5476%
5477% WritePixelCachePixels() writes image pixels to the specified region of the
5478% pixel cache.
5479%
5480% The format of the WritePixelCachePixels() method is:
5481%
5482% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5483% NexusInfo *nexus_info,ExceptionInfo *exception)
5484%
5485% A description of each parameter follows:
5486%
5487% o cache_info: the pixel cache.
5488%
5489% o nexus_info: the cache nexus to write the pixels.
5490%
5491% o exception: return any errors or warnings in this structure.
5492%
5493*/
5494static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5495 NexusInfo *nexus_info,ExceptionInfo *exception)
5496{
5497 MagickOffsetType
5498 count,
5499 offset;
5500
5501 MagickSizeType
5502 length,
5503 number_pixels;
5504
cristy3ed852e2009-09-05 21:47:34 +00005505 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005506 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005507
cristybb503372010-05-27 20:51:26 +00005508 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005509 y;
5510
cristybb503372010-05-27 20:51:26 +00005511 size_t
cristy3ed852e2009-09-05 21:47:34 +00005512 rows;
5513
5514 if (cache_info->debug != MagickFalse)
5515 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
5516 cache_info->filename);
5517 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5518 return(MagickTrue);
5519 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5520 nexus_info->region.x;
5521 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
5522 rows=nexus_info->region.height;
5523 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005524 p=nexus_info->pixels;
5525 switch (cache_info->type)
5526 {
5527 case MemoryCache:
5528 case MapCache:
5529 {
5530 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005531 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005532
5533 /*
5534 Write pixels to memory.
5535 */
cristydd341db2010-03-04 19:06:38 +00005536 if ((cache_info->columns == nexus_info->region.width) &&
5537 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5538 {
5539 length=number_pixels;
5540 rows=1UL;
5541 }
cristy3ed852e2009-09-05 21:47:34 +00005542 q=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00005543 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005544 {
5545 (void) CopyMagickMemory(q,p,(size_t) length);
5546 p+=nexus_info->region.width;
5547 q+=cache_info->columns;
5548 }
5549 break;
5550 }
5551 case DiskCache:
5552 {
5553 /*
5554 Write pixels to disk.
5555 */
5556 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5557 {
5558 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5559 cache_info->cache_filename);
5560 return(MagickFalse);
5561 }
cristydd341db2010-03-04 19:06:38 +00005562 if ((cache_info->columns == nexus_info->region.width) &&
5563 (number_pixels < MagickMaxBufferExtent))
5564 {
5565 length=number_pixels;
5566 rows=1UL;
5567 }
cristybb503372010-05-27 20:51:26 +00005568 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005569 {
5570 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5571 sizeof(*p),length,(const unsigned char *) p);
5572 if ((MagickSizeType) count < length)
5573 break;
5574 p+=nexus_info->region.width;
5575 offset+=cache_info->columns;
5576 }
cristybb503372010-05-27 20:51:26 +00005577 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005578 {
5579 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5580 cache_info->cache_filename);
5581 return(MagickFalse);
5582 }
5583 break;
5584 }
5585 default:
5586 break;
5587 }
5588 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005589 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005590 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005591 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005592 nexus_info->region.width,(double) nexus_info->region.height,(double)
5593 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005594 return(MagickTrue);
5595}