blob: ef3dbf259593ee4903c488eb3147819a2777a0dc [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% %
cristy7e41fe82010-12-04 23:12:08 +000020% Copyright 1999-2011 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*/
cristy4c08aed2011-07-01 19:47:50 +000043#include "MagickCore/studio.h"
44#include "MagickCore/blob.h"
45#include "MagickCore/blob-private.h"
46#include "MagickCore/cache.h"
47#include "MagickCore/cache-private.h"
48#include "MagickCore/color-private.h"
49#include "MagickCore/composite-private.h"
50#include "MagickCore/exception.h"
51#include "MagickCore/exception-private.h"
52#include "MagickCore/geometry.h"
53#include "MagickCore/list.h"
54#include "MagickCore/log.h"
55#include "MagickCore/magick.h"
56#include "MagickCore/memory_.h"
57#include "MagickCore/pixel.h"
58#include "MagickCore/pixel-accessor.h"
59#include "MagickCore/policy.h"
60#include "MagickCore/quantum.h"
61#include "MagickCore/random_.h"
62#include "MagickCore/resource_.h"
63#include "MagickCore/semaphore.h"
64#include "MagickCore/splay-tree.h"
65#include "MagickCore/string_.h"
66#include "MagickCore/string-private.h"
67#include "MagickCore/thread-private.h"
68#include "MagickCore/utility.h"
cristy3ed852e2009-09-05 21:47:34 +000069#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
cristy4c08aed2011-07-01 19:47:50 +000099 Quantum
cristy3ed852e2009-09-05 21:47:34 +0000100 *cache,
101 *pixels;
102
cristy4c08aed2011-07-01 19:47:50 +0000103 void
104 *metacontent;
cristy3ed852e2009-09-05 21:47:34 +0000105
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
cristy4c08aed2011-07-01 19:47:50 +0000117static const Quantum
cristybb503372010-05-27 20:51:26 +0000118 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
cristye7cc7cf2010-09-21 13:26:47 +0000119 const ssize_t,const size_t,const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000120 *GetVirtualPixelsCache(const Image *);
121
cristy4c08aed2011-07-01 19:47:50 +0000122static const void
123 *GetVirtualMetacontentFromCache(const Image *);
124
cristy3ed852e2009-09-05 21:47:34 +0000125static MagickBooleanType
cristye7cc7cf2010-09-21 13:26:47 +0000126 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,
127 PixelPacket *,ExceptionInfo *),
128 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
129 const ssize_t,const ssize_t,PixelPacket *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000130 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
cristy4c08aed2011-07-01 19:47:50 +0000131 ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000132 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
133 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
cristy4c08aed2011-07-01 19:47:50 +0000134 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000135 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
136
cristy4c08aed2011-07-01 19:47:50 +0000137static Quantum
cristye7cc7cf2010-09-21 13:26:47 +0000138 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
139 const size_t,ExceptionInfo *),
cristybb503372010-05-27 20:51:26 +0000140 *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
cristy0a922382011-07-16 15:30:34 +0000188 cache_info=(CacheInfo *) AcquireAlignedMemory(1,sizeof(*cache_info));
cristy3ed852e2009-09-05 21:47:34 +0000189 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");
cristy3ed852e2009-09-05 21:47:34 +0000203 cache_info->semaphore=AllocateSemaphoreInfo();
cristy93505cf2010-08-10 21:37:49 +0000204 cache_info->reference_count=1;
cristy3ed852e2009-09-05 21:47:34 +0000205 cache_info->disk_semaphore=AllocateSemaphoreInfo();
206 cache_info->debug=IsEventLogging();
207 cache_info->signature=MagickSignature;
208 if ((cache_resources == (SplayTreeInfo *) NULL) &&
209 (instantiate_cache == MagickFalse))
210 {
cristy4e1dff62009-10-25 20:36:03 +0000211 if (cache_semaphore == (SemaphoreInfo *) NULL)
212 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000213 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000214 if ((cache_resources == (SplayTreeInfo *) NULL) &&
215 (instantiate_cache == MagickFalse))
216 {
217 cache_resources=NewSplayTree((int (*)(const void *,const void *))
218 NULL,(void *(*)(void *)) NULL,(void *(*)(void *)) NULL);
219 instantiate_cache=MagickTrue;
220 }
cristyf84a1932010-01-03 18:00:18 +0000221 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000222 }
223 (void) AddValueToSplayTree(cache_resources,cache_info,cache_info);
224 return((Cache ) cache_info);
225}
226
227/*
228%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
229% %
230% %
231% %
232% A c q u i r e P i x e l C a c h e N e x u s %
233% %
234% %
235% %
236%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
237%
238% AcquirePixelCacheNexus() allocates the NexusInfo structure.
239%
240% The format of the AcquirePixelCacheNexus method is:
241%
cristybb503372010-05-27 20:51:26 +0000242% NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000243%
244% A description of each parameter follows:
245%
246% o number_threads: the number of nexus threads.
247%
248*/
cristy2cd7a752010-08-23 00:48:54 +0000249MagickExport NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000250{
cristy3ed852e2009-09-05 21:47:34 +0000251 NexusInfo
252 **nexus_info;
253
cristye076a6e2010-08-15 19:59:43 +0000254 register ssize_t
255 i;
256
cristy0a922382011-07-16 15:30:34 +0000257 nexus_info=(NexusInfo **) AcquireAlignedMemory(number_threads,
cristy3ed852e2009-09-05 21:47:34 +0000258 sizeof(*nexus_info));
259 if (nexus_info == (NexusInfo **) NULL)
260 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristybb503372010-05-27 20:51:26 +0000261 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000262 {
cristy6a924af2010-09-23 14:02:54 +0000263 nexus_info[i]=(NexusInfo *) AcquireAlignedMemory(1,sizeof(**nexus_info));
cristy3ed852e2009-09-05 21:47:34 +0000264 if (nexus_info[i] == (NexusInfo *) NULL)
265 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
266 (void) ResetMagickMemory(nexus_info[i],0,sizeof(*nexus_info[i]));
267 nexus_info[i]->signature=MagickSignature;
268 }
269 return(nexus_info);
270}
271
272/*
273%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
274% %
275% %
276% %
cristyd43a46b2010-01-21 02:13:41 +0000277+ A c q u i r e P i x e l C a c h e P i x e l s %
278% %
279% %
280% %
281%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
282%
283% AcquirePixelCachePixels() returns the pixels associated with the specified
284% image.
285%
286% The format of the AcquirePixelCachePixels() method is:
287%
288% const void *AcquirePixelCachePixels(const Image *image,
289% MagickSizeType *length,ExceptionInfo *exception)
290%
291% A description of each parameter follows:
292%
293% o image: the image.
294%
295% o length: the pixel cache length.
296%
297% o exception: return any errors or warnings in this structure.
298%
299*/
300MagickExport const void *AcquirePixelCachePixels(const Image *image,
301 MagickSizeType *length,ExceptionInfo *exception)
302{
303 CacheInfo
304 *cache_info;
305
306 assert(image != (const Image *) NULL);
307 assert(image->signature == MagickSignature);
cristyd43a46b2010-01-21 02:13:41 +0000308 assert(exception != (ExceptionInfo *) NULL);
309 assert(exception->signature == MagickSignature);
310 assert(image->cache != (Cache) NULL);
311 cache_info=(CacheInfo *) image->cache;
312 assert(cache_info->signature == MagickSignature);
313 *length=0;
314 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
315 return((const void *) NULL);
316 *length=cache_info->length;
317 return((const void *) cache_info->pixels);
318}
319
320/*
321%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
322% %
323% %
324% %
cristyf34a1452009-10-24 22:29:27 +0000325+ C a c h e C o m p o n e n t G e n e s i s %
326% %
327% %
328% %
329%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
330%
331% CacheComponentGenesis() instantiates the cache component.
332%
333% The format of the CacheComponentGenesis method is:
334%
335% MagickBooleanType CacheComponentGenesis(void)
336%
337*/
338MagickExport MagickBooleanType CacheComponentGenesis(void)
339{
cristy165b6092009-10-26 13:52:10 +0000340 AcquireSemaphoreInfo(&cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000341 return(MagickTrue);
342}
343
344/*
345%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
346% %
347% %
348% %
349+ C a c h e C o m p o n e n t T e r m i n u s %
350% %
351% %
352% %
353%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
354%
355% CacheComponentTerminus() destroys the cache component.
356%
357% The format of the CacheComponentTerminus() method is:
358%
359% CacheComponentTerminus(void)
360%
361*/
362MagickExport void CacheComponentTerminus(void)
363{
cristy18b17442009-10-25 18:36:48 +0000364 if (cache_semaphore == (SemaphoreInfo *) NULL)
365 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000366 LockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000367 if (cache_resources != (SplayTreeInfo *) NULL)
368 cache_resources=DestroySplayTree(cache_resources);
369 instantiate_cache=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +0000370 UnlockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000371 DestroySemaphoreInfo(&cache_semaphore);
372}
373
374/*
375%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
376% %
377% %
378% %
cristy3ed852e2009-09-05 21:47:34 +0000379+ C l i p P i x e l C a c h e N e x u s %
380% %
381% %
382% %
383%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
384%
385% ClipPixelCacheNexus() clips the cache nexus as defined by the image clip
cristy4c08aed2011-07-01 19:47:50 +0000386% mask. It returns MagickTrue if the pixel region is clipped, otherwise
387% MagickFalse.
cristy3ed852e2009-09-05 21:47:34 +0000388%
389% The format of the ClipPixelCacheNexus() method is:
390%
391% MagickBooleanType ClipPixelCacheNexus(Image *image,NexusInfo *nexus_info,
392% ExceptionInfo *exception)
393%
394% A description of each parameter follows:
395%
396% o image: the image.
397%
398% o nexus_info: the cache nexus to clip.
399%
400% o exception: return any errors or warnings in this structure.
401%
402*/
403static MagickBooleanType ClipPixelCacheNexus(Image *image,
404 NexusInfo *nexus_info,ExceptionInfo *exception)
405{
406 CacheInfo
407 *cache_info;
408
409 MagickSizeType
410 number_pixels;
411
412 NexusInfo
413 **clip_nexus,
414 **image_nexus;
415
cristy4c08aed2011-07-01 19:47:50 +0000416 register const Quantum
417 *restrict p,
cristyc47d1f82009-11-26 01:44:43 +0000418 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +0000419
cristy4c08aed2011-07-01 19:47:50 +0000420 register Quantum
cristyc47d1f82009-11-26 01:44:43 +0000421 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000422
cristye076a6e2010-08-15 19:59:43 +0000423 register ssize_t
424 i;
425
cristy3ed852e2009-09-05 21:47:34 +0000426 /*
427 Apply clip mask.
428 */
429 if (image->debug != MagickFalse)
430 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
431 if (image->clip_mask == (Image *) NULL)
432 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +0000433 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +0000434 if (cache_info == (Cache) NULL)
435 return(MagickFalse);
436 image_nexus=AcquirePixelCacheNexus(1);
437 clip_nexus=AcquirePixelCacheNexus(1);
438 if ((image_nexus == (NexusInfo **) NULL) ||
439 (clip_nexus == (NexusInfo **) NULL))
440 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy4c08aed2011-07-01 19:47:50 +0000441 p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
442 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
443 nexus_info->region.height,image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +0000444 q=nexus_info->pixels;
cristy3ed852e2009-09-05 21:47:34 +0000445 r=GetVirtualPixelsFromNexus(image->clip_mask,MaskVirtualPixelMethod,
446 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
447 nexus_info->region.height,clip_nexus[0],exception);
448 number_pixels=(MagickSizeType) nexus_info->region.width*
449 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +0000450 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000451 {
cristy4c08aed2011-07-01 19:47:50 +0000452 if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +0000453 break;
cristy4c08aed2011-07-01 19:47:50 +0000454 if (GetPixelIntensity(image,r) > ((Quantum) QuantumRange/2))
cristy3ed852e2009-09-05 21:47:34 +0000455 {
cristy4c08aed2011-07-01 19:47:50 +0000456 SetPixelRed(image,GetPixelRed(image,p),q);
457 SetPixelGreen(image,GetPixelGreen(image,p),q);
458 SetPixelBlue(image,GetPixelBlue(image,p),q);
459 if (cache_info->colorspace == CMYKColorspace)
460 SetPixelBlack(image,GetPixelBlack(image,p),q);
461 SetPixelAlpha(image,GetPixelAlpha(image,p),q);
cristy3ed852e2009-09-05 21:47:34 +0000462 }
cristyed231572011-07-14 02:18:59 +0000463 p+=GetPixelChannels(image);
464 q+=GetPixelChannels(image);
465 r+=GetPixelChannels(image->clip_mask);
cristy3ed852e2009-09-05 21:47:34 +0000466 }
467 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
468 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +0000469 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +0000470 return(MagickFalse);
471 return(MagickTrue);
472}
473
474/*
475%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
476% %
477% %
478% %
479+ C l o n e P i x e l C a c h e %
480% %
481% %
482% %
483%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
484%
485% ClonePixelCache() clones a pixel cache.
486%
487% The format of the ClonePixelCache() method is:
488%
489% Cache ClonePixelCache(const Cache cache)
490%
491% A description of each parameter follows:
492%
493% o cache: the pixel cache.
494%
495*/
496MagickExport Cache ClonePixelCache(const Cache cache)
497{
498 CacheInfo
499 *clone_info;
500
501 const CacheInfo
502 *cache_info;
503
504 assert(cache != (const Cache) NULL);
505 cache_info=(const CacheInfo *) cache;
506 assert(cache_info->signature == MagickSignature);
507 if (cache_info->debug != MagickFalse)
508 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
509 cache_info->filename);
510 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
511 if (clone_info == (Cache) NULL)
512 return((Cache) NULL);
513 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
514 return((Cache ) clone_info);
515}
516
517/*
518%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
519% %
520% %
521% %
cristy60c44a82009-10-07 00:58:49 +0000522+ 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 +0000523% %
524% %
525% %
526%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
527% ClonePixelCachePixels() clones the source pixel cache to the destination
528% cache.
529%
530% The format of the ClonePixelCachePixels() method is:
531%
532% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
533% CacheInfo *source_info,ExceptionInfo *exception)
534%
535% A description of each parameter follows:
536%
537% o cache_info: the pixel cache.
538%
539% o source_info: the source pixel cache.
540%
541% o exception: return any errors or warnings in this structure.
542%
543*/
544
545static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
546{
547 int
548 status;
549
cristy5ee247a2010-02-12 15:42:34 +0000550 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000551 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000552 if (cache_info->file != -1)
cristy4c08aed2011-07-01 19:47:50 +0000553 {
554 status=close(cache_info->file);
555 cache_info->file=(-1);
556 RelinquishMagickResource(FileResource,1);
557 }
cristyf84a1932010-01-03 18:00:18 +0000558 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000559 return(status == -1 ? MagickFalse : MagickTrue);
560}
561
562static void LimitPixelCacheDescriptors(void)
563{
564 register CacheInfo
565 *p,
566 *q;
567
568 /*
569 Limit # of open file descriptors.
570 */
571 if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
572 return;
cristyf84a1932010-01-03 18:00:18 +0000573 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000574 if (cache_resources == (SplayTreeInfo *) NULL)
575 {
cristyf84a1932010-01-03 18:00:18 +0000576 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000577 return;
578 }
579 ResetSplayTreeIterator(cache_resources);
580 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
581 while (p != (CacheInfo *) NULL)
582 {
583 if ((p->type == DiskCache) && (p->file != -1))
cristy508d9312010-02-10 21:10:30 +0000584 break;
cristy3ed852e2009-09-05 21:47:34 +0000585 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
586 }
587 for (q=p; p != (CacheInfo *) NULL; )
588 {
589 if ((p->type == DiskCache) && (p->file != -1) &&
590 (p->timestamp < q->timestamp))
cristy508d9312010-02-10 21:10:30 +0000591 q=p;
cristy3ed852e2009-09-05 21:47:34 +0000592 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
593 }
594 if (q != (CacheInfo *) NULL)
cristy9e116922010-02-12 20:58:13 +0000595 {
596 /*
597 Close least recently used cache.
598 */
599 (void) close(q->file);
600 q->file=(-1);
601 }
cristyf84a1932010-01-03 18:00:18 +0000602 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000603}
604
605static inline MagickSizeType MagickMax(const MagickSizeType x,
606 const MagickSizeType y)
607{
608 if (x > y)
609 return(x);
610 return(y);
611}
612
613static inline MagickSizeType MagickMin(const MagickSizeType x,
614 const MagickSizeType y)
615{
616 if (x < y)
617 return(x);
618 return(y);
619}
620
621static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
622 const MapMode mode)
623{
624 int
625 file;
626
627 /*
628 Open pixel cache on disk.
629 */
cristyf84a1932010-01-03 18:00:18 +0000630 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000631 if (cache_info->file != -1)
632 {
cristyf84a1932010-01-03 18:00:18 +0000633 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000634 return(MagickTrue); /* cache already open */
635 }
636 LimitPixelCacheDescriptors();
637 if (*cache_info->cache_filename == '\0')
638 file=AcquireUniqueFileResource(cache_info->cache_filename);
639 else
640 switch (mode)
641 {
642 case ReadMode:
643 {
644 file=open(cache_info->cache_filename,O_RDONLY | O_BINARY);
645 break;
646 }
647 case WriteMode:
648 {
649 file=open(cache_info->cache_filename,O_WRONLY | O_CREAT | O_BINARY |
650 O_EXCL,S_MODE);
651 if (file == -1)
652 file=open(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
653 break;
654 }
655 case IOMode:
656 default:
657 {
658 file=open(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
659 O_EXCL,S_MODE);
660 if (file == -1)
661 file=open(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
662 break;
663 }
664 }
665 if (file == -1)
666 {
cristyf84a1932010-01-03 18:00:18 +0000667 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000668 return(MagickFalse);
669 }
670 (void) AcquireMagickResource(FileResource,1);
671 cache_info->file=file;
672 cache_info->timestamp=time(0);
cristyf84a1932010-01-03 18:00:18 +0000673 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000674 return(MagickTrue);
675}
676
677static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
678 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000679 unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000680{
681 register MagickOffsetType
682 i;
683
684 ssize_t
685 count;
686
cristy08a88202010-03-04 19:18:05 +0000687 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000688#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000689 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000690 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000691 {
cristyf84a1932010-01-03 18:00:18 +0000692 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000693 return((MagickOffsetType) -1);
694 }
695#endif
696 count=0;
697 for (i=0; i < (MagickOffsetType) length; i+=count)
698 {
699#if !defined(MAGICKCORE_HAVE_PREAD)
700 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
701 (MagickSizeType) SSIZE_MAX));
702#else
703 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000704 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000705#endif
706 if (count > 0)
707 continue;
708 count=0;
709 if (errno != EINTR)
710 {
711 i=(-1);
712 break;
713 }
714 }
715#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000716 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000717#endif
718 return(i);
719}
720
721static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
722 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000723 const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000724{
725 register MagickOffsetType
726 i;
727
728 ssize_t
729 count;
730
cristy08a88202010-03-04 19:18:05 +0000731 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000732#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000733 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy7f317702011-02-18 20:40:28 +0000734 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
cristy3ed852e2009-09-05 21:47:34 +0000735 {
cristyf84a1932010-01-03 18:00:18 +0000736 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000737 return((MagickOffsetType) -1);
738 }
739#endif
740 count=0;
741 for (i=0; i < (MagickOffsetType) length; i+=count)
742 {
743#if !defined(MAGICKCORE_HAVE_PWRITE)
744 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
745 (MagickSizeType) SSIZE_MAX));
746#else
747 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
cristy94fc8fa2011-02-19 15:27:47 +0000748 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
cristy3ed852e2009-09-05 21:47:34 +0000749#endif
750 if (count > 0)
751 continue;
752 count=0;
753 if (errno != EINTR)
754 {
755 i=(-1);
756 break;
757 }
758 }
759#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000760 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000761#endif
762 return(i);
763}
764
cristy4c08aed2011-07-01 19:47:50 +0000765static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000766 CacheInfo *cache_info,ExceptionInfo *exception)
767{
768 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000769 count;
cristy3ed852e2009-09-05 21:47:34 +0000770
cristy4c08aed2011-07-01 19:47:50 +0000771 register MagickOffsetType
772 i;
cristye076a6e2010-08-15 19:59:43 +0000773
cristybb503372010-05-27 20:51:26 +0000774 size_t
cristy4c08aed2011-07-01 19:47:50 +0000775 length;
cristy3ed852e2009-09-05 21:47:34 +0000776
cristy4c08aed2011-07-01 19:47:50 +0000777 unsigned char
778 *blob;
779
780 /*
781 Clone pixel cache (both caches on disk).
782 */
cristy3ed852e2009-09-05 21:47:34 +0000783 if (cache_info->debug != MagickFalse)
784 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
cristy0a922382011-07-16 15:30:34 +0000785 blob=(unsigned char *) AcquireAlignedMemory(MagickMaxBufferExtent,
cristy4c08aed2011-07-01 19:47:50 +0000786 sizeof(*blob));
787 if (blob == (unsigned char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000788 {
cristy4c08aed2011-07-01 19:47:50 +0000789 (void) ThrowMagickException(exception,GetMagickModule(),
790 ResourceLimitError,"MemoryAllocationFailed","`%s'",
791 cache_info->filename);
792 return(MagickFalse);
793 }
cristy3dedf062011-07-02 14:07:40 +0000794 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000795 {
796 blob=(unsigned char *) RelinquishMagickMemory(blob);
797 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
798 cache_info->cache_filename);
799 return(MagickFalse);
800 }
cristy3dedf062011-07-02 14:07:40 +0000801 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000802 {
803 (void) ClosePixelCacheOnDisk(cache_info);
804 blob=(unsigned char *) RelinquishMagickMemory(blob);
cristy3ed852e2009-09-05 21:47:34 +0000805 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
806 clone_info->cache_filename);
807 return(MagickFalse);
808 }
cristy4c08aed2011-07-01 19:47:50 +0000809 count=0;
810 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
cristy3ed852e2009-09-05 21:47:34 +0000811 {
cristy4c08aed2011-07-01 19:47:50 +0000812 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
813 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
814 blob);
815 if (count <= 0)
cristy3ed852e2009-09-05 21:47:34 +0000816 {
cristy4c08aed2011-07-01 19:47:50 +0000817 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
818 cache_info->cache_filename);
819 break;
cristy3ed852e2009-09-05 21:47:34 +0000820 }
cristy4c08aed2011-07-01 19:47:50 +0000821 length=(size_t) count;
822 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
823 if ((MagickSizeType) count != length)
824 {
825 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
826 clone_info->cache_filename);
827 break;
828 }
829 }
830 (void) ClosePixelCacheOnDisk(clone_info);
831 (void) ClosePixelCacheOnDisk(cache_info);
832 blob=(unsigned char *) RelinquishMagickMemory(blob);
833 if (i < (MagickOffsetType) cache_info->length)
834 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000835 return(MagickTrue);
836}
837
cristy4c08aed2011-07-01 19:47:50 +0000838static MagickBooleanType OptimizedPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000839 CacheInfo *cache_info,ExceptionInfo *exception)
840{
841 MagickOffsetType
cristy4c08aed2011-07-01 19:47:50 +0000842 count;
cristy3ed852e2009-09-05 21:47:34 +0000843
cristy4c08aed2011-07-01 19:47:50 +0000844 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
cristy3ed852e2009-09-05 21:47:34 +0000845 {
cristy3ed852e2009-09-05 21:47:34 +0000846 /*
cristy4c08aed2011-07-01 19:47:50 +0000847 Clone pixel cache (both caches in memory).
cristy3ed852e2009-09-05 21:47:34 +0000848 */
cristy4c08aed2011-07-01 19:47:50 +0000849 if (cache_info->debug != MagickFalse)
850 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
851 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
852 cache_info->length);
853 return(MagickTrue);
854 }
855 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
856 {
857 /*
858 Clone pixel cache (one cache on disk, one in memory).
859 */
860 if (cache_info->debug != MagickFalse)
861 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
862 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000863 {
cristy4c08aed2011-07-01 19:47:50 +0000864 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000865 cache_info->cache_filename);
866 return(MagickFalse);
867 }
cristy4c08aed2011-07-01 19:47:50 +0000868 count=ReadPixelCacheRegion(cache_info,cache_info->offset,
869 cache_info->length,(unsigned char *) clone_info->pixels);
870 (void) ClosePixelCacheOnDisk(cache_info);
871 if ((MagickSizeType) count != cache_info->length)
872 {
873 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
874 cache_info->cache_filename);
875 return(MagickFalse);
876 }
877 return(MagickTrue);
878 }
879 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
880 {
881 /*
882 Clone pixel cache (one cache on disk, one in memory).
883 */
884 if (clone_info->debug != MagickFalse)
885 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
886 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
887 {
888 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
889 clone_info->cache_filename);
890 return(MagickFalse);
891 }
892 count=WritePixelCacheRegion(clone_info,clone_info->offset,
893 clone_info->length,(unsigned char *) cache_info->pixels);
894 (void) ClosePixelCacheOnDisk(clone_info);
895 if ((MagickSizeType) count != clone_info->length)
896 {
897 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
898 clone_info->cache_filename);
899 return(MagickFalse);
900 }
901 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +0000902 }
903 /*
cristy4c08aed2011-07-01 19:47:50 +0000904 Clone pixel cache (both caches on disk).
cristy3ed852e2009-09-05 21:47:34 +0000905 */
cristy4c08aed2011-07-01 19:47:50 +0000906 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +0000907}
908
cristy4c08aed2011-07-01 19:47:50 +0000909static MagickBooleanType UnoptimizedPixelCacheClone(CacheInfo *clone_info,
cristy3ed852e2009-09-05 21:47:34 +0000910 CacheInfo *cache_info,ExceptionInfo *exception)
911{
cristy4c08aed2011-07-01 19:47:50 +0000912 MagickBooleanType
913 status;
cristy3ed852e2009-09-05 21:47:34 +0000914
cristy4c08aed2011-07-01 19:47:50 +0000915 MagickOffsetType
916 cache_offset,
917 clone_offset,
918 count;
919
920 register ssize_t
921 x;
922
923 size_t
cristy3ed852e2009-09-05 21:47:34 +0000924 length;
925
cristy4c08aed2011-07-01 19:47:50 +0000926 ssize_t
cristye076a6e2010-08-15 19:59:43 +0000927 y;
928
cristy4c08aed2011-07-01 19:47:50 +0000929 unsigned char
930 *blob;
cristy3ed852e2009-09-05 21:47:34 +0000931
cristy4c08aed2011-07-01 19:47:50 +0000932 /*
933 Clone pixel cache (unoptimized).
934 */
cristy3ed852e2009-09-05 21:47:34 +0000935 if (cache_info->debug != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000936 {
cristy4c08aed2011-07-01 19:47:50 +0000937 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
938 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
939 else
940 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
941 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
942 else
943 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
944 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
945 else
946 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
947 }
cristyed231572011-07-14 02:18:59 +0000948 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
949 clone_info->number_channels)*sizeof(Quantum),MagickMax(
cristy4c08aed2011-07-01 19:47:50 +0000950 cache_info->metacontent_extent,clone_info->metacontent_extent));
cristy0a922382011-07-16 15:30:34 +0000951 blob=(unsigned char *) AcquireAlignedMemory(length,sizeof(*blob));
cristy4c08aed2011-07-01 19:47:50 +0000952 if (blob == (unsigned char *) NULL)
953 {
954 (void) ThrowMagickException(exception,GetMagickModule(),
955 ResourceLimitError,"MemoryAllocationFailed","`%s'",
956 cache_info->filename);
cristy3ed852e2009-09-05 21:47:34 +0000957 return(MagickFalse);
958 }
cristy4c08aed2011-07-01 19:47:50 +0000959 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
960 cache_offset=0;
961 clone_offset=0;
962 if (cache_info->type == DiskCache)
cristy3ed852e2009-09-05 21:47:34 +0000963 {
cristy4c08aed2011-07-01 19:47:50 +0000964 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000965 {
cristy4c08aed2011-07-01 19:47:50 +0000966 blob=(unsigned char *) RelinquishMagickMemory(blob);
967 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3ed852e2009-09-05 21:47:34 +0000968 cache_info->cache_filename);
969 return(MagickFalse);
970 }
cristy4c08aed2011-07-01 19:47:50 +0000971 cache_offset=cache_info->offset;
972 }
973 if (clone_info->type == DiskCache)
974 {
cristy3dedf062011-07-02 14:07:40 +0000975 if ((cache_info->type == DiskCache) &&
976 (strcmp(cache_info->cache_filename,clone_info->cache_filename) == 0))
977 {
978 (void) ClosePixelCacheOnDisk(clone_info);
979 *clone_info->cache_filename='\0';
980 }
981 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000982 {
cristy4c08aed2011-07-01 19:47:50 +0000983 if (cache_info->type == DiskCache)
984 (void) ClosePixelCacheOnDisk(cache_info);
985 blob=(unsigned char *) RelinquishMagickMemory(blob);
986 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
987 clone_info->cache_filename);
988 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000989 }
cristy4c08aed2011-07-01 19:47:50 +0000990 clone_offset=clone_info->offset;
cristy3ed852e2009-09-05 21:47:34 +0000991 }
992 /*
cristy4c08aed2011-07-01 19:47:50 +0000993 Clone pixel channels.
cristy3ed852e2009-09-05 21:47:34 +0000994 */
cristy4c08aed2011-07-01 19:47:50 +0000995 status=MagickTrue;
996 for (y=0; y < (ssize_t) cache_info->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000997 {
cristy4c08aed2011-07-01 19:47:50 +0000998 for (x=0; x < (ssize_t) cache_info->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000999 {
cristy3ed852e2009-09-05 21:47:34 +00001000 /*
cristy4c08aed2011-07-01 19:47:50 +00001001 Read a set of pixel channels.
cristy3ed852e2009-09-05 21:47:34 +00001002 */
cristyed231572011-07-14 02:18:59 +00001003 length=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001004 if (cache_info->type != DiskCache)
1005 (void) memcpy(blob,(unsigned char *) cache_info->pixels+cache_offset,
1006 length);
cristy3ed852e2009-09-05 21:47:34 +00001007 else
1008 {
cristy4c08aed2011-07-01 19:47:50 +00001009 count=ReadPixelCacheRegion(cache_info,cache_offset,length,blob);
1010 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00001011 {
cristy4c08aed2011-07-01 19:47:50 +00001012 status=MagickFalse;
1013 break;
cristy3ed852e2009-09-05 21:47:34 +00001014 }
1015 }
cristy4c08aed2011-07-01 19:47:50 +00001016 cache_offset+=length;
1017 if ((y < (ssize_t) clone_info->rows) &&
1018 (x < (ssize_t) clone_info->columns))
cristy3ed852e2009-09-05 21:47:34 +00001019 {
cristy4c08aed2011-07-01 19:47:50 +00001020 /*
1021 Write a set of pixel channels.
1022 */
cristyed231572011-07-14 02:18:59 +00001023 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001024 if (clone_info->type != DiskCache)
1025 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1026 blob,length);
1027 else
1028 {
1029 count=WritePixelCacheRegion(clone_info,clone_offset,length,
1030 blob);
1031 if ((MagickSizeType) count != length)
1032 {
1033 status=MagickFalse;
1034 break;
1035 }
1036 }
1037 clone_offset+=length;
cristy3ed852e2009-09-05 21:47:34 +00001038 }
1039 }
cristyed231572011-07-14 02:18:59 +00001040 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001041 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1042 for ( ; x < (ssize_t) clone_info->columns; x++)
1043 {
1044 /*
1045 Set remaining columns with transparent pixel channels.
1046 */
1047 if (clone_info->type != DiskCache)
1048 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
1049 length);
1050 else
1051 {
1052 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1053 if ((MagickSizeType) count != length)
1054 {
1055 status=MagickFalse;
1056 break;
1057 }
1058 }
1059 clone_offset+=length;
1060 }
1061 }
cristyed231572011-07-14 02:18:59 +00001062 length=clone_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00001063 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1064 for ( ; y < (ssize_t) clone_info->rows; y++)
1065 {
1066 /*
1067 Set remaining rows with transparent pixels.
1068 */
1069 for (x=0; x < (ssize_t) clone_info->columns; x++)
1070 {
1071 if (clone_info->type != DiskCache)
1072 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
1073 length);
1074 else
1075 {
1076 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1077 if ((MagickSizeType) count != length)
1078 {
1079 status=MagickFalse;
1080 break;
1081 }
1082 }
1083 clone_offset+=length;
1084 }
1085 }
1086 if ((cache_info->metacontent_extent != 0) &&
1087 (clone_info->metacontent_extent != 0))
1088 {
1089 /*
1090 Clone metacontent.
1091 */
1092 for (y=0; y < (ssize_t) cache_info->rows; y++)
1093 {
1094 for (x=0; x < (ssize_t) cache_info->columns; x++)
1095 {
1096 /*
1097 Read a set of metacontent.
1098 */
1099 length=cache_info->metacontent_extent;
1100 if (cache_info->type != DiskCache)
1101 (void) memcpy(blob,(unsigned char *) cache_info->pixels+
1102 cache_offset,length);
1103 else
1104 {
1105 count=ReadPixelCacheRegion(cache_info,cache_offset,length,blob);
1106 if ((MagickSizeType) count != length)
1107 {
1108 status=MagickFalse;
1109 break;
1110 }
1111 }
1112 cache_offset+=length;
1113 if ((y < (ssize_t) clone_info->rows) &&
1114 (x < (ssize_t) clone_info->columns))
1115 {
1116 /*
1117 Write a set of metacontent.
1118 */
1119 length=clone_info->metacontent_extent;
1120 if (clone_info->type != DiskCache)
1121 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1122 blob,length);
1123 else
1124 {
1125 count=WritePixelCacheRegion(clone_info,clone_offset,length,
1126 blob);
1127 if ((MagickSizeType) count != length)
1128 {
1129 status=MagickFalse;
1130 break;
1131 }
1132 }
1133 clone_offset+=length;
1134 }
1135 }
1136 length=clone_info->metacontent_extent;
1137 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1138 for ( ; x < (ssize_t) clone_info->columns; x++)
1139 {
1140 /*
1141 Set remaining columns with metacontent.
1142 */
1143 if (clone_info->type != DiskCache)
1144 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1145 blob,length);
1146 else
1147 {
1148 count=WritePixelCacheRegion(clone_info,clone_offset,length,
1149 blob);
1150 if ((MagickSizeType) count != length)
1151 {
1152 status=MagickFalse;
1153 break;
1154 }
1155 }
1156 clone_offset+=length;
1157 }
1158 }
1159 length=clone_info->metacontent_extent;
1160 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1161 for ( ; y < (ssize_t) clone_info->rows; y++)
1162 {
1163 /*
1164 Set remaining rows with metacontent.
1165 */
1166 for (x=0; x < (ssize_t) clone_info->columns; x++)
1167 {
1168 if (clone_info->type != DiskCache)
1169 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1170 blob,length);
1171 else
1172 {
1173 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1174 if ((MagickSizeType) count != length)
1175 {
1176 status=MagickFalse;
1177 break;
1178 }
1179 }
1180 clone_offset+=length;
1181 }
1182 }
1183 }
1184 if (clone_info->type == DiskCache)
1185 (void) ClosePixelCacheOnDisk(clone_info);
1186 if (cache_info->type == DiskCache)
1187 (void) ClosePixelCacheOnDisk(cache_info);
1188 blob=(unsigned char *) RelinquishMagickMemory(blob);
1189 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001190}
1191
1192static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1193 CacheInfo *cache_info,ExceptionInfo *exception)
1194{
cristy5a7fbfb2010-11-06 16:10:59 +00001195 if (cache_info->type == PingCache)
1196 return(MagickTrue);
cristy4c08aed2011-07-01 19:47:50 +00001197 if ((cache_info->columns == clone_info->columns) &&
1198 (cache_info->rows == clone_info->rows) &&
cristyed231572011-07-14 02:18:59 +00001199 (cache_info->number_channels == clone_info->number_channels) &&
cristy4c08aed2011-07-01 19:47:50 +00001200 (cache_info->metacontent_extent == clone_info->metacontent_extent))
1201 return(OptimizedPixelCacheClone(clone_info,cache_info,exception));
1202 return(UnoptimizedPixelCacheClone(clone_info,cache_info,exception));
cristy3ed852e2009-09-05 21:47:34 +00001203}
1204
1205/*
1206%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1207% %
1208% %
1209% %
1210+ C l o n e P i x e l C a c h e M e t h o d s %
1211% %
1212% %
1213% %
1214%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1215%
1216% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1217% another.
1218%
1219% The format of the ClonePixelCacheMethods() method is:
1220%
1221% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1222%
1223% A description of each parameter follows:
1224%
1225% o clone: Specifies a pointer to a Cache structure.
1226%
1227% o cache: the pixel cache.
1228%
1229*/
1230MagickExport void ClonePixelCacheMethods(Cache clone,const Cache cache)
1231{
1232 CacheInfo
1233 *cache_info,
1234 *source_info;
1235
1236 assert(clone != (Cache) NULL);
1237 source_info=(CacheInfo *) clone;
1238 assert(source_info->signature == MagickSignature);
1239 if (source_info->debug != MagickFalse)
1240 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1241 source_info->filename);
1242 assert(cache != (Cache) NULL);
1243 cache_info=(CacheInfo *) cache;
1244 assert(cache_info->signature == MagickSignature);
1245 source_info->methods=cache_info->methods;
1246}
1247
1248/*
1249%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1250% %
1251% %
1252% %
1253+ D e s t r o y I m a g e P i x e l C a c h e %
1254% %
1255% %
1256% %
1257%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1258%
1259% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1260%
1261% The format of the DestroyImagePixelCache() method is:
1262%
1263% void DestroyImagePixelCache(Image *image)
1264%
1265% A description of each parameter follows:
1266%
1267% o image: the image.
1268%
1269*/
1270static void DestroyImagePixelCache(Image *image)
1271{
1272 assert(image != (Image *) NULL);
1273 assert(image->signature == MagickSignature);
1274 if (image->debug != MagickFalse)
1275 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1276 if (image->cache == (void *) NULL)
1277 return;
1278 image->cache=DestroyPixelCache(image->cache);
1279}
1280
1281/*
1282%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1283% %
1284% %
1285% %
1286+ D e s t r o y I m a g e P i x e l s %
1287% %
1288% %
1289% %
1290%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1291%
1292% DestroyImagePixels() deallocates memory associated with the pixel cache.
1293%
1294% The format of the DestroyImagePixels() method is:
1295%
1296% void DestroyImagePixels(Image *image)
1297%
1298% A description of each parameter follows:
1299%
1300% o image: the image.
1301%
1302*/
1303MagickExport void DestroyImagePixels(Image *image)
1304{
1305 CacheInfo
1306 *cache_info;
1307
1308 assert(image != (const Image *) NULL);
1309 assert(image->signature == MagickSignature);
1310 if (image->debug != MagickFalse)
1311 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1312 assert(image->cache != (Cache) NULL);
1313 cache_info=(CacheInfo *) image->cache;
1314 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001315 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1316 {
1317 cache_info->methods.destroy_pixel_handler(image);
1318 return;
1319 }
cristy2036f5c2010-09-19 21:18:17 +00001320 image->cache=DestroyPixelCache(image->cache);
cristy3ed852e2009-09-05 21:47:34 +00001321}
1322
1323/*
1324%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1325% %
1326% %
1327% %
1328+ D e s t r o y P i x e l C a c h e %
1329% %
1330% %
1331% %
1332%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1333%
1334% DestroyPixelCache() deallocates memory associated with the pixel cache.
1335%
1336% The format of the DestroyPixelCache() method is:
1337%
1338% Cache DestroyPixelCache(Cache cache)
1339%
1340% A description of each parameter follows:
1341%
1342% o cache: the pixel cache.
1343%
1344*/
1345
1346static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1347{
1348 switch (cache_info->type)
1349 {
1350 case MemoryCache:
1351 {
1352 if (cache_info->mapped == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001353 cache_info->pixels=(Quantum *) RelinquishMagickMemory(
cristy3ed852e2009-09-05 21:47:34 +00001354 cache_info->pixels);
1355 else
cristy4c08aed2011-07-01 19:47:50 +00001356 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
cristy3ed852e2009-09-05 21:47:34 +00001357 (size_t) cache_info->length);
1358 RelinquishMagickResource(MemoryResource,cache_info->length);
1359 break;
1360 }
1361 case MapCache:
1362 {
cristy4c08aed2011-07-01 19:47:50 +00001363 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00001364 cache_info->length);
1365 RelinquishMagickResource(MapResource,cache_info->length);
1366 }
1367 case DiskCache:
1368 {
1369 if (cache_info->file != -1)
1370 (void) ClosePixelCacheOnDisk(cache_info);
1371 RelinquishMagickResource(DiskResource,cache_info->length);
1372 break;
1373 }
1374 default:
1375 break;
1376 }
1377 cache_info->type=UndefinedCache;
1378 cache_info->mapped=MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001379 cache_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001380}
1381
1382MagickExport Cache DestroyPixelCache(Cache cache)
1383{
1384 CacheInfo
1385 *cache_info;
1386
cristy3ed852e2009-09-05 21:47:34 +00001387 assert(cache != (Cache) NULL);
1388 cache_info=(CacheInfo *) cache;
1389 assert(cache_info->signature == MagickSignature);
1390 if (cache_info->debug != MagickFalse)
1391 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1392 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001393 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001394 cache_info->reference_count--;
1395 if (cache_info->reference_count != 0)
1396 {
cristyf84a1932010-01-03 18:00:18 +00001397 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001398 return((Cache) NULL);
1399 }
cristyf84a1932010-01-03 18:00:18 +00001400 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001401 if (cache_resources != (SplayTreeInfo *) NULL)
1402 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
cristy5b8de732009-09-10 23:50:40 +00001403 if (cache_info->debug != MagickFalse)
1404 {
1405 char
1406 message[MaxTextExtent];
1407
cristyb51dff52011-05-19 16:55:47 +00001408 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
cristy5b8de732009-09-10 23:50:40 +00001409 cache_info->filename);
1410 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1411 }
cristyc2e1bdd2009-09-10 23:43:34 +00001412 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1413 (cache_info->type != DiskCache)))
1414 RelinquishPixelCachePixels(cache_info);
1415 else
1416 {
1417 RelinquishPixelCachePixels(cache_info);
1418 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1419 }
cristy3ed852e2009-09-05 21:47:34 +00001420 *cache_info->cache_filename='\0';
1421 if (cache_info->nexus_info != (NexusInfo **) NULL)
1422 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1423 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001424 if (cache_info->random_info != (RandomInfo *) NULL)
1425 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001426 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1427 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1428 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1429 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001430 cache_info->signature=(~MagickSignature);
cristyb41ee102010-10-04 16:46:15 +00001431 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00001432 cache=(Cache) NULL;
1433 return(cache);
1434}
1435
1436/*
1437%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1438% %
1439% %
1440% %
1441+ D e s t r o y P i x e l C a c h e N e x u s %
1442% %
1443% %
1444% %
1445%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1446%
1447% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1448%
1449% The format of the DestroyPixelCacheNexus() method is:
1450%
1451% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001452% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001453%
1454% A description of each parameter follows:
1455%
1456% o nexus_info: the nexus to destroy.
1457%
1458% o number_threads: the number of nexus threads.
1459%
1460*/
1461
1462static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1463{
1464 if (nexus_info->mapped == MagickFalse)
1465 (void) RelinquishMagickMemory(nexus_info->cache);
1466 else
1467 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00001468 nexus_info->cache=(Quantum *) NULL;
1469 nexus_info->pixels=(Quantum *) NULL;
1470 nexus_info->metacontent=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00001471 nexus_info->length=0;
1472 nexus_info->mapped=MagickFalse;
1473}
1474
1475MagickExport NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001476 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001477{
cristybb503372010-05-27 20:51:26 +00001478 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001479 i;
1480
1481 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001482 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001483 {
cristy4c08aed2011-07-01 19:47:50 +00001484 if (nexus_info[i]->cache != (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001485 RelinquishCacheNexusPixels(nexus_info[i]);
1486 nexus_info[i]->signature=(~MagickSignature);
cristy0a922382011-07-16 15:30:34 +00001487 nexus_info[i]=(NexusInfo *) RelinquishMagickMemory(nexus_info[i]);
cristy3ed852e2009-09-05 21:47:34 +00001488 }
cristyb41ee102010-10-04 16:46:15 +00001489 nexus_info=(NexusInfo **) RelinquishMagickMemory(nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00001490 return(nexus_info);
1491}
1492
1493/*
1494%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1495% %
1496% %
1497% %
cristy4c08aed2011-07-01 19:47:50 +00001498% G e t A u t h e n t i c M e t a c o n t e n t %
cristy3ed852e2009-09-05 21:47:34 +00001499% %
1500% %
1501% %
1502%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1503%
cristy4c08aed2011-07-01 19:47:50 +00001504% GetAuthenticMetacontent() returns the authentic metacontent corresponding
1505% with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1506% returned if the associated pixels are not available.
cristy3ed852e2009-09-05 21:47:34 +00001507%
cristy4c08aed2011-07-01 19:47:50 +00001508% The format of the GetAuthenticMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00001509%
cristy4c08aed2011-07-01 19:47:50 +00001510% void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001511%
1512% A description of each parameter follows:
1513%
1514% o image: the image.
1515%
1516*/
cristy4c08aed2011-07-01 19:47:50 +00001517MagickExport void *GetAuthenticMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001518{
1519 CacheInfo
1520 *cache_info;
1521
cristy5c9e6f22010-09-17 17:31:01 +00001522 const int
1523 id = GetOpenMPThreadId();
1524
cristy4c08aed2011-07-01 19:47:50 +00001525 void
1526 *metacontent;
1527
cristye7cc7cf2010-09-21 13:26:47 +00001528 assert(image != (const Image *) NULL);
1529 assert(image->signature == MagickSignature);
1530 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001531 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001532 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001533 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1534 (GetAuthenticMetacontentFromHandler) NULL)
1535 {
1536 metacontent=cache_info->methods.
1537 get_authentic_metacontent_from_handler(image);
1538 return(metacontent);
1539 }
cristy6ebe97c2010-07-03 01:17:28 +00001540 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001541 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1542 cache_info->nexus_info[id]);
1543 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001544}
1545
1546/*
1547%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1548% %
1549% %
1550% %
cristy4c08aed2011-07-01 19:47:50 +00001551+ G e t A u t h e n t i c M e t a c o n t e n t F r o m C a c h e %
cristy3ed852e2009-09-05 21:47:34 +00001552% %
1553% %
1554% %
1555%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1556%
cristy4c08aed2011-07-01 19:47:50 +00001557% GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1558% with the last call to QueueAuthenticPixelsCache() or
1559% GetAuthenticPixelsCache().
cristy3ed852e2009-09-05 21:47:34 +00001560%
cristy4c08aed2011-07-01 19:47:50 +00001561% The format of the GetAuthenticMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00001562%
cristy4c08aed2011-07-01 19:47:50 +00001563% void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001564%
1565% A description of each parameter follows:
1566%
1567% o image: the image.
1568%
1569*/
cristy4c08aed2011-07-01 19:47:50 +00001570static void *GetAuthenticMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001571{
1572 CacheInfo
1573 *cache_info;
1574
cristy2036f5c2010-09-19 21:18:17 +00001575 const int
1576 id = GetOpenMPThreadId();
1577
cristy4c08aed2011-07-01 19:47:50 +00001578 void
1579 *metacontent;
1580
cristy3ed852e2009-09-05 21:47:34 +00001581 assert(image != (const Image *) NULL);
1582 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001583 assert(image->cache != (Cache) NULL);
1584 cache_info=(CacheInfo *) image->cache;
1585 assert(cache_info->signature == MagickSignature);
cristy2036f5c2010-09-19 21:18:17 +00001586 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001587 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1588 cache_info->nexus_info[id]);
1589 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00001590}
1591
1592/*
1593%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1594% %
1595% %
1596% %
1597+ 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 %
1598% %
1599% %
1600% %
1601%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1602%
1603% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1604% disk pixel cache as defined by the geometry parameters. A pointer to the
1605% pixels is returned if the pixels are transferred, otherwise a NULL is
1606% returned.
1607%
1608% The format of the GetAuthenticPixelCacheNexus() method is:
1609%
cristy4c08aed2011-07-01 19:47:50 +00001610% Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001611% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001612% NexusInfo *nexus_info,ExceptionInfo *exception)
1613%
1614% A description of each parameter follows:
1615%
1616% o image: the image.
1617%
1618% o x,y,columns,rows: These values define the perimeter of a region of
1619% pixels.
1620%
1621% o nexus_info: the cache nexus to return.
1622%
1623% o exception: return any errors or warnings in this structure.
1624%
1625*/
1626
cristy4c08aed2011-07-01 19:47:50 +00001627static inline MagickBooleanType IsPixelAuthentic(const CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00001628 NexusInfo *nexus_info)
1629{
cristy4c08aed2011-07-01 19:47:50 +00001630 MagickBooleanType
1631 status;
1632
cristy3ed852e2009-09-05 21:47:34 +00001633 MagickOffsetType
1634 offset;
1635
cristy73724512010-04-12 14:43:14 +00001636 if (cache_info->type == PingCache)
1637 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001638 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1639 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00001640 status=nexus_info->pixels == (cache_info->pixels+offset*
cristyed231572011-07-14 02:18:59 +00001641 cache_info->number_channels) ? MagickTrue : MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00001642 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001643}
1644
cristy4c08aed2011-07-01 19:47:50 +00001645MagickExport Quantum *GetAuthenticPixelCacheNexus(Image *image,
cristye076a6e2010-08-15 19:59:43 +00001646 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001647 NexusInfo *nexus_info,ExceptionInfo *exception)
1648{
1649 CacheInfo
1650 *cache_info;
1651
cristy4c08aed2011-07-01 19:47:50 +00001652 Quantum
cristy3ed852e2009-09-05 21:47:34 +00001653 *pixels;
1654
1655 /*
1656 Transfer pixels from the cache.
1657 */
1658 assert(image != (Image *) NULL);
1659 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001660 pixels=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00001661 if (pixels == (Quantum *) NULL)
1662 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001663 cache_info=(CacheInfo *) image->cache;
1664 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00001665 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001666 return(pixels);
1667 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001668 return((Quantum *) NULL);
1669 if (cache_info->metacontent_extent != 0)
1670 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1671 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001672 return(pixels);
1673}
1674
1675/*
1676%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1677% %
1678% %
1679% %
1680+ 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 %
1681% %
1682% %
1683% %
1684%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1685%
1686% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1687% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1688%
1689% The format of the GetAuthenticPixelsFromCache() method is:
1690%
cristy4c08aed2011-07-01 19:47:50 +00001691% Quantum *GetAuthenticPixelsFromCache(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001692%
1693% A description of each parameter follows:
1694%
1695% o image: the image.
1696%
1697*/
cristy4c08aed2011-07-01 19:47:50 +00001698static Quantum *GetAuthenticPixelsFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001699{
1700 CacheInfo
1701 *cache_info;
1702
cristy5c9e6f22010-09-17 17:31:01 +00001703 const int
1704 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001705
cristye7cc7cf2010-09-21 13:26:47 +00001706 assert(image != (const Image *) NULL);
1707 assert(image->signature == MagickSignature);
1708 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001709 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00001710 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001711 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001712 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001713}
1714
1715/*
1716%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1717% %
1718% %
1719% %
1720% G e t A u t h e n t i c P i x e l Q u e u e %
1721% %
1722% %
1723% %
1724%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1725%
cristy4c08aed2011-07-01 19:47:50 +00001726% GetAuthenticPixelQueue() returns the authentic pixels associated
1727% corresponding with the last call to QueueAuthenticPixels() or
1728% GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001729%
1730% The format of the GetAuthenticPixelQueue() method is:
1731%
cristy4c08aed2011-07-01 19:47:50 +00001732% Quantum *GetAuthenticPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00001733%
1734% A description of each parameter follows:
1735%
1736% o image: the image.
1737%
1738*/
cristy4c08aed2011-07-01 19:47:50 +00001739MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00001740{
1741 CacheInfo
1742 *cache_info;
1743
cristy2036f5c2010-09-19 21:18:17 +00001744 const int
1745 id = GetOpenMPThreadId();
1746
cristy3ed852e2009-09-05 21:47:34 +00001747 assert(image != (const Image *) NULL);
1748 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001749 assert(image->cache != (Cache) NULL);
1750 cache_info=(CacheInfo *) image->cache;
1751 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001752 if (cache_info->methods.get_authentic_pixels_from_handler !=
1753 (GetAuthenticPixelsFromHandler) NULL)
1754 return(cache_info->methods.get_authentic_pixels_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001755 assert(id < (int) cache_info->number_threads);
1756 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001757}
1758
1759/*
1760%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1761% %
1762% %
1763% %
1764% G e t A u t h e n t i c P i x e l s %
1765% %
1766% %
cristy4c08aed2011-07-01 19:47:50 +00001767% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cristy3ed852e2009-09-05 21:47:34 +00001768%
1769% GetAuthenticPixels() obtains a pixel region for read/write access. If the
cristy4c08aed2011-07-01 19:47:50 +00001770% region is successfully accessed, a pointer to a Quantum array
cristy3ed852e2009-09-05 21:47:34 +00001771% representing the region is returned, otherwise NULL is returned.
1772%
1773% The returned pointer may point to a temporary working copy of the pixels
1774% or it may point to the original pixels in memory. Performance is maximized
1775% if the selected region is part of one row, or one or more full rows, since
1776% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001777% if the image is in memory, or in a memory-mapped file. The returned pointer
1778% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001779%
1780% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00001781% Quantum. If the image has corresponding metacontent,call
1782% GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1783% meta-content corresponding to the region. Once the Quantum array has
1784% been updated, the changes must be saved back to the underlying image using
1785% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00001786%
1787% The format of the GetAuthenticPixels() method is:
1788%
cristy4c08aed2011-07-01 19:47:50 +00001789% Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00001790% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001791% ExceptionInfo *exception)
1792%
1793% A description of each parameter follows:
1794%
1795% o image: the image.
1796%
1797% o x,y,columns,rows: These values define the perimeter of a region of
1798% pixels.
1799%
1800% o exception: return any errors or warnings in this structure.
1801%
1802*/
cristy4c08aed2011-07-01 19:47:50 +00001803MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001804 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001805 ExceptionInfo *exception)
1806{
1807 CacheInfo
1808 *cache_info;
1809
cristy2036f5c2010-09-19 21:18:17 +00001810 const int
1811 id = GetOpenMPThreadId();
1812
cristy4c08aed2011-07-01 19:47:50 +00001813 Quantum
1814 *pixels;
1815
cristy3ed852e2009-09-05 21:47:34 +00001816 assert(image != (Image *) NULL);
1817 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001818 assert(image->cache != (Cache) NULL);
1819 cache_info=(CacheInfo *) image->cache;
1820 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001821 if (cache_info->methods.get_authentic_pixels_handler !=
cristy4c08aed2011-07-01 19:47:50 +00001822 (GetAuthenticPixelsHandler) NULL)
1823 {
1824 pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1825 rows,exception);
1826 return(pixels);
1827 }
cristy2036f5c2010-09-19 21:18:17 +00001828 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001829 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1830 cache_info->nexus_info[id],exception);
1831 return(pixels);
cristy3ed852e2009-09-05 21:47:34 +00001832}
1833
1834/*
1835%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1836% %
1837% %
1838% %
1839+ G e t A u t h e n t i c P i x e l s C a c h e %
1840% %
1841% %
1842% %
1843%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1844%
1845% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1846% as defined by the geometry parameters. A pointer to the pixels is returned
1847% if the pixels are transferred, otherwise a NULL is returned.
1848%
1849% The format of the GetAuthenticPixelsCache() method is:
1850%
cristy4c08aed2011-07-01 19:47:50 +00001851% Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001852% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001853% ExceptionInfo *exception)
1854%
1855% A description of each parameter follows:
1856%
1857% o image: the image.
1858%
1859% o x,y,columns,rows: These values define the perimeter of a region of
1860% pixels.
1861%
1862% o exception: return any errors or warnings in this structure.
1863%
1864*/
cristy4c08aed2011-07-01 19:47:50 +00001865static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00001866 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001867 ExceptionInfo *exception)
1868{
1869 CacheInfo
1870 *cache_info;
1871
cristy5c9e6f22010-09-17 17:31:01 +00001872 const int
1873 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001874
cristy4c08aed2011-07-01 19:47:50 +00001875 Quantum
1876 *pixels;
1877
cristye7cc7cf2010-09-21 13:26:47 +00001878 assert(image != (const Image *) NULL);
1879 assert(image->signature == MagickSignature);
1880 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00001881 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001882 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00001883 return((Quantum *) NULL);
cristye7cc7cf2010-09-21 13:26:47 +00001884 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001885 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00001886 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1887 cache_info->nexus_info[id],exception);
1888 return(pixels);
cristy3ed852e2009-09-05 21:47:34 +00001889}
1890
1891/*
1892%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1893% %
1894% %
1895% %
1896+ G e t I m a g e E x t e n t %
1897% %
1898% %
1899% %
1900%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1901%
cristy4c08aed2011-07-01 19:47:50 +00001902% GetImageExtent() returns the extent of the pixels associated corresponding
1903% with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
cristy3ed852e2009-09-05 21:47:34 +00001904%
1905% The format of the GetImageExtent() method is:
1906%
1907% MagickSizeType GetImageExtent(const Image *image)
1908%
1909% A description of each parameter follows:
1910%
1911% o image: the image.
1912%
1913*/
1914MagickExport MagickSizeType GetImageExtent(const Image *image)
1915{
1916 CacheInfo
1917 *cache_info;
1918
cristy5c9e6f22010-09-17 17:31:01 +00001919 const int
1920 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001921
cristy3ed852e2009-09-05 21:47:34 +00001922 assert(image != (Image *) NULL);
1923 assert(image->signature == MagickSignature);
1924 if (image->debug != MagickFalse)
1925 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1926 assert(image->cache != (Cache) NULL);
1927 cache_info=(CacheInfo *) image->cache;
1928 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001929 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001930 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001931}
1932
1933/*
1934%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1935% %
1936% %
1937% %
1938+ G e t I m a g e P i x e l C a c h e %
1939% %
1940% %
1941% %
1942%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1943%
1944% GetImagePixelCache() ensures that there is only a single reference to the
1945% pixel cache to be modified, updating the provided cache pointer to point to
1946% a clone of the original pixel cache if necessary.
1947%
1948% The format of the GetImagePixelCache method is:
1949%
1950% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1951% ExceptionInfo *exception)
1952%
1953% A description of each parameter follows:
1954%
1955% o image: the image.
1956%
1957% o clone: any value other than MagickFalse clones the cache pixels.
1958%
1959% o exception: return any errors or warnings in this structure.
1960%
1961*/
cristy3ed852e2009-09-05 21:47:34 +00001962static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
1963{
1964 CacheInfo
1965 *cache_info;
1966
1967 /*
1968 Does the image match the pixel cache morphology?
1969 */
1970 cache_info=(CacheInfo *) image->cache;
1971 if ((image->storage_class != cache_info->storage_class) ||
1972 (image->colorspace != cache_info->colorspace) ||
1973 (image->columns != cache_info->columns) ||
1974 (image->rows != cache_info->rows) ||
cristyed231572011-07-14 02:18:59 +00001975 (image->number_channels != cache_info->number_channels) ||
cristy4c08aed2011-07-01 19:47:50 +00001976 (image->metacontent_extent != cache_info->metacontent_extent) ||
cristy3ed852e2009-09-05 21:47:34 +00001977 (cache_info->nexus_info == (NexusInfo **) NULL) ||
1978 (cache_info->number_threads < GetOpenMPMaximumThreads()))
1979 return(MagickFalse);
1980 return(MagickTrue);
1981}
1982
cristy77ff0282010-09-13 00:51:10 +00001983static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1984 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001985{
1986 CacheInfo
1987 *cache_info;
1988
cristy3ed852e2009-09-05 21:47:34 +00001989 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00001990 destroy,
cristy3ed852e2009-09-05 21:47:34 +00001991 status;
1992
cristy50a10922010-02-15 18:35:25 +00001993 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00001994 cpu_throttle = 0,
1995 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00001996 time_limit = 0;
1997
cristy1ea34962010-07-01 19:49:21 +00001998 static time_t
cristya21afde2010-07-02 00:45:40 +00001999 cache_genesis = 0;
cristy1ea34962010-07-01 19:49:21 +00002000
cristyc4f9f132010-03-04 18:50:01 +00002001 status=MagickTrue;
2002 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00002003 if (cpu_throttle == 0)
2004 {
2005 char
2006 *limit;
2007
2008 /*
2009 Set CPU throttle in milleseconds.
2010 */
2011 cpu_throttle=MagickResourceInfinity;
2012 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2013 if (limit == (char *) NULL)
2014 limit=GetPolicyValue("throttle");
2015 if (limit != (char *) NULL)
2016 {
2017 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2018 limit=DestroyString(limit);
2019 }
2020 }
2021 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2022 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00002023 if (time_limit == 0)
2024 {
cristy6ebe97c2010-07-03 01:17:28 +00002025 /*
2026 Set the exire time in seconds.
2027 */
cristy1ea34962010-07-01 19:49:21 +00002028 time_limit=GetMagickResourceLimit(TimeResource);
cristya21afde2010-07-02 00:45:40 +00002029 cache_genesis=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00002030 }
2031 if ((time_limit != MagickResourceInfinity) &&
cristya21afde2010-07-02 00:45:40 +00002032 ((MagickSizeType) (time((time_t *) NULL)-cache_genesis) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00002033 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00002034 assert(image->cache != (Cache) NULL);
2035 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002036 destroy=MagickFalse;
cristyceb55ee2010-11-06 16:05:49 +00002037 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002038 {
cristyceb55ee2010-11-06 16:05:49 +00002039 LockSemaphoreInfo(cache_info->semaphore);
cristy4e6fa712010-11-06 16:06:12 +00002040 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002041 {
cristyceb55ee2010-11-06 16:05:49 +00002042 Image
2043 clone_image;
2044
2045 CacheInfo
2046 *clone_info;
2047
2048 /*
2049 Clone pixel cache.
2050 */
2051 clone_image=(*image);
2052 clone_image.semaphore=AllocateSemaphoreInfo();
2053 clone_image.reference_count=1;
2054 clone_image.cache=ClonePixelCache(cache_info);
2055 clone_info=(CacheInfo *) clone_image.cache;
2056 status=OpenPixelCache(&clone_image,IOMode,exception);
2057 if (status != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00002058 {
cristy5a7fbfb2010-11-06 16:10:59 +00002059 if (clone != MagickFalse)
cristy4e6fa712010-11-06 16:06:12 +00002060 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002061 if (status != MagickFalse)
2062 {
cristyceb55ee2010-11-06 16:05:49 +00002063 destroy=MagickTrue;
2064 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00002065 }
2066 }
cristyceb55ee2010-11-06 16:05:49 +00002067 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002068 }
cristyceb55ee2010-11-06 16:05:49 +00002069 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002070 }
cristy4320e0e2009-09-10 15:00:08 +00002071 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002072 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002073 if (status != MagickFalse)
2074 {
2075 /*
2076 Ensure the image matches the pixel cache morphology.
2077 */
2078 image->taint=MagickTrue;
cristy5f1c1ff2010-12-23 21:38:06 +00002079 image->type=UndefinedType;
cristydd438462010-05-06 13:44:04 +00002080 if (image->colorspace == GRAYColorspace)
2081 image->colorspace=RGBColorspace;
cristy3ed852e2009-09-05 21:47:34 +00002082 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2083 status=OpenPixelCache(image,IOMode,exception);
2084 }
cristyf84a1932010-01-03 18:00:18 +00002085 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002086 if (status == MagickFalse)
2087 return((Cache) NULL);
2088 return(image->cache);
2089}
2090
2091/*
2092%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2093% %
2094% %
2095% %
2096% G e t O n e A u t h e n t i c P i x e l %
2097% %
2098% %
2099% %
2100%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2101%
2102% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2103% location. The image background color is returned if an error occurs.
2104%
2105% The format of the GetOneAuthenticPixel() method is:
2106%
cristybb503372010-05-27 20:51:26 +00002107% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2108% const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002109%
2110% A description of each parameter follows:
2111%
2112% o image: the image.
2113%
2114% o x,y: These values define the location of the pixel to return.
2115%
2116% o pixel: return a pixel at the specified (x,y) location.
2117%
2118% o exception: return any errors or warnings in this structure.
2119%
2120*/
cristyacbbb7c2010-06-30 18:56:48 +00002121MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2122 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002123{
2124 CacheInfo
2125 *cache_info;
2126
cristy4c08aed2011-07-01 19:47:50 +00002127 register Quantum
2128 *q;
cristy2036f5c2010-09-19 21:18:17 +00002129
cristy3ed852e2009-09-05 21:47:34 +00002130 assert(image != (Image *) NULL);
2131 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002132 assert(image->cache != (Cache) NULL);
2133 cache_info=(CacheInfo *) image->cache;
2134 assert(cache_info->signature == MagickSignature);
2135 *pixel=image->background_color;
cristyd317f372010-09-18 01:42:20 +00002136 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2137 (GetOneAuthenticPixelFromHandler) NULL)
2138 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2139 pixel,exception));
cristy4c08aed2011-07-01 19:47:50 +00002140 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2141 if (q == (Quantum *) NULL)
cristy2036f5c2010-09-19 21:18:17 +00002142 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00002143 GetPixelPacket(image,q,pixel);
cristy2036f5c2010-09-19 21:18:17 +00002144 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002145}
2146
2147/*
2148%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2149% %
2150% %
2151% %
2152+ 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 %
2153% %
2154% %
2155% %
2156%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2157%
2158% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2159% location. The image background color is returned if an error occurs.
2160%
2161% The format of the GetOneAuthenticPixelFromCache() method is:
2162%
2163% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy5f959472010-05-27 22:19:46 +00002164% const ssize_t x,const ssize_t y,PixelPacket *pixel,
2165% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002166%
2167% A description of each parameter follows:
2168%
2169% o image: the image.
2170%
2171% o x,y: These values define the location of the pixel to return.
2172%
2173% o pixel: return a pixel at the specified (x,y) location.
2174%
2175% o exception: return any errors or warnings in this structure.
2176%
2177*/
2178static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristybb503372010-05-27 20:51:26 +00002179 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002180{
cristy098f78c2010-09-23 17:28:44 +00002181 CacheInfo
2182 *cache_info;
2183
2184 const int
2185 id = GetOpenMPThreadId();
2186
cristy4c08aed2011-07-01 19:47:50 +00002187 register Quantum
2188 *q;
cristy3ed852e2009-09-05 21:47:34 +00002189
cristy0158a4b2010-09-20 13:59:45 +00002190 assert(image != (const Image *) NULL);
2191 assert(image->signature == MagickSignature);
2192 assert(image->cache != (Cache) NULL);
cristy098f78c2010-09-23 17:28:44 +00002193 cache_info=(CacheInfo *) image->cache;
2194 assert(cache_info->signature == MagickSignature);
cristy098f78c2010-09-23 17:28:44 +00002195 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002196 *pixel=image->background_color;
2197 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2198 exception);
2199 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002200 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00002201 GetPixelPacket(image,q,pixel);
cristy3ed852e2009-09-05 21:47:34 +00002202 return(MagickTrue);
2203}
2204
2205/*
2206%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2207% %
2208% %
2209% %
2210% G e t O n e V i r t u a l M a g i c k P i x e l %
2211% %
2212% %
2213% %
2214%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2215%
2216% GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2217% location. The image background color is returned if an error occurs. If
2218% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2219%
2220% The format of the GetOneVirtualMagickPixel() method is:
2221%
2222% MagickBooleanType GetOneVirtualMagickPixel(const Image image,
cristy4c08aed2011-07-01 19:47:50 +00002223% const ssize_t x,const ssize_t y,PixelInfo *pixel,
cristy3ed852e2009-09-05 21:47:34 +00002224% ExceptionInfo exception)
2225%
2226% A description of each parameter follows:
2227%
2228% o image: the image.
2229%
2230% o x,y: these values define the location of the pixel to return.
2231%
2232% o pixel: return a pixel at the specified (x,y) location.
2233%
2234% o exception: return any errors or warnings in this structure.
2235%
2236*/
2237MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
cristy4c08aed2011-07-01 19:47:50 +00002238 const ssize_t x,const ssize_t y,PixelInfo *pixel,
cristyacbbb7c2010-06-30 18:56:48 +00002239 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002240{
2241 CacheInfo
2242 *cache_info;
2243
cristy0158a4b2010-09-20 13:59:45 +00002244 const int
2245 id = GetOpenMPThreadId();
2246
cristy4c08aed2011-07-01 19:47:50 +00002247 register const Quantum
cristy0158a4b2010-09-20 13:59:45 +00002248 *pixels;
cristy3ed852e2009-09-05 21:47:34 +00002249
2250 assert(image != (const Image *) NULL);
2251 assert(image->signature == MagickSignature);
2252 assert(image->cache != (Cache) NULL);
2253 cache_info=(CacheInfo *) image->cache;
2254 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002255 assert(id < (int) cache_info->number_threads);
2256 pixels=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2257 1UL,1UL,cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002258 GetPixelInfo(image,pixel);
2259 if (pixels == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002260 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00002261 SetPixelInfo(image,pixels,pixel);
cristy3ed852e2009-09-05 21:47:34 +00002262 return(MagickTrue);
2263}
2264
2265/*
2266%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2267% %
2268% %
2269% %
2270% G e t O n e V i r t u a l M e t h o d P i x e l %
2271% %
2272% %
2273% %
2274%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2275%
2276% GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2277% location as defined by specified pixel method. The image background color
2278% is returned if an error occurs. If you plan to modify the pixel, use
2279% GetOneAuthenticPixel() instead.
2280%
2281% The format of the GetOneVirtualMethodPixel() method is:
2282%
2283% MagickBooleanType GetOneVirtualMethodPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002284% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
cristy4c08aed2011-07-01 19:47:50 +00002285% const ssize_t y,PixelPacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002286%
2287% A description of each parameter follows:
2288%
2289% o image: the image.
2290%
2291% o virtual_pixel_method: the virtual pixel method.
2292%
2293% o x,y: These values define the location of the pixel to return.
2294%
2295% o pixel: return a pixel at the specified (x,y) location.
2296%
2297% o exception: return any errors or warnings in this structure.
2298%
2299*/
2300MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002301 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002302 PixelPacket *pixel,ExceptionInfo *exception)
2303{
cristy3ed852e2009-09-05 21:47:34 +00002304 CacheInfo
2305 *cache_info;
2306
cristy0158a4b2010-09-20 13:59:45 +00002307 const int
2308 id = GetOpenMPThreadId();
2309
cristy4c08aed2011-07-01 19:47:50 +00002310 const Quantum
2311 *p;
cristy2036f5c2010-09-19 21:18:17 +00002312
cristy3ed852e2009-09-05 21:47:34 +00002313 assert(image != (const Image *) NULL);
2314 assert(image->signature == MagickSignature);
2315 assert(image->cache != (Cache) NULL);
2316 cache_info=(CacheInfo *) image->cache;
2317 assert(cache_info->signature == MagickSignature);
2318 *pixel=image->background_color;
cristyd317f372010-09-18 01:42:20 +00002319 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2320 (GetOneVirtualPixelFromHandler) NULL)
2321 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2322 virtual_pixel_method,x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002323 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002324 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
cristy0158a4b2010-09-20 13:59:45 +00002325 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002326 if (p == (const Quantum *) NULL)
cristy2036f5c2010-09-19 21:18:17 +00002327 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00002328 GetPixelPacket(image,p,pixel);
2329 if (image->colorspace == CMYKColorspace)
2330 pixel->black=GetPixelBlack(image,p);
cristy2036f5c2010-09-19 21:18:17 +00002331 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002332}
2333
2334/*
2335%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2336% %
2337% %
2338% %
2339% G e t O n e V i r t u a l P i x e l %
2340% %
2341% %
2342% %
2343%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2344%
2345% GetOneVirtualPixel() returns a single virtual pixel at the specified
2346% (x,y) location. The image background color is returned if an error occurs.
2347% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2348%
2349% The format of the GetOneVirtualPixel() method is:
2350%
cristybb503372010-05-27 20:51:26 +00002351% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2352% const ssize_t y,PixelPacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002353%
2354% A description of each parameter follows:
2355%
2356% o image: the image.
2357%
2358% o x,y: These values define the location of the pixel to return.
2359%
2360% o pixel: return a pixel at the specified (x,y) location.
2361%
2362% o exception: return any errors or warnings in this structure.
2363%
2364*/
2365MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002366 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002367{
cristy3ed852e2009-09-05 21:47:34 +00002368 CacheInfo
2369 *cache_info;
2370
cristy0158a4b2010-09-20 13:59:45 +00002371 const int
2372 id = GetOpenMPThreadId();
2373
cristy4c08aed2011-07-01 19:47:50 +00002374 const Quantum
2375 *p;
cristy2036f5c2010-09-19 21:18:17 +00002376
cristy3ed852e2009-09-05 21:47:34 +00002377 assert(image != (const Image *) NULL);
2378 assert(image->signature == MagickSignature);
2379 assert(image->cache != (Cache) NULL);
2380 cache_info=(CacheInfo *) image->cache;
2381 assert(cache_info->signature == MagickSignature);
2382 *pixel=image->background_color;
cristyd317f372010-09-18 01:42:20 +00002383 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2384 (GetOneVirtualPixelFromHandler) NULL)
2385 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2386 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002387 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002388 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
cristy0158a4b2010-09-20 13:59:45 +00002389 1UL,1UL,cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002390 if (p == (const Quantum *) NULL)
cristy2036f5c2010-09-19 21:18:17 +00002391 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00002392 GetPixelPacket(image,p,pixel);
2393 if (image->colorspace == CMYKColorspace)
2394 pixel->black=GetPixelBlack(image,p);
cristy2036f5c2010-09-19 21:18:17 +00002395 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002396}
2397
2398/*
2399%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2400% %
2401% %
2402% %
2403+ 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 %
2404% %
2405% %
2406% %
2407%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2408%
2409% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2410% specified (x,y) location. The image background color is returned if an
2411% error occurs.
2412%
2413% The format of the GetOneVirtualPixelFromCache() method is:
2414%
2415% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristy4c08aed2011-07-01 19:47:50 +00002416% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002417% PixelPacket *pixel,ExceptionInfo *exception)
2418%
2419% A description of each parameter follows:
2420%
2421% o image: the image.
2422%
2423% o virtual_pixel_method: the virtual pixel method.
2424%
2425% o x,y: These values define the location of the pixel to return.
2426%
2427% o pixel: return a pixel at the specified (x,y) location.
2428%
2429% o exception: return any errors or warnings in this structure.
2430%
2431*/
2432static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002433 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002434 PixelPacket *pixel,ExceptionInfo *exception)
2435{
cristy0158a4b2010-09-20 13:59:45 +00002436 CacheInfo
2437 *cache_info;
2438
2439 const int
2440 id = GetOpenMPThreadId();
2441
cristy4c08aed2011-07-01 19:47:50 +00002442 const Quantum
2443 *p;
cristy3ed852e2009-09-05 21:47:34 +00002444
cristye7cc7cf2010-09-21 13:26:47 +00002445 assert(image != (const Image *) NULL);
2446 assert(image->signature == MagickSignature);
2447 assert(image->cache != (Cache) NULL);
cristy0158a4b2010-09-20 13:59:45 +00002448 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002449 assert(cache_info->signature == MagickSignature);
cristy0158a4b2010-09-20 13:59:45 +00002450 assert(id < (int) cache_info->number_threads);
cristye7cc7cf2010-09-21 13:26:47 +00002451 *pixel=image->background_color;
cristy4c08aed2011-07-01 19:47:50 +00002452 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
cristy0158a4b2010-09-20 13:59:45 +00002453 cache_info->nexus_info[id],exception);
cristy4c08aed2011-07-01 19:47:50 +00002454 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002455 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00002456 GetPixelPacket(image,p,pixel);
2457 if (image->colorspace == CMYKColorspace)
2458 pixel->black=GetPixelBlack(image,p);
cristy3ed852e2009-09-05 21:47:34 +00002459 return(MagickTrue);
2460}
2461
2462/*
2463%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2464% %
2465% %
2466% %
2467+ G e t P i x e l C a c h e C o l o r s p a c e %
2468% %
2469% %
2470% %
2471%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2472%
2473% GetPixelCacheColorspace() returns the class type of the pixel cache.
2474%
2475% The format of the GetPixelCacheColorspace() method is:
2476%
2477% Colorspace GetPixelCacheColorspace(Cache cache)
2478%
2479% A description of each parameter follows:
2480%
2481% o cache: the pixel cache.
2482%
2483*/
2484MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
2485{
2486 CacheInfo
2487 *cache_info;
2488
2489 assert(cache != (Cache) NULL);
2490 cache_info=(CacheInfo *) cache;
2491 assert(cache_info->signature == MagickSignature);
2492 if (cache_info->debug != MagickFalse)
2493 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2494 cache_info->filename);
2495 return(cache_info->colorspace);
2496}
2497
2498/*
2499%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2500% %
2501% %
2502% %
2503+ G e t P i x e l C a c h e M e t h o d s %
2504% %
2505% %
2506% %
2507%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2508%
2509% GetPixelCacheMethods() initializes the CacheMethods structure.
2510%
2511% The format of the GetPixelCacheMethods() method is:
2512%
2513% void GetPixelCacheMethods(CacheMethods *cache_methods)
2514%
2515% A description of each parameter follows:
2516%
2517% o cache_methods: Specifies a pointer to a CacheMethods structure.
2518%
2519*/
2520MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
2521{
2522 assert(cache_methods != (CacheMethods *) NULL);
2523 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2524 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2525 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002526 cache_methods->get_virtual_metacontent_from_handler=
2527 GetVirtualMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002528 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2529 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
cristy4c08aed2011-07-01 19:47:50 +00002530 cache_methods->get_authentic_metacontent_from_handler=
2531 GetAuthenticMetacontentFromCache;
cristy3ed852e2009-09-05 21:47:34 +00002532 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2533 cache_methods->get_one_authentic_pixel_from_handler=
2534 GetOneAuthenticPixelFromCache;
2535 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2536 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2537 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2538}
2539
2540/*
2541%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2542% %
2543% %
2544% %
2545+ G e t P i x e l C a c h e N e x u s E x t e n t %
2546% %
2547% %
2548% %
2549%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2550%
cristy4c08aed2011-07-01 19:47:50 +00002551% GetPixelCacheNexusExtent() returns the extent of the pixels associated
2552% corresponding with the last call to SetPixelCacheNexusPixels() or
2553% GetPixelCacheNexusPixels().
cristy3ed852e2009-09-05 21:47:34 +00002554%
2555% The format of the GetPixelCacheNexusExtent() method is:
2556%
2557% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2558% NexusInfo *nexus_info)
2559%
2560% A description of each parameter follows:
2561%
2562% o nexus_info: the nexus info.
2563%
2564*/
2565MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2566 NexusInfo *nexus_info)
2567{
2568 CacheInfo
2569 *cache_info;
2570
2571 MagickSizeType
2572 extent;
2573
cristye7cc7cf2010-09-21 13:26:47 +00002574 assert(cache != (const Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002575 cache_info=(CacheInfo *) cache;
2576 assert(cache_info->signature == MagickSignature);
2577 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2578 if (extent == 0)
2579 return((MagickSizeType) cache_info->columns*cache_info->rows);
2580 return(extent);
2581}
2582
2583/*
2584%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2585% %
2586% %
2587% %
cristy4c08aed2011-07-01 19:47:50 +00002588+ G e t P i x e l C a c h e N e x u s M e t a c o n t e n t %
cristy3ed852e2009-09-05 21:47:34 +00002589% %
2590% %
2591% %
2592%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2593%
cristy4c08aed2011-07-01 19:47:50 +00002594% GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2595% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002596%
cristy4c08aed2011-07-01 19:47:50 +00002597% The format of the GetPixelCacheNexusMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002598%
cristy4c08aed2011-07-01 19:47:50 +00002599% void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002600% NexusInfo *nexus_info)
2601%
2602% A description of each parameter follows:
2603%
2604% o cache: the pixel cache.
2605%
cristy4c08aed2011-07-01 19:47:50 +00002606% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002607%
2608*/
cristy4c08aed2011-07-01 19:47:50 +00002609MagickExport void *GetPixelCacheNexusMetacontent(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002610 NexusInfo *nexus_info)
2611{
2612 CacheInfo
2613 *cache_info;
2614
cristye7cc7cf2010-09-21 13:26:47 +00002615 assert(cache != (const Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002616 cache_info=(CacheInfo *) cache;
2617 assert(cache_info->signature == MagickSignature);
2618 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002619 return((void *) NULL);
2620 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002621}
2622
2623/*
2624%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2625% %
2626% %
2627% %
2628+ G e t P i x e l C a c h e N e x u s P i x e l s %
2629% %
2630% %
2631% %
2632%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2633%
2634% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2635% cache nexus.
2636%
2637% The format of the GetPixelCacheNexusPixels() method is:
2638%
cristy4c08aed2011-07-01 19:47:50 +00002639% Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002640% NexusInfo *nexus_info)
2641%
2642% A description of each parameter follows:
2643%
2644% o cache: the pixel cache.
2645%
2646% o nexus_info: the cache nexus to return the pixels.
2647%
2648*/
cristy4c08aed2011-07-01 19:47:50 +00002649MagickExport Quantum *GetPixelCacheNexusPixels(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002650 NexusInfo *nexus_info)
2651{
2652 CacheInfo
2653 *cache_info;
2654
cristye7cc7cf2010-09-21 13:26:47 +00002655 assert(cache != (const Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002656 cache_info=(CacheInfo *) cache;
2657 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002658 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002659 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002660 return(nexus_info->pixels);
2661}
2662
2663/*
2664%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2665% %
2666% %
2667% %
cristy056ba772010-01-02 23:33:54 +00002668+ G e t P i x e l C a c h e P i x e l s %
2669% %
2670% %
2671% %
2672%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2673%
2674% GetPixelCachePixels() returns the pixels associated with the specified image.
2675%
2676% The format of the GetPixelCachePixels() method is:
2677%
cristyf84a1932010-01-03 18:00:18 +00002678% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2679% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002680%
2681% A description of each parameter follows:
2682%
2683% o image: the image.
2684%
2685% o length: the pixel cache length.
2686%
cristyf84a1932010-01-03 18:00:18 +00002687% o exception: return any errors or warnings in this structure.
2688%
cristy056ba772010-01-02 23:33:54 +00002689*/
cristyf84a1932010-01-03 18:00:18 +00002690MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2691 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002692{
2693 CacheInfo
2694 *cache_info;
2695
2696 assert(image != (const Image *) NULL);
2697 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002698 assert(image->cache != (Cache) NULL);
cristy654fdaf2011-02-24 15:24:33 +00002699 assert(length != (MagickSizeType *) NULL);
2700 assert(exception != (ExceptionInfo *) NULL);
2701 assert(exception->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00002702 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002703 assert(cache_info->signature == MagickSignature);
2704 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002705 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002706 return((void *) NULL);
2707 *length=cache_info->length;
2708 return((void *) cache_info->pixels);
2709}
2710
2711/*
2712%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2713% %
2714% %
2715% %
cristyb32b90a2009-09-07 21:45:48 +00002716+ 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 +00002717% %
2718% %
2719% %
2720%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2721%
2722% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2723%
2724% The format of the GetPixelCacheStorageClass() method is:
2725%
2726% ClassType GetPixelCacheStorageClass(Cache cache)
2727%
2728% A description of each parameter follows:
2729%
2730% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2731%
2732% o cache: the pixel cache.
2733%
2734*/
2735MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
2736{
2737 CacheInfo
2738 *cache_info;
2739
2740 assert(cache != (Cache) NULL);
2741 cache_info=(CacheInfo *) cache;
2742 assert(cache_info->signature == MagickSignature);
2743 if (cache_info->debug != MagickFalse)
2744 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2745 cache_info->filename);
2746 return(cache_info->storage_class);
2747}
2748
2749/*
2750%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2751% %
2752% %
2753% %
cristyb32b90a2009-09-07 21:45:48 +00002754+ G e t P i x e l C a c h e T i l e S i z e %
2755% %
2756% %
2757% %
2758%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2759%
2760% GetPixelCacheTileSize() returns the pixel cache tile size.
2761%
2762% The format of the GetPixelCacheTileSize() method is:
2763%
cristybb503372010-05-27 20:51:26 +00002764% void GetPixelCacheTileSize(const Image *image,size_t *width,
2765% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002766%
2767% A description of each parameter follows:
2768%
2769% o image: the image.
2770%
2771% o width: the optimize cache tile width in pixels.
2772%
2773% o height: the optimize cache tile height in pixels.
2774%
2775*/
cristybb503372010-05-27 20:51:26 +00002776MagickExport void GetPixelCacheTileSize(const Image *image,size_t *width,
2777 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002778{
cristy4c08aed2011-07-01 19:47:50 +00002779 CacheInfo
2780 *cache_info;
2781
cristyb32b90a2009-09-07 21:45:48 +00002782 assert(image != (Image *) NULL);
2783 assert(image->signature == MagickSignature);
2784 if (image->debug != MagickFalse)
2785 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00002786 cache_info=(CacheInfo *) image->cache;
2787 assert(cache_info->signature == MagickSignature);
cristyed231572011-07-14 02:18:59 +00002788 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002789 if (GetPixelCacheType(image) == DiskCache)
cristyed231572011-07-14 02:18:59 +00002790 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
cristyb32b90a2009-09-07 21:45:48 +00002791 *height=(*width);
2792}
2793
2794/*
2795%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2796% %
2797% %
2798% %
2799+ G e t P i x e l C a c h e T y p e %
2800% %
2801% %
2802% %
2803%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2804%
2805% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2806%
2807% The format of the GetPixelCacheType() method is:
2808%
2809% CacheType GetPixelCacheType(const Image *image)
2810%
2811% A description of each parameter follows:
2812%
2813% o image: the image.
2814%
2815*/
2816MagickExport CacheType GetPixelCacheType(const Image *image)
2817{
2818 CacheInfo
2819 *cache_info;
2820
2821 assert(image != (Image *) NULL);
2822 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002823 assert(image->cache != (Cache) NULL);
2824 cache_info=(CacheInfo *) image->cache;
2825 assert(cache_info->signature == MagickSignature);
2826 return(cache_info->type);
2827}
2828
2829/*
2830%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2831% %
2832% %
2833% %
cristy3ed852e2009-09-05 21:47:34 +00002834+ 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 %
2835% %
2836% %
2837% %
2838%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2839%
2840% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2841% pixel cache. A virtual pixel is any pixel access that is outside the
2842% boundaries of the image cache.
2843%
2844% The format of the GetPixelCacheVirtualMethod() method is:
2845%
2846% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2847%
2848% A description of each parameter follows:
2849%
2850% o image: the image.
2851%
2852*/
2853MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2854{
2855 CacheInfo
2856 *cache_info;
2857
2858 assert(image != (Image *) NULL);
2859 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002860 assert(image->cache != (Cache) NULL);
2861 cache_info=(CacheInfo *) image->cache;
2862 assert(cache_info->signature == MagickSignature);
2863 return(cache_info->virtual_pixel_method);
2864}
2865
2866/*
2867%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2868% %
2869% %
2870% %
cristy4c08aed2011-07-01 19:47:50 +00002871+ G e t V i r t u a l M e t a c o n t e n t F r o m C a c h e %
cristy3ed852e2009-09-05 21:47:34 +00002872% %
2873% %
2874% %
2875%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2876%
cristy4c08aed2011-07-01 19:47:50 +00002877% GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2878% the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00002879%
cristy4c08aed2011-07-01 19:47:50 +00002880% The format of the GetVirtualMetacontentFromCache() method is:
cristy3ed852e2009-09-05 21:47:34 +00002881%
cristy4c08aed2011-07-01 19:47:50 +00002882% void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002883%
2884% A description of each parameter follows:
2885%
2886% o image: the image.
2887%
2888*/
cristy4c08aed2011-07-01 19:47:50 +00002889static const void *GetVirtualMetacontentFromCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002890{
2891 CacheInfo
2892 *cache_info;
2893
cristy5c9e6f22010-09-17 17:31:01 +00002894 const int
2895 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002896
cristy4c08aed2011-07-01 19:47:50 +00002897 const void
2898 *metacontent;
2899
cristye7cc7cf2010-09-21 13:26:47 +00002900 assert(image != (const Image *) NULL);
2901 assert(image->signature == MagickSignature);
2902 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002903 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00002904 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00002905 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002906 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2907 cache_info->nexus_info[id]);
2908 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002909}
2910
2911/*
2912%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2913% %
2914% %
2915% %
cristy4c08aed2011-07-01 19:47:50 +00002916+ G e t V i r t u a l M e t a c o n t e n t F r o m N e x u s %
cristy3ed852e2009-09-05 21:47:34 +00002917% %
2918% %
2919% %
2920%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2921%
cristy4c08aed2011-07-01 19:47:50 +00002922% GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2923% cache nexus.
cristy3ed852e2009-09-05 21:47:34 +00002924%
cristy4c08aed2011-07-01 19:47:50 +00002925% The format of the GetVirtualMetacontentFromNexus() method is:
cristy3ed852e2009-09-05 21:47:34 +00002926%
cristy4c08aed2011-07-01 19:47:50 +00002927% const void *GetVirtualMetacontentFromNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00002928% NexusInfo *nexus_info)
2929%
2930% A description of each parameter follows:
2931%
2932% o cache: the pixel cache.
2933%
cristy4c08aed2011-07-01 19:47:50 +00002934% o nexus_info: the cache nexus to return the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00002935%
2936*/
cristy4c08aed2011-07-01 19:47:50 +00002937MagickExport const void *GetVirtualMetacontentFromNexus(
2938 const Cache cache,NexusInfo *nexus_info)
cristy3ed852e2009-09-05 21:47:34 +00002939{
2940 CacheInfo
2941 *cache_info;
2942
cristye7cc7cf2010-09-21 13:26:47 +00002943 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002944 cache_info=(CacheInfo *) cache;
2945 assert(cache_info->signature == MagickSignature);
2946 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00002947 return((void *) NULL);
2948 return(nexus_info->metacontent);
cristy3ed852e2009-09-05 21:47:34 +00002949}
2950
2951/*
2952%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2953% %
2954% %
2955% %
cristy4c08aed2011-07-01 19:47:50 +00002956% G e t V i r t u a l M e t a c o n t e n t %
cristy3ed852e2009-09-05 21:47:34 +00002957% %
2958% %
2959% %
2960%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2961%
cristy4c08aed2011-07-01 19:47:50 +00002962% GetVirtualMetacontent() returns the virtual metacontent corresponding with
2963% the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2964% returned if the meta-content are not available.
cristy3ed852e2009-09-05 21:47:34 +00002965%
cristy4c08aed2011-07-01 19:47:50 +00002966% The format of the GetVirtualMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00002967%
cristy4c08aed2011-07-01 19:47:50 +00002968% const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002969%
2970% A description of each parameter follows:
2971%
2972% o image: the image.
2973%
2974*/
cristy4c08aed2011-07-01 19:47:50 +00002975MagickExport const void *GetVirtualMetacontent(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00002976{
2977 CacheInfo
2978 *cache_info;
2979
cristy2036f5c2010-09-19 21:18:17 +00002980 const int
2981 id = GetOpenMPThreadId();
2982
cristy4c08aed2011-07-01 19:47:50 +00002983 const void
2984 *metacontent;
2985
cristy3ed852e2009-09-05 21:47:34 +00002986 assert(image != (const Image *) NULL);
2987 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002988 assert(image->cache != (Cache) NULL);
2989 cache_info=(CacheInfo *) image->cache;
2990 assert(cache_info->signature == MagickSignature);
cristy4c08aed2011-07-01 19:47:50 +00002991 if (cache_info->methods.get_virtual_metacontent_from_handler !=
2992 (GetVirtualMetacontentFromHandler) NULL)
2993 {
2994 metacontent=cache_info->methods.
2995 get_virtual_metacontent_from_handler(image);
2996 return(metacontent);
2997 }
cristy2036f5c2010-09-19 21:18:17 +00002998 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00002999 metacontent=GetVirtualMetacontentFromNexus(cache_info,
3000 cache_info->nexus_info[id]);
3001 return(metacontent);
cristy3ed852e2009-09-05 21:47:34 +00003002}
3003
3004/*
3005%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3006% %
3007% %
3008% %
3009+ 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 %
3010% %
3011% %
3012% %
3013%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3014%
3015% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3016% pixel cache as defined by the geometry parameters. A pointer to the pixels
3017% is returned if the pixels are transferred, otherwise a NULL is returned.
3018%
3019% The format of the GetVirtualPixelsFromNexus() method is:
3020%
cristy4c08aed2011-07-01 19:47:50 +00003021% Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003022% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00003023% const size_t columns,const size_t rows,NexusInfo *nexus_info,
3024% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003025%
3026% A description of each parameter follows:
3027%
3028% o image: the image.
3029%
3030% o virtual_pixel_method: the virtual pixel method.
3031%
3032% o x,y,columns,rows: These values define the perimeter of a region of
3033% pixels.
3034%
3035% o nexus_info: the cache nexus to acquire.
3036%
3037% o exception: return any errors or warnings in this structure.
3038%
3039*/
3040
cristybb503372010-05-27 20:51:26 +00003041static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003042 DitherMatrix[64] =
3043 {
3044 0, 48, 12, 60, 3, 51, 15, 63,
3045 32, 16, 44, 28, 35, 19, 47, 31,
3046 8, 56, 4, 52, 11, 59, 7, 55,
3047 40, 24, 36, 20, 43, 27, 39, 23,
3048 2, 50, 14, 62, 1, 49, 13, 61,
3049 34, 18, 46, 30, 33, 17, 45, 29,
3050 10, 58, 6, 54, 9, 57, 5, 53,
3051 42, 26, 38, 22, 41, 25, 37, 21
3052 };
3053
cristybb503372010-05-27 20:51:26 +00003054static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003055{
cristybb503372010-05-27 20:51:26 +00003056 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003057 index;
3058
3059 index=x+DitherMatrix[x & 0x07]-32L;
3060 if (index < 0L)
3061 return(0L);
cristybb503372010-05-27 20:51:26 +00003062 if (index >= (ssize_t) columns)
3063 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00003064 return(index);
3065}
3066
cristybb503372010-05-27 20:51:26 +00003067static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003068{
cristybb503372010-05-27 20:51:26 +00003069 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003070 index;
3071
3072 index=y+DitherMatrix[y & 0x07]-32L;
3073 if (index < 0L)
3074 return(0L);
cristybb503372010-05-27 20:51:26 +00003075 if (index >= (ssize_t) rows)
3076 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00003077 return(index);
3078}
3079
cristybb503372010-05-27 20:51:26 +00003080static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003081{
3082 if (x < 0L)
3083 return(0L);
cristybb503372010-05-27 20:51:26 +00003084 if (x >= (ssize_t) columns)
3085 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003086 return(x);
3087}
3088
cristybb503372010-05-27 20:51:26 +00003089static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003090{
3091 if (y < 0L)
3092 return(0L);
cristybb503372010-05-27 20:51:26 +00003093 if (y >= (ssize_t) rows)
3094 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003095 return(y);
3096}
3097
cristybb503372010-05-27 20:51:26 +00003098static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003099{
cristybb503372010-05-27 20:51:26 +00003100 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003101}
3102
cristybb503372010-05-27 20:51:26 +00003103static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003104{
cristybb503372010-05-27 20:51:26 +00003105 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003106}
3107
3108/*
3109 VirtualPixelModulo() computes the remainder of dividing offset by extent. It
3110 returns not only the quotient (tile the offset falls in) but also the positive
3111 remainer within that tile such that 0 <= remainder < extent. This method is
3112 essentially a ldiv() using a floored modulo division rather than the normal
3113 default truncated modulo division.
3114*/
cristybb503372010-05-27 20:51:26 +00003115static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3116 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003117{
3118 MagickModulo
3119 modulo;
3120
cristybb503372010-05-27 20:51:26 +00003121 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003122 if (offset < 0L)
3123 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003124 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003125 return(modulo);
3126}
3127
cristy4c08aed2011-07-01 19:47:50 +00003128MagickExport const Quantum *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003129 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3130 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003131 ExceptionInfo *exception)
3132{
3133 CacheInfo
3134 *cache_info;
3135
3136 MagickOffsetType
3137 offset;
3138
3139 MagickSizeType
3140 length,
3141 number_pixels;
3142
3143 NexusInfo
3144 **virtual_nexus;
3145
cristy4c08aed2011-07-01 19:47:50 +00003146 Quantum
cristy3ed852e2009-09-05 21:47:34 +00003147 *pixels,
cristy4c08aed2011-07-01 19:47:50 +00003148 *virtual_pixel;
cristy3ed852e2009-09-05 21:47:34 +00003149
3150 RectangleInfo
3151 region;
3152
cristy4c08aed2011-07-01 19:47:50 +00003153 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00003154 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003155
cristy4c08aed2011-07-01 19:47:50 +00003156 register const void
3157 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003158
cristy4c08aed2011-07-01 19:47:50 +00003159 register Quantum
cristye076a6e2010-08-15 19:59:43 +00003160 *restrict q;
3161
cristybb503372010-05-27 20:51:26 +00003162 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003163 u,
3164 v;
3165
cristy4c08aed2011-07-01 19:47:50 +00003166 register unsigned char
3167 *restrict s;
3168
3169 void
3170 *virtual_associated_pixel;
3171
cristy3ed852e2009-09-05 21:47:34 +00003172 /*
3173 Acquire pixels.
3174 */
cristye7cc7cf2010-09-21 13:26:47 +00003175 assert(image != (const Image *) NULL);
3176 assert(image->signature == MagickSignature);
3177 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003178 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003179 assert(cache_info->signature == MagickSignature);
cristy4cfbb3f2010-03-14 20:40:23 +00003180 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00003181 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003182 region.x=x;
3183 region.y=y;
3184 region.width=columns;
3185 region.height=rows;
3186 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00003187 if (pixels == (Quantum *) NULL)
3188 return((const Quantum *) NULL);
cristydf415c82010-03-11 16:47:50 +00003189 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3190 nexus_info->region.x;
3191 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3192 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003193 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3194 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003195 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3196 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003197 {
3198 MagickBooleanType
3199 status;
3200
3201 /*
3202 Pixel request is inside cache extents.
3203 */
cristy4c08aed2011-07-01 19:47:50 +00003204 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003205 return(pixels);
3206 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3207 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003208 return((const Quantum *) NULL);
3209 if (cache_info->metacontent_extent != 0)
cristy3ed852e2009-09-05 21:47:34 +00003210 {
cristy4c08aed2011-07-01 19:47:50 +00003211 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00003212 if (status == MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00003213 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003214 }
3215 return(pixels);
3216 }
3217 /*
3218 Pixel request is outside cache extents.
3219 */
3220 q=pixels;
cristy4c08aed2011-07-01 19:47:50 +00003221 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
cristy3ed852e2009-09-05 21:47:34 +00003222 virtual_nexus=AcquirePixelCacheNexus(1);
3223 if (virtual_nexus == (NexusInfo **) NULL)
3224 {
cristy4c08aed2011-07-01 19:47:50 +00003225 if (virtual_nexus != (NexusInfo **) NULL)
3226 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
cristy3ed852e2009-09-05 21:47:34 +00003227 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3228 "UnableToGetCacheNexus","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003229 return((const Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003230 }
cristy4c08aed2011-07-01 19:47:50 +00003231 virtual_pixel=(Quantum *) NULL;
3232 virtual_associated_pixel=(void *) NULL;
cristy3ed852e2009-09-05 21:47:34 +00003233 switch (virtual_pixel_method)
3234 {
cristy4c08aed2011-07-01 19:47:50 +00003235 case BackgroundVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003236 case BlackVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003237 case GrayVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003238 case TransparentVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003239 case MaskVirtualPixelMethod:
3240 case WhiteVirtualPixelMethod:
cristy4c08aed2011-07-01 19:47:50 +00003241 case EdgeVirtualPixelMethod:
3242 case CheckerTileVirtualPixelMethod:
3243 case HorizontalTileVirtualPixelMethod:
3244 case VerticalTileVirtualPixelMethod:
cristy3ed852e2009-09-05 21:47:34 +00003245 {
cristy4c08aed2011-07-01 19:47:50 +00003246 /*
3247 Acquire virtual pixel and associated channels.
3248 */
cristy0a922382011-07-16 15:30:34 +00003249 virtual_pixel=(Quantum *) AcquireAlignedMemory(
cristyed231572011-07-14 02:18:59 +00003250 cache_info->number_channels,sizeof(*virtual_pixel));
cristy4c08aed2011-07-01 19:47:50 +00003251 if (virtual_pixel == (Quantum *) NULL)
3252 {
3253 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3254 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3255 "UnableToGetCacheNexus","`%s'",image->filename);
3256 return((const Quantum *) NULL);
3257 }
cristyed231572011-07-14 02:18:59 +00003258 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00003259 sizeof(*virtual_pixel));
3260 if (cache_info->metacontent_extent != 0)
3261 {
cristy0a922382011-07-16 15:30:34 +00003262 virtual_associated_pixel=(void *) AcquireAlignedMemory(1,
cristy4c08aed2011-07-01 19:47:50 +00003263 cache_info->metacontent_extent);
3264 if (virtual_associated_pixel == (void *) NULL)
3265 {
cristy0a922382011-07-16 15:30:34 +00003266 virtual_pixel=(Quantum *) RelinquishMagickMemory(virtual_pixel);
cristy4c08aed2011-07-01 19:47:50 +00003267 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3268 (void) ThrowMagickException(exception,GetMagickModule(),
3269 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
3270 return((const Quantum *) NULL);
3271 }
3272 (void) ResetMagickMemory(virtual_associated_pixel,0,
3273 cache_info->metacontent_extent);
3274 }
3275 switch (virtual_pixel_method)
3276 {
3277 case BlackVirtualPixelMethod:
3278 {
3279 SetPixelRed(image,0,virtual_pixel);
3280 SetPixelGreen(image,0,virtual_pixel);
3281 SetPixelBlue(image,0,virtual_pixel);
3282 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3283 break;
3284 }
3285 case GrayVirtualPixelMethod:
3286 {
3287 SetPixelRed(image,QuantumRange/2,virtual_pixel);
3288 SetPixelGreen(image,QuantumRange/2,virtual_pixel);
3289 SetPixelBlue(image,QuantumRange/2,virtual_pixel);
3290 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3291 break;
3292 }
3293 case TransparentVirtualPixelMethod:
3294 {
3295 SetPixelRed(image,0,virtual_pixel);
3296 SetPixelGreen(image,0,virtual_pixel);
3297 SetPixelBlue(image,0,virtual_pixel);
3298 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3299 break;
3300 }
3301 case MaskVirtualPixelMethod:
3302 case WhiteVirtualPixelMethod:
3303 {
3304 SetPixelRed(image,(Quantum) QuantumRange,virtual_pixel);
3305 SetPixelGreen(image,(Quantum) QuantumRange,virtual_pixel);
3306 SetPixelBlue(image,(Quantum) QuantumRange,virtual_pixel);
3307 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3308 break;
3309 }
3310 default:
3311 {
3312 SetPixelRed(image,image->background_color.red,virtual_pixel);
3313 SetPixelGreen(image,image->background_color.green,virtual_pixel);
3314 SetPixelBlue(image,image->background_color.blue,virtual_pixel);
3315 SetPixelAlpha(image,image->background_color.alpha,virtual_pixel);
3316 break;
3317 }
3318 }
cristy3ed852e2009-09-05 21:47:34 +00003319 break;
3320 }
3321 default:
cristy3ed852e2009-09-05 21:47:34 +00003322 break;
cristy3ed852e2009-09-05 21:47:34 +00003323 }
cristybb503372010-05-27 20:51:26 +00003324 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003325 {
cristybb503372010-05-27 20:51:26 +00003326 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003327 {
3328 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003329 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003330 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3331 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003332 {
3333 MagickModulo
3334 x_modulo,
3335 y_modulo;
3336
3337 /*
3338 Transfer a single pixel.
3339 */
3340 length=(MagickSizeType) 1;
3341 switch (virtual_pixel_method)
3342 {
cristy3ed852e2009-09-05 21:47:34 +00003343 default:
3344 {
3345 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003346 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003347 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003348 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003349 break;
3350 }
3351 case RandomVirtualPixelMethod:
3352 {
3353 if (cache_info->random_info == (RandomInfo *) NULL)
3354 cache_info->random_info=AcquireRandomInfo();
3355 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003356 RandomX(cache_info->random_info,cache_info->columns),
3357 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003358 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003359 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003360 break;
3361 }
3362 case DitherVirtualPixelMethod:
3363 {
3364 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003365 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003366 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003367 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003368 break;
3369 }
3370 case TileVirtualPixelMethod:
3371 {
3372 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3373 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3374 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003375 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003376 exception);
cristy4c08aed2011-07-01 19:47:50 +00003377 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003378 break;
3379 }
3380 case MirrorVirtualPixelMethod:
3381 {
3382 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3383 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003384 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003385 x_modulo.remainder-1L;
3386 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3387 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003388 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003389 y_modulo.remainder-1L;
3390 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003391 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003392 exception);
cristy4c08aed2011-07-01 19:47:50 +00003393 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003394 break;
3395 }
3396 case HorizontalTileEdgeVirtualPixelMethod:
3397 {
3398 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3399 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003400 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003401 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003402 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003403 break;
3404 }
3405 case VerticalTileEdgeVirtualPixelMethod:
3406 {
3407 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3408 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003409 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003410 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003411 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3412 break;
3413 }
3414 case BackgroundVirtualPixelMethod:
3415 case BlackVirtualPixelMethod:
3416 case GrayVirtualPixelMethod:
3417 case TransparentVirtualPixelMethod:
3418 case MaskVirtualPixelMethod:
3419 case WhiteVirtualPixelMethod:
3420 {
3421 p=virtual_pixel;
3422 r=virtual_associated_pixel;
3423 break;
3424 }
3425 case EdgeVirtualPixelMethod:
3426 case CheckerTileVirtualPixelMethod:
3427 {
3428 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3429 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3430 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3431 {
3432 p=virtual_pixel;
3433 r=virtual_associated_pixel;
3434 break;
3435 }
3436 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3437 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3438 exception);
3439 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3440 break;
3441 }
3442 case HorizontalTileVirtualPixelMethod:
3443 {
3444 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3445 {
3446 p=virtual_pixel;
3447 r=virtual_associated_pixel;
3448 break;
3449 }
3450 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3451 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3452 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3453 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3454 exception);
3455 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3456 break;
3457 }
3458 case VerticalTileVirtualPixelMethod:
3459 {
3460 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3461 {
3462 p=virtual_pixel;
3463 r=virtual_associated_pixel;
3464 break;
3465 }
3466 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3467 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3468 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3469 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3470 exception);
3471 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003472 break;
3473 }
3474 }
cristy4c08aed2011-07-01 19:47:50 +00003475 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003476 break;
cristyed231572011-07-14 02:18:59 +00003477 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00003478 sizeof(*p));
cristyed231572011-07-14 02:18:59 +00003479 q+=cache_info->number_channels;
cristy4c08aed2011-07-01 19:47:50 +00003480 if ((s != (void *) NULL) &&
3481 (r != (const void *) NULL))
3482 {
3483 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3484 s+=cache_info->metacontent_extent;
3485 }
cristy3ed852e2009-09-05 21:47:34 +00003486 continue;
3487 }
3488 /*
3489 Transfer a run of pixels.
3490 */
cristy4c08aed2011-07-01 19:47:50 +00003491 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3492 length,1UL,*virtual_nexus,exception);
3493 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003494 break;
cristy4c08aed2011-07-01 19:47:50 +00003495 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristyed231572011-07-14 02:18:59 +00003496 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3497 q+=length*cache_info->number_channels;
cristy4c08aed2011-07-01 19:47:50 +00003498 if ((s != (void *) NULL) && (r != (const void *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003499 {
cristy4c08aed2011-07-01 19:47:50 +00003500 (void) memcpy(s,r,(size_t) length);
3501 s+=length*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003502 }
3503 }
3504 }
cristy4c08aed2011-07-01 19:47:50 +00003505 /*
3506 Free resources.
3507 */
3508 if (virtual_associated_pixel != (void *) NULL)
3509 virtual_associated_pixel=(void *) RelinquishMagickMemory(
3510 virtual_associated_pixel);
3511 if (virtual_pixel != (Quantum *) NULL)
3512 virtual_pixel=(Quantum *) RelinquishMagickMemory(virtual_pixel);
cristy3ed852e2009-09-05 21:47:34 +00003513 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3514 return(pixels);
3515}
3516
3517/*
3518%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3519% %
3520% %
3521% %
3522+ G e t V i r t u a l P i x e l C a c h e %
3523% %
3524% %
3525% %
3526%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3527%
3528% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3529% cache as defined by the geometry parameters. A pointer to the pixels
3530% is returned if the pixels are transferred, otherwise a NULL is returned.
3531%
3532% The format of the GetVirtualPixelCache() method is:
3533%
cristy4c08aed2011-07-01 19:47:50 +00003534% const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003535% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3536% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003537% ExceptionInfo *exception)
3538%
3539% A description of each parameter follows:
3540%
3541% o image: the image.
3542%
3543% o virtual_pixel_method: the virtual pixel method.
3544%
3545% o x,y,columns,rows: These values define the perimeter of a region of
3546% pixels.
3547%
3548% o exception: return any errors or warnings in this structure.
3549%
3550*/
cristy4c08aed2011-07-01 19:47:50 +00003551static const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003552 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3553 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003554{
3555 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003556 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003557
cristy5c9e6f22010-09-17 17:31:01 +00003558 const int
3559 id = GetOpenMPThreadId();
3560
cristy4c08aed2011-07-01 19:47:50 +00003561 const Quantum
3562 *pixels;
3563
cristye7cc7cf2010-09-21 13:26:47 +00003564 assert(image != (const Image *) NULL);
3565 assert(image->signature == MagickSignature);
3566 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003567 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003568 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003569 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00003570 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3571 cache_info->nexus_info[id],exception);
3572 return(pixels);
cristy3ed852e2009-09-05 21:47:34 +00003573}
3574
3575/*
3576%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3577% %
3578% %
3579% %
3580% G e t V i r t u a l P i x e l Q u e u e %
3581% %
3582% %
3583% %
3584%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3585%
cristy4c08aed2011-07-01 19:47:50 +00003586% GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3587% with the last call to QueueAuthenticPixels() or GetVirtualPixels().
cristy3ed852e2009-09-05 21:47:34 +00003588%
3589% The format of the GetVirtualPixelQueue() method is:
3590%
cristy4c08aed2011-07-01 19:47:50 +00003591% const Quantum *GetVirtualPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00003592%
3593% A description of each parameter follows:
3594%
3595% o image: the image.
3596%
3597*/
cristy4c08aed2011-07-01 19:47:50 +00003598MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003599{
3600 CacheInfo
3601 *cache_info;
3602
cristy2036f5c2010-09-19 21:18:17 +00003603 const int
3604 id = GetOpenMPThreadId();
3605
cristy3ed852e2009-09-05 21:47:34 +00003606 assert(image != (const Image *) NULL);
3607 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003608 assert(image->cache != (Cache) NULL);
3609 cache_info=(CacheInfo *) image->cache;
3610 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003611 if (cache_info->methods.get_virtual_pixels_handler !=
3612 (GetVirtualPixelsHandler) NULL)
3613 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003614 assert(id < (int) cache_info->number_threads);
3615 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003616}
3617
3618/*
3619%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3620% %
3621% %
3622% %
3623% G e t V i r t u a l P i x e l s %
3624% %
3625% %
3626% %
3627%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3628%
3629% GetVirtualPixels() returns an immutable pixel region. If the
3630% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003631% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003632% copy of the pixels or it may point to the original pixels in memory.
3633% Performance is maximized if the selected region is part of one row, or one
3634% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003635% (without a copy) if the image is in memory, or in a memory-mapped file. The
3636% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003637%
3638% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00003639% Quantum. If the image type is CMYK or the storage class is PseudoClass,
3640% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3641% access the meta-content (of type void) corresponding to the the
3642% region.
cristy3ed852e2009-09-05 21:47:34 +00003643%
3644% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3645%
3646% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3647% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3648% GetCacheViewAuthenticPixels() instead.
3649%
3650% The format of the GetVirtualPixels() method is:
3651%
cristy4c08aed2011-07-01 19:47:50 +00003652% const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00003653% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003654% ExceptionInfo *exception)
3655%
3656% A description of each parameter follows:
3657%
3658% o image: the image.
3659%
3660% o x,y,columns,rows: These values define the perimeter of a region of
3661% pixels.
3662%
3663% o exception: return any errors or warnings in this structure.
3664%
3665*/
cristy4c08aed2011-07-01 19:47:50 +00003666MagickExport const Quantum *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003667 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3668 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003669{
3670 CacheInfo
3671 *cache_info;
3672
cristy2036f5c2010-09-19 21:18:17 +00003673 const int
3674 id = GetOpenMPThreadId();
3675
cristy4c08aed2011-07-01 19:47:50 +00003676 const Quantum
3677 *pixels;
3678
cristy3ed852e2009-09-05 21:47:34 +00003679 assert(image != (const Image *) NULL);
3680 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003681 assert(image->cache != (Cache) NULL);
3682 cache_info=(CacheInfo *) image->cache;
3683 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003684 if (cache_info->methods.get_virtual_pixel_handler !=
3685 (GetVirtualPixelHandler) NULL)
3686 return(cache_info->methods.get_virtual_pixel_handler(image,
3687 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003688 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00003689 pixels=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3690 columns,rows,cache_info->nexus_info[id],exception);
3691 return(pixels);
cristy3ed852e2009-09-05 21:47:34 +00003692}
3693
3694/*
3695%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3696% %
3697% %
3698% %
3699+ 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 %
3700% %
3701% %
3702% %
3703%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3704%
cristy4c08aed2011-07-01 19:47:50 +00003705% GetVirtualPixelsCache() returns the pixels associated corresponding with the
3706% last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00003707%
3708% The format of the GetVirtualPixelsCache() method is:
3709%
cristy4c08aed2011-07-01 19:47:50 +00003710% Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003711%
3712% A description of each parameter follows:
3713%
3714% o image: the image.
3715%
3716*/
cristy4c08aed2011-07-01 19:47:50 +00003717static const Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003718{
3719 CacheInfo
3720 *cache_info;
3721
cristy5c9e6f22010-09-17 17:31:01 +00003722 const int
3723 id = GetOpenMPThreadId();
3724
cristye7cc7cf2010-09-21 13:26:47 +00003725 assert(image != (const Image *) NULL);
3726 assert(image->signature == MagickSignature);
3727 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003728 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003729 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003730 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003731 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003732}
3733
3734/*
3735%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3736% %
3737% %
3738% %
3739+ G e t V i r t u a l P i x e l s N e x u s %
3740% %
3741% %
3742% %
3743%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3744%
3745% GetVirtualPixelsNexus() returns the pixels associated with the specified
3746% cache nexus.
3747%
3748% The format of the GetVirtualPixelsNexus() method is:
3749%
cristy4c08aed2011-07-01 19:47:50 +00003750% const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003751% NexusInfo *nexus_info)
3752%
3753% A description of each parameter follows:
3754%
3755% o cache: the pixel cache.
3756%
3757% o nexus_info: the cache nexus to return the colormap pixels.
3758%
3759*/
cristy4c08aed2011-07-01 19:47:50 +00003760MagickExport const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003761 NexusInfo *nexus_info)
3762{
3763 CacheInfo
3764 *cache_info;
3765
cristye7cc7cf2010-09-21 13:26:47 +00003766 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003767 cache_info=(CacheInfo *) cache;
3768 assert(cache_info->signature == MagickSignature);
3769 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003770 return((Quantum *) NULL);
3771 return((const Quantum *) nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00003772}
3773
3774/*
3775%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3776% %
3777% %
3778% %
3779+ M a s k P i x e l C a c h e N e x u s %
3780% %
3781% %
3782% %
3783%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3784%
3785% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3786% The method returns MagickTrue if the pixel region is masked, otherwise
3787% MagickFalse.
3788%
3789% The format of the MaskPixelCacheNexus() method is:
3790%
3791% MagickBooleanType MaskPixelCacheNexus(Image *image,
3792% NexusInfo *nexus_info,ExceptionInfo *exception)
3793%
3794% A description of each parameter follows:
3795%
3796% o image: the image.
3797%
3798% o nexus_info: the cache nexus to clip.
3799%
3800% o exception: return any errors or warnings in this structure.
3801%
3802*/
3803
cristy4c08aed2011-07-01 19:47:50 +00003804static inline void MagickPixelCompositeMask(const PixelInfo *p,
3805 const MagickRealType alpha,const PixelInfo *q,
3806 const MagickRealType beta,PixelInfo *composite)
cristy3ed852e2009-09-05 21:47:34 +00003807{
3808 MagickRealType
3809 gamma;
3810
cristy4c08aed2011-07-01 19:47:50 +00003811 if (alpha == TransparentAlpha)
cristy3ed852e2009-09-05 21:47:34 +00003812 {
3813 *composite=(*q);
3814 return;
3815 }
3816 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3817 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
cristyb40bd892011-04-23 00:52:38 +00003818 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3819 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3820 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
cristy3ed852e2009-09-05 21:47:34 +00003821 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
cristy4c08aed2011-07-01 19:47:50 +00003822 composite->black=gamma*MagickOver_(p->black,alpha,q->black,beta);
cristy3ed852e2009-09-05 21:47:34 +00003823}
3824
3825static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3826 ExceptionInfo *exception)
3827{
3828 CacheInfo
3829 *cache_info;
3830
cristy4c08aed2011-07-01 19:47:50 +00003831 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00003832 alpha,
3833 beta;
3834
3835 MagickSizeType
3836 number_pixels;
3837
3838 NexusInfo
3839 **clip_nexus,
3840 **image_nexus;
3841
cristy4c08aed2011-07-01 19:47:50 +00003842 register const Quantum
3843 *restrict p,
cristyc47d1f82009-11-26 01:44:43 +00003844 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003845
cristy4c08aed2011-07-01 19:47:50 +00003846 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00003847 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003848
cristye076a6e2010-08-15 19:59:43 +00003849 register ssize_t
3850 i;
3851
cristy3ed852e2009-09-05 21:47:34 +00003852 /*
3853 Apply clip mask.
3854 */
3855 if (image->debug != MagickFalse)
3856 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3857 if (image->mask == (Image *) NULL)
3858 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +00003859 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00003860 if (cache_info == (Cache) NULL)
3861 return(MagickFalse);
3862 image_nexus=AcquirePixelCacheNexus(1);
3863 clip_nexus=AcquirePixelCacheNexus(1);
3864 if ((image_nexus == (NexusInfo **) NULL) ||
3865 (clip_nexus == (NexusInfo **) NULL))
3866 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003867 p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
3868 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3869 nexus_info->region.height,image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003870 q=nexus_info->pixels;
cristy3ed852e2009-09-05 21:47:34 +00003871 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3872 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3873 nexus_info->region.height,clip_nexus[0],&image->exception);
cristy4c08aed2011-07-01 19:47:50 +00003874 GetPixelInfo(image,&alpha);
3875 GetPixelInfo(image,&beta);
cristy3ed852e2009-09-05 21:47:34 +00003876 number_pixels=(MagickSizeType) nexus_info->region.width*
3877 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +00003878 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +00003879 {
cristy4c08aed2011-07-01 19:47:50 +00003880 if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003881 break;
cristy4c08aed2011-07-01 19:47:50 +00003882 SetPixelInfo(image,p,&alpha);
3883 SetPixelInfo(image,q,&beta);
3884 MagickPixelCompositeMask(&beta,(MagickRealType) GetPixelIntensity(image,r),
3885 &alpha,alpha.alpha,&beta);
3886 SetPixelRed(image,ClampToQuantum(beta.red),q);
3887 SetPixelGreen(image,ClampToQuantum(beta.green),q);
3888 SetPixelBlue(image,ClampToQuantum(beta.blue),q);
3889 if (cache_info->colorspace == CMYKColorspace)
3890 SetPixelBlack(image,ClampToQuantum(beta.black),q);
3891 SetPixelAlpha(image,ClampToQuantum(beta.alpha),q);
cristy3ed852e2009-09-05 21:47:34 +00003892 p++;
3893 q++;
3894 r++;
3895 }
3896 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3897 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +00003898 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003899 return(MagickFalse);
3900 return(MagickTrue);
3901}
3902
3903/*
3904%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3905% %
3906% %
3907% %
3908+ O p e n P i x e l C a c h e %
3909% %
3910% %
3911% %
3912%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3913%
3914% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3915% dimensions, allocating space for the image pixels and optionally the
cristy4c08aed2011-07-01 19:47:50 +00003916% metacontent, and memory mapping the cache if it is disk based. The cache
3917% nexus array is initialized as well.
cristy3ed852e2009-09-05 21:47:34 +00003918%
3919% The format of the OpenPixelCache() method is:
3920%
3921% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3922% ExceptionInfo *exception)
3923%
3924% A description of each parameter follows:
3925%
3926% o image: the image.
3927%
3928% o mode: ReadMode, WriteMode, or IOMode.
3929%
3930% o exception: return any errors or warnings in this structure.
3931%
3932*/
3933
cristyd43a46b2010-01-21 02:13:41 +00003934static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003935{
3936 cache_info->mapped=MagickFalse;
cristy5e044432011-07-16 03:35:35 +00003937 cache_info->pixels=(Quantum *) AcquireAlignedMemory(1,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003938 cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003939 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003940 {
3941 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003942 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003943 cache_info->length);
3944 }
3945}
3946
3947static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3948{
3949 CacheInfo
3950 *cache_info;
3951
3952 MagickOffsetType
3953 count,
3954 extent,
3955 offset;
3956
3957 cache_info=(CacheInfo *) image->cache;
3958 if (image->debug != MagickFalse)
3959 {
3960 char
3961 format[MaxTextExtent],
3962 message[MaxTextExtent];
3963
cristyb9080c92009-12-01 20:13:26 +00003964 (void) FormatMagickSize(length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003965 (void) FormatLocaleString(message,MaxTextExtent,
cristyb37d4f22011-06-27 19:22:42 +00003966 "extend %s (%s[%d], disk, %s)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003967 cache_info->cache_filename,cache_info->file,format);
3968 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3969 }
3970 if (length != (MagickSizeType) ((MagickOffsetType) length))
3971 return(MagickFalse);
cristy7f317702011-02-18 20:40:28 +00003972 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
cristy3ed852e2009-09-05 21:47:34 +00003973 if (extent < 0)
3974 return(MagickFalse);
3975 if ((MagickSizeType) extent >= length)
3976 return(MagickTrue);
3977 offset=(MagickOffsetType) length-1;
3978 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3979 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3980}
3981
3982static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3983 ExceptionInfo *exception)
3984{
cristy3ed852e2009-09-05 21:47:34 +00003985 CacheInfo
3986 *cache_info,
3987 source_info;
3988
cristyf3a6a9d2010-11-07 21:02:56 +00003989 char
3990 format[MaxTextExtent],
3991 message[MaxTextExtent];
3992
cristy4c08aed2011-07-01 19:47:50 +00003993 MagickBooleanType
3994 status;
3995
cristy3ed852e2009-09-05 21:47:34 +00003996 MagickSizeType
3997 length,
3998 number_pixels;
3999
cristy3ed852e2009-09-05 21:47:34 +00004000 size_t
cristye076a6e2010-08-15 19:59:43 +00004001 columns,
cristy3ed852e2009-09-05 21:47:34 +00004002 packet_size;
4003
cristye7cc7cf2010-09-21 13:26:47 +00004004 assert(image != (const Image *) NULL);
4005 assert(image->signature == MagickSignature);
4006 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004007 if (image->debug != MagickFalse)
4008 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4009 if ((image->columns == 0) || (image->rows == 0))
4010 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
cristyed231572011-07-14 02:18:59 +00004011 StandardPixelChannelMap(image);
cristy3ed852e2009-09-05 21:47:34 +00004012 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004013 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004014 source_info=(*cache_info);
4015 source_info.file=(-1);
cristyb51dff52011-05-19 16:55:47 +00004016 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
cristye8c25f92010-06-03 00:53:06 +00004017 image->filename,(double) GetImageIndexInList(image));
cristy4c08aed2011-07-01 19:47:50 +00004018 cache_info->storage_class=image->storage_class;
4019 cache_info->colorspace=image->colorspace;
cristy87528ea2009-09-10 14:53:56 +00004020 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +00004021 cache_info->rows=image->rows;
4022 cache_info->columns=image->columns;
cristyed231572011-07-14 02:18:59 +00004023 cache_info->number_channels=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +00004024 cache_info->metacontent_extent=image->metacontent_extent;
cristy73724512010-04-12 14:43:14 +00004025 if (image->ping != MagickFalse)
4026 {
cristy73724512010-04-12 14:43:14 +00004027 cache_info->type=PingCache;
cristy4c08aed2011-07-01 19:47:50 +00004028 cache_info->pixels=(Quantum *) NULL;
4029 cache_info->metacontent=(void *) NULL;
cristy73724512010-04-12 14:43:14 +00004030 cache_info->length=0;
4031 return(MagickTrue);
4032 }
cristy3ed852e2009-09-05 21:47:34 +00004033 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristyed231572011-07-14 02:18:59 +00004034 packet_size=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00004035 if (image->metacontent_extent != 0)
4036 packet_size+=cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004037 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00004038 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00004039 if (cache_info->columns != columns)
4040 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4041 image->filename);
4042 cache_info->length=length;
cristy4c08aed2011-07-01 19:47:50 +00004043 if ((cache_info->type != UndefinedCache) &&
4044 (cache_info->columns <= source_info.columns) &&
4045 (cache_info->rows <= source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00004046 (cache_info->number_channels <= source_info.number_channels) &&
cristy4c08aed2011-07-01 19:47:50 +00004047 (cache_info->metacontent_extent <= source_info.metacontent_extent))
4048 {
4049 /*
4050 Inline pixel cache clone optimization.
4051 */
4052 if ((cache_info->columns == source_info.columns) &&
4053 (cache_info->rows == source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00004054 (cache_info->number_channels == source_info.number_channels) &&
cristy4c08aed2011-07-01 19:47:50 +00004055 (cache_info->metacontent_extent == source_info.metacontent_extent))
4056 return(MagickTrue);
4057 return(ClonePixelCachePixels(cache_info,&source_info,exception));
4058 }
cristy3ed852e2009-09-05 21:47:34 +00004059 status=AcquireMagickResource(AreaResource,cache_info->length);
cristyed231572011-07-14 02:18:59 +00004060 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00004061 cache_info->metacontent_extent);
cristy3ed852e2009-09-05 21:47:34 +00004062 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4063 {
4064 status=AcquireMagickResource(MemoryResource,cache_info->length);
4065 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4066 (cache_info->type == MemoryCache))
4067 {
cristyd43a46b2010-01-21 02:13:41 +00004068 AllocatePixelCachePixels(cache_info);
cristy4c08aed2011-07-01 19:47:50 +00004069 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004070 cache_info->pixels=source_info.pixels;
4071 else
4072 {
4073 /*
4074 Create memory pixel cache.
4075 */
cristy4c08aed2011-07-01 19:47:50 +00004076 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004077 if (image->debug != MagickFalse)
4078 {
cristy97e7a572009-12-05 15:07:53 +00004079 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004080 format);
cristyb51dff52011-05-19 16:55:47 +00004081 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004082 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
4083 cache_info->filename,cache_info->mapped != MagickFalse ?
4084 "anonymous" : "heap",(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00004085 cache_info->rows,(double) cache_info->number_channels,
cristye8c25f92010-06-03 00:53:06 +00004086 format);
cristy3ed852e2009-09-05 21:47:34 +00004087 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4088 message);
4089 }
cristy3ed852e2009-09-05 21:47:34 +00004090 cache_info->type=MemoryCache;
cristy4c08aed2011-07-01 19:47:50 +00004091 cache_info->metacontent=(void *) NULL;
4092 if (cache_info->metacontent_extent != 0)
4093 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00004094 number_pixels*cache_info->number_channels);
cristy3ed852e2009-09-05 21:47:34 +00004095 if (source_info.storage_class != UndefinedClass)
4096 {
cristy4c08aed2011-07-01 19:47:50 +00004097 status=ClonePixelCachePixels(cache_info,&source_info,
cristy3ed852e2009-09-05 21:47:34 +00004098 exception);
4099 RelinquishPixelCachePixels(&source_info);
4100 }
cristy4c08aed2011-07-01 19:47:50 +00004101 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004102 }
4103 }
4104 RelinquishMagickResource(MemoryResource,cache_info->length);
4105 }
4106 /*
4107 Create pixel cache on disk.
4108 */
4109 status=AcquireMagickResource(DiskResource,cache_info->length);
4110 if (status == MagickFalse)
4111 {
4112 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4113 "CacheResourcesExhausted","`%s'",image->filename);
4114 return(MagickFalse);
4115 }
4116 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4117 {
4118 RelinquishMagickResource(DiskResource,cache_info->length);
4119 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4120 image->filename);
4121 return(MagickFalse);
4122 }
4123 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4124 cache_info->length);
4125 if (status == MagickFalse)
4126 {
4127 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4128 image->filename);
4129 return(MagickFalse);
4130 }
cristyed231572011-07-14 02:18:59 +00004131 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00004132 cache_info->metacontent_extent);
cristy3ed852e2009-09-05 21:47:34 +00004133 status=AcquireMagickResource(AreaResource,cache_info->length);
4134 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4135 cache_info->type=DiskCache;
4136 else
4137 {
4138 status=AcquireMagickResource(MapResource,cache_info->length);
4139 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4140 (cache_info->type != MemoryCache))
4141 cache_info->type=DiskCache;
4142 else
4143 {
cristy4c08aed2011-07-01 19:47:50 +00004144 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
cristy3ed852e2009-09-05 21:47:34 +00004145 cache_info->offset,(size_t) cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00004146 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004147 {
cristy3ed852e2009-09-05 21:47:34 +00004148 cache_info->type=DiskCache;
cristy4c08aed2011-07-01 19:47:50 +00004149 cache_info->pixels=source_info.pixels;
cristy3ed852e2009-09-05 21:47:34 +00004150 }
4151 else
4152 {
4153 /*
4154 Create file-backed memory-mapped pixel cache.
4155 */
cristy4c08aed2011-07-01 19:47:50 +00004156 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004157 (void) ClosePixelCacheOnDisk(cache_info);
4158 cache_info->type=MapCache;
4159 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004160 cache_info->metacontent=(void *) NULL;
4161 if (cache_info->metacontent_extent != 0)
4162 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00004163 number_pixels*cache_info->number_channels);
cristy4c08aed2011-07-01 19:47:50 +00004164 if (source_info.storage_class != UndefinedClass)
cristy3ed852e2009-09-05 21:47:34 +00004165 {
4166 status=ClonePixelCachePixels(cache_info,&source_info,
4167 exception);
4168 RelinquishPixelCachePixels(&source_info);
4169 }
4170 if (image->debug != MagickFalse)
4171 {
cristy97e7a572009-12-05 15:07:53 +00004172 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004173 format);
cristyb51dff52011-05-19 16:55:47 +00004174 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004175 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
cristy3ed852e2009-09-05 21:47:34 +00004176 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004177 cache_info->file,(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00004178 cache_info->rows,(double) cache_info->number_channels,
cristy4c08aed2011-07-01 19:47:50 +00004179 format);
cristy3ed852e2009-09-05 21:47:34 +00004180 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4181 message);
4182 }
cristy4c08aed2011-07-01 19:47:50 +00004183 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004184 }
4185 }
4186 RelinquishMagickResource(MapResource,cache_info->length);
4187 }
cristy4c08aed2011-07-01 19:47:50 +00004188 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004189 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4190 {
4191 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4192 RelinquishPixelCachePixels(&source_info);
4193 }
4194 if (image->debug != MagickFalse)
4195 {
cristyb9080c92009-12-01 20:13:26 +00004196 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00004197 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004198 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
cristye8c25f92010-06-03 00:53:06 +00004199 cache_info->cache_filename,cache_info->file,(double)
cristy4c08aed2011-07-01 19:47:50 +00004200 cache_info->columns,(double) cache_info->rows,(double)
cristyed231572011-07-14 02:18:59 +00004201 cache_info->number_channels,format);
cristy3ed852e2009-09-05 21:47:34 +00004202 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4203 }
cristy4c08aed2011-07-01 19:47:50 +00004204 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004205}
4206
4207/*
4208%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4209% %
4210% %
4211% %
4212+ P e r s i s t P i x e l C a c h e %
4213% %
4214% %
4215% %
4216%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4217%
4218% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4219% persistent pixel cache is one that resides on disk and is not destroyed
4220% when the program exits.
4221%
4222% The format of the PersistPixelCache() method is:
4223%
4224% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4225% const MagickBooleanType attach,MagickOffsetType *offset,
4226% ExceptionInfo *exception)
4227%
4228% A description of each parameter follows:
4229%
4230% o image: the image.
4231%
4232% o filename: the persistent pixel cache filename.
4233%
cristyf3a6a9d2010-11-07 21:02:56 +00004234% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00004235%
cristy3ed852e2009-09-05 21:47:34 +00004236% o initialize: A value other than zero initializes the persistent pixel
4237% cache.
4238%
4239% o offset: the offset in the persistent cache to store pixels.
4240%
4241% o exception: return any errors or warnings in this structure.
4242%
4243*/
4244MagickExport MagickBooleanType PersistPixelCache(Image *image,
4245 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4246 ExceptionInfo *exception)
4247{
4248 CacheInfo
4249 *cache_info,
4250 *clone_info;
4251
4252 Image
4253 clone_image;
4254
cristy3ed852e2009-09-05 21:47:34 +00004255 MagickBooleanType
4256 status;
4257
cristye076a6e2010-08-15 19:59:43 +00004258 ssize_t
4259 page_size;
4260
cristy3ed852e2009-09-05 21:47:34 +00004261 assert(image != (Image *) NULL);
4262 assert(image->signature == MagickSignature);
4263 if (image->debug != MagickFalse)
4264 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4265 assert(image->cache != (void *) NULL);
4266 assert(filename != (const char *) NULL);
4267 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004268 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004269 cache_info=(CacheInfo *) image->cache;
4270 assert(cache_info->signature == MagickSignature);
4271 if (attach != MagickFalse)
4272 {
4273 /*
cristy01b7eb02009-09-10 23:10:14 +00004274 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004275 */
4276 if (image->debug != MagickFalse)
4277 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004278 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004279 (void) CopyMagickString(cache_info->cache_filename,filename,
4280 MaxTextExtent);
4281 cache_info->type=DiskCache;
4282 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004283 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004284 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004285 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004286 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004287 }
cristy01b7eb02009-09-10 23:10:14 +00004288 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4289 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004290 {
cristyf84a1932010-01-03 18:00:18 +00004291 LockSemaphoreInfo(cache_info->semaphore);
cristy09449f72010-01-23 03:08:36 +00004292 if ((cache_info->mode != ReadMode) &&
4293 (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004294 (cache_info->reference_count == 1))
4295 {
4296 int
4297 status;
4298
4299 /*
cristy01b7eb02009-09-10 23:10:14 +00004300 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004301 */
4302 status=rename(cache_info->cache_filename,filename);
4303 if (status == 0)
4304 {
4305 (void) CopyMagickString(cache_info->cache_filename,filename,
4306 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004307 *offset+=cache_info->length+page_size-(cache_info->length %
4308 page_size);
cristyf84a1932010-01-03 18:00:18 +00004309 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004310 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004311 if (image->debug != MagickFalse)
4312 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4313 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004314 return(MagickTrue);
4315 }
4316 }
cristyf84a1932010-01-03 18:00:18 +00004317 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004318 }
4319 /*
cristy01b7eb02009-09-10 23:10:14 +00004320 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004321 */
4322 clone_image=(*image);
4323 clone_info=(CacheInfo *) clone_image.cache;
4324 image->cache=ClonePixelCache(cache_info);
4325 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4326 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4327 cache_info->type=DiskCache;
4328 cache_info->offset=(*offset);
4329 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004330 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004331 if (status != MagickFalse)
cristycfae90a2010-10-04 14:43:33 +00004332 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
cristy688f07b2009-09-27 15:19:13 +00004333 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004334 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4335 return(status);
4336}
4337
4338/*
4339%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4340% %
4341% %
4342% %
4343+ Q u e u e A u t h e n t i c N e x u s %
4344% %
4345% %
4346% %
4347%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4348%
4349% QueueAuthenticNexus() allocates an region to store image pixels as defined
4350% by the region rectangle and returns a pointer to the region. This region is
4351% subsequently transferred from the pixel cache with
4352% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4353% pixels are transferred, otherwise a NULL is returned.
4354%
4355% The format of the QueueAuthenticNexus() method is:
4356%
cristy4c08aed2011-07-01 19:47:50 +00004357% Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004358% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004359% NexusInfo *nexus_info,ExceptionInfo *exception)
4360%
4361% A description of each parameter follows:
4362%
4363% o image: the image.
4364%
4365% o x,y,columns,rows: These values define the perimeter of a region of
4366% pixels.
4367%
4368% o nexus_info: the cache nexus to set.
4369%
4370% o exception: return any errors or warnings in this structure.
4371%
4372*/
cristy4c08aed2011-07-01 19:47:50 +00004373MagickExport Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy30097232010-07-01 02:16:30 +00004374 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
4375 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004376{
4377 CacheInfo
4378 *cache_info;
4379
4380 MagickOffsetType
4381 offset;
4382
4383 MagickSizeType
4384 number_pixels;
4385
4386 RectangleInfo
4387 region;
4388
4389 /*
4390 Validate pixel cache geometry.
4391 */
cristye7cc7cf2010-09-21 13:26:47 +00004392 assert(image != (const Image *) NULL);
4393 assert(image->signature == MagickSignature);
4394 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004395 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
cristye7cc7cf2010-09-21 13:26:47 +00004396 assert(cache_info->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00004397 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004398 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004399 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4400 {
4401 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4402 "NoPixelsDefinedInCache","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004403 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004404 }
cristybb503372010-05-27 20:51:26 +00004405 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4406 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004407 {
4408 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4409 "PixelsAreNotAuthentic","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004410 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004411 }
4412 offset=(MagickOffsetType) y*cache_info->columns+x;
4413 if (offset < 0)
cristy4c08aed2011-07-01 19:47:50 +00004414 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004415 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4416 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4417 if ((MagickSizeType) offset >= number_pixels)
cristy4c08aed2011-07-01 19:47:50 +00004418 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004419 /*
4420 Return pixel cache.
4421 */
4422 region.x=x;
4423 region.y=y;
4424 region.width=columns;
4425 region.height=rows;
4426 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4427}
4428
4429/*
4430%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4431% %
4432% %
4433% %
4434+ 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 %
4435% %
4436% %
4437% %
4438%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4439%
4440% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4441% defined by the region rectangle and returns a pointer to the region. This
4442% region is subsequently transferred from the pixel cache with
4443% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4444% pixels are transferred, otherwise a NULL is returned.
4445%
4446% The format of the QueueAuthenticPixelsCache() method is:
4447%
cristy4c08aed2011-07-01 19:47:50 +00004448% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004449% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004450% ExceptionInfo *exception)
4451%
4452% A description of each parameter follows:
4453%
4454% o image: the image.
4455%
4456% o x,y,columns,rows: These values define the perimeter of a region of
4457% pixels.
4458%
4459% o exception: return any errors or warnings in this structure.
4460%
4461*/
cristy4c08aed2011-07-01 19:47:50 +00004462static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004463 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004464 ExceptionInfo *exception)
4465{
4466 CacheInfo
4467 *cache_info;
4468
cristy5c9e6f22010-09-17 17:31:01 +00004469 const int
4470 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004471
cristy4c08aed2011-07-01 19:47:50 +00004472 Quantum
4473 *pixels;
4474
cristye7cc7cf2010-09-21 13:26:47 +00004475 assert(image != (const Image *) NULL);
4476 assert(image->signature == MagickSignature);
4477 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004478 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004479 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004480 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00004481 pixels=QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4482 exception);
4483 return(pixels);
cristy3ed852e2009-09-05 21:47:34 +00004484}
4485
4486/*
4487%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4488% %
4489% %
4490% %
4491% Q u e u e A u t h e n t i c P i x e l s %
4492% %
4493% %
4494% %
4495%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4496%
4497% QueueAuthenticPixels() queues a mutable pixel region. If the region is
cristy4c08aed2011-07-01 19:47:50 +00004498% successfully initialized a pointer to a Quantum array representing the
cristy3ed852e2009-09-05 21:47:34 +00004499% region is returned, otherwise NULL is returned. The returned pointer may
4500% point to a temporary working buffer for the pixels or it may point to the
4501% final location of the pixels in memory.
4502%
4503% Write-only access means that any existing pixel values corresponding to
4504% the region are ignored. This is useful if the initial image is being
4505% created from scratch, or if the existing pixel values are to be
4506% completely replaced without need to refer to their pre-existing values.
4507% The application is free to read and write the pixel buffer returned by
4508% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4509% initialize the pixel array values. Initializing pixel array values is the
4510% application's responsibility.
4511%
4512% Performance is maximized if the selected region is part of one row, or
4513% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004514% pixels in-place (without a copy) if the image is in memory, or in a
4515% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004516% by the user.
4517%
4518% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00004519% Quantum. If the image type is CMYK or the storage class is PseudoClass,
4520% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4521% obtain the meta-content (of type void) corresponding to the region.
4522% Once the Quantum (and/or Quantum) array has been updated, the
4523% changes must be saved back to the underlying image using
4524% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00004525%
4526% The format of the QueueAuthenticPixels() method is:
4527%
cristy4c08aed2011-07-01 19:47:50 +00004528% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004529% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004530% ExceptionInfo *exception)
4531%
4532% A description of each parameter follows:
4533%
4534% o image: the image.
4535%
4536% o x,y,columns,rows: These values define the perimeter of a region of
4537% pixels.
4538%
4539% o exception: return any errors or warnings in this structure.
4540%
4541*/
cristy4c08aed2011-07-01 19:47:50 +00004542MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004543 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004544 ExceptionInfo *exception)
4545{
4546 CacheInfo
4547 *cache_info;
4548
cristy2036f5c2010-09-19 21:18:17 +00004549 const int
4550 id = GetOpenMPThreadId();
4551
cristy4c08aed2011-07-01 19:47:50 +00004552 Quantum
4553 *pixels;
4554
cristy3ed852e2009-09-05 21:47:34 +00004555 assert(image != (Image *) NULL);
4556 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004557 assert(image->cache != (Cache) NULL);
4558 cache_info=(CacheInfo *) image->cache;
4559 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004560 if (cache_info->methods.queue_authentic_pixels_handler !=
4561 (QueueAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004562 {
4563 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
4564 columns,rows,exception);
4565 return(pixels);
4566 }
cristy2036f5c2010-09-19 21:18:17 +00004567 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00004568 pixels=QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4569 exception);
4570 return(pixels);
cristy3ed852e2009-09-05 21:47:34 +00004571}
4572
4573/*
4574%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4575% %
4576% %
4577% %
cristy4c08aed2011-07-01 19:47:50 +00004578+ R e a d P i x e l C a c h e M e t a c o n t e n t %
cristy3ed852e2009-09-05 21:47:34 +00004579% %
4580% %
4581% %
4582%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4583%
cristy4c08aed2011-07-01 19:47:50 +00004584% ReadPixelCacheMetacontent() reads metacontent from the specified region of
cristy3ed852e2009-09-05 21:47:34 +00004585% the pixel cache.
4586%
cristy4c08aed2011-07-01 19:47:50 +00004587% The format of the ReadPixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00004588%
cristy4c08aed2011-07-01 19:47:50 +00004589% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004590% NexusInfo *nexus_info,ExceptionInfo *exception)
4591%
4592% A description of each parameter follows:
4593%
4594% o cache_info: the pixel cache.
4595%
cristy4c08aed2011-07-01 19:47:50 +00004596% o nexus_info: the cache nexus to read the metacontent.
cristy3ed852e2009-09-05 21:47:34 +00004597%
4598% o exception: return any errors or warnings in this structure.
4599%
4600*/
cristy4c08aed2011-07-01 19:47:50 +00004601static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004602 NexusInfo *nexus_info,ExceptionInfo *exception)
4603{
4604 MagickOffsetType
4605 count,
4606 offset;
4607
4608 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004609 extent,
4610 length;
cristy3ed852e2009-09-05 21:47:34 +00004611
cristybb503372010-05-27 20:51:26 +00004612 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004613 y;
4614
cristy4c08aed2011-07-01 19:47:50 +00004615 register unsigned char
4616 *restrict q;
4617
cristybb503372010-05-27 20:51:26 +00004618 size_t
cristy3ed852e2009-09-05 21:47:34 +00004619 rows;
4620
cristy4c08aed2011-07-01 19:47:50 +00004621 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00004622 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00004623 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004624 return(MagickTrue);
4625 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4626 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00004627 length=(MagickSizeType) nexus_info->region.width*
4628 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004629 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004630 extent=length*rows;
cristy4c08aed2011-07-01 19:47:50 +00004631 q=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00004632 switch (cache_info->type)
4633 {
4634 case MemoryCache:
4635 case MapCache:
4636 {
cristy4c08aed2011-07-01 19:47:50 +00004637 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00004638 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004639
4640 /*
cristy4c08aed2011-07-01 19:47:50 +00004641 Read meta-content from memory.
cristy3ed852e2009-09-05 21:47:34 +00004642 */
cristydd341db2010-03-04 19:06:38 +00004643 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004644 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004645 {
cristy48078b12010-09-23 17:11:01 +00004646 length=extent;
cristydd341db2010-03-04 19:06:38 +00004647 rows=1UL;
4648 }
cristy4c08aed2011-07-01 19:47:50 +00004649 p=(unsigned char *) cache_info->metacontent+offset*
4650 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00004651 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004652 {
cristy8f036fe2010-09-18 02:02:00 +00004653 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00004654 p+=cache_info->metacontent_extent*cache_info->columns;
4655 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004656 }
4657 break;
4658 }
4659 case DiskCache:
4660 {
4661 /*
cristy4c08aed2011-07-01 19:47:50 +00004662 Read meta content from disk.
cristy3ed852e2009-09-05 21:47:34 +00004663 */
4664 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4665 {
4666 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4667 cache_info->cache_filename);
4668 return(MagickFalse);
4669 }
cristydd341db2010-03-04 19:06:38 +00004670 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004671 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004672 {
cristy48078b12010-09-23 17:11:01 +00004673 length=extent;
cristydd341db2010-03-04 19:06:38 +00004674 rows=1UL;
4675 }
cristy48078b12010-09-23 17:11:01 +00004676 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004677 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004678 {
cristy48078b12010-09-23 17:11:01 +00004679 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00004680 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00004681 cache_info->metacontent_extent,length,(unsigned char *) q);
4682 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004683 break;
4684 offset+=cache_info->columns;
cristy4c08aed2011-07-01 19:47:50 +00004685 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004686 }
cristybb503372010-05-27 20:51:26 +00004687 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004688 {
4689 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4690 cache_info->cache_filename);
4691 return(MagickFalse);
4692 }
4693 break;
4694 }
4695 default:
4696 break;
4697 }
4698 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004699 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004700 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004701 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004702 nexus_info->region.width,(double) nexus_info->region.height,(double)
4703 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004704 return(MagickTrue);
4705}
4706
4707/*
4708%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4709% %
4710% %
4711% %
4712+ R e a d P i x e l C a c h e P i x e l s %
4713% %
4714% %
4715% %
4716%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4717%
4718% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4719% cache.
4720%
4721% The format of the ReadPixelCachePixels() method is:
4722%
4723% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4724% NexusInfo *nexus_info,ExceptionInfo *exception)
4725%
4726% A description of each parameter follows:
4727%
4728% o cache_info: the pixel cache.
4729%
4730% o nexus_info: the cache nexus to read the pixels.
4731%
4732% o exception: return any errors or warnings in this structure.
4733%
4734*/
4735static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4736 NexusInfo *nexus_info,ExceptionInfo *exception)
4737{
4738 MagickOffsetType
4739 count,
4740 offset;
4741
4742 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004743 extent,
4744 length;
cristy3ed852e2009-09-05 21:47:34 +00004745
cristy4c08aed2011-07-01 19:47:50 +00004746 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004747 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004748
cristye076a6e2010-08-15 19:59:43 +00004749 register ssize_t
4750 y;
4751
cristybb503372010-05-27 20:51:26 +00004752 size_t
cristy3ed852e2009-09-05 21:47:34 +00004753 rows;
4754
cristy4c08aed2011-07-01 19:47:50 +00004755 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004756 return(MagickTrue);
4757 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4758 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004759 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004760 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00004761 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004762 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004763 q=nexus_info->pixels;
4764 switch (cache_info->type)
4765 {
4766 case MemoryCache:
4767 case MapCache:
4768 {
cristy4c08aed2011-07-01 19:47:50 +00004769 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004770 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004771
4772 /*
4773 Read pixels from memory.
4774 */
cristydd341db2010-03-04 19:06:38 +00004775 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004776 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004777 {
cristy48078b12010-09-23 17:11:01 +00004778 length=extent;
cristydd341db2010-03-04 19:06:38 +00004779 rows=1UL;
4780 }
cristyed231572011-07-14 02:18:59 +00004781 p=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00004782 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004783 {
cristy8f036fe2010-09-18 02:02:00 +00004784 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00004785 p+=cache_info->number_channels*cache_info->columns;
4786 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004787 }
4788 break;
4789 }
4790 case DiskCache:
4791 {
4792 /*
4793 Read pixels from disk.
4794 */
4795 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4796 {
4797 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4798 cache_info->cache_filename);
4799 return(MagickFalse);
4800 }
cristydd341db2010-03-04 19:06:38 +00004801 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004802 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004803 {
cristy48078b12010-09-23 17:11:01 +00004804 length=extent;
cristydd341db2010-03-04 19:06:38 +00004805 rows=1UL;
4806 }
cristybb503372010-05-27 20:51:26 +00004807 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004808 {
4809 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00004810 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
cristy4c08aed2011-07-01 19:47:50 +00004811 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004812 break;
4813 offset+=cache_info->columns;
cristyed231572011-07-14 02:18:59 +00004814 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004815 }
cristybb503372010-05-27 20:51:26 +00004816 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004817 {
4818 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4819 cache_info->cache_filename);
4820 return(MagickFalse);
4821 }
4822 break;
4823 }
4824 default:
4825 break;
4826 }
4827 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004828 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004829 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004830 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004831 nexus_info->region.width,(double) nexus_info->region.height,(double)
4832 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004833 return(MagickTrue);
4834}
4835
4836/*
4837%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4838% %
4839% %
4840% %
4841+ R e f e r e n c e P i x e l C a c h e %
4842% %
4843% %
4844% %
4845%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4846%
4847% ReferencePixelCache() increments the reference count associated with the
4848% pixel cache returning a pointer to the cache.
4849%
4850% The format of the ReferencePixelCache method is:
4851%
4852% Cache ReferencePixelCache(Cache cache_info)
4853%
4854% A description of each parameter follows:
4855%
4856% o cache_info: the pixel cache.
4857%
4858*/
4859MagickExport Cache ReferencePixelCache(Cache cache)
4860{
4861 CacheInfo
4862 *cache_info;
4863
4864 assert(cache != (Cache *) NULL);
4865 cache_info=(CacheInfo *) cache;
4866 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004867 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004868 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004869 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004870 return(cache_info);
4871}
4872
4873/*
4874%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4875% %
4876% %
4877% %
4878+ S e t P i x e l C a c h e M e t h o d s %
4879% %
4880% %
4881% %
4882%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4883%
4884% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4885%
4886% The format of the SetPixelCacheMethods() method is:
4887%
4888% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4889%
4890% A description of each parameter follows:
4891%
4892% o cache: the pixel cache.
4893%
4894% o cache_methods: Specifies a pointer to a CacheMethods structure.
4895%
4896*/
4897MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4898{
4899 CacheInfo
4900 *cache_info;
4901
4902 GetOneAuthenticPixelFromHandler
4903 get_one_authentic_pixel_from_handler;
4904
4905 GetOneVirtualPixelFromHandler
4906 get_one_virtual_pixel_from_handler;
4907
4908 /*
4909 Set cache pixel methods.
4910 */
4911 assert(cache != (Cache) NULL);
4912 assert(cache_methods != (CacheMethods *) NULL);
4913 cache_info=(CacheInfo *) cache;
4914 assert(cache_info->signature == MagickSignature);
4915 if (cache_info->debug != MagickFalse)
4916 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4917 cache_info->filename);
4918 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4919 cache_info->methods.get_virtual_pixel_handler=
4920 cache_methods->get_virtual_pixel_handler;
4921 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4922 cache_info->methods.destroy_pixel_handler=
4923 cache_methods->destroy_pixel_handler;
cristy4c08aed2011-07-01 19:47:50 +00004924 if (cache_methods->get_virtual_metacontent_from_handler !=
4925 (GetVirtualMetacontentFromHandler) NULL)
4926 cache_info->methods.get_virtual_metacontent_from_handler=
4927 cache_methods->get_virtual_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004928 if (cache_methods->get_authentic_pixels_handler !=
4929 (GetAuthenticPixelsHandler) NULL)
4930 cache_info->methods.get_authentic_pixels_handler=
4931 cache_methods->get_authentic_pixels_handler;
4932 if (cache_methods->queue_authentic_pixels_handler !=
4933 (QueueAuthenticPixelsHandler) NULL)
4934 cache_info->methods.queue_authentic_pixels_handler=
4935 cache_methods->queue_authentic_pixels_handler;
4936 if (cache_methods->sync_authentic_pixels_handler !=
4937 (SyncAuthenticPixelsHandler) NULL)
4938 cache_info->methods.sync_authentic_pixels_handler=
4939 cache_methods->sync_authentic_pixels_handler;
4940 if (cache_methods->get_authentic_pixels_from_handler !=
4941 (GetAuthenticPixelsFromHandler) NULL)
4942 cache_info->methods.get_authentic_pixels_from_handler=
4943 cache_methods->get_authentic_pixels_from_handler;
cristy4c08aed2011-07-01 19:47:50 +00004944 if (cache_methods->get_authentic_metacontent_from_handler !=
4945 (GetAuthenticMetacontentFromHandler) NULL)
4946 cache_info->methods.get_authentic_metacontent_from_handler=
4947 cache_methods->get_authentic_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004948 get_one_virtual_pixel_from_handler=
4949 cache_info->methods.get_one_virtual_pixel_from_handler;
4950 if (get_one_virtual_pixel_from_handler !=
4951 (GetOneVirtualPixelFromHandler) NULL)
4952 cache_info->methods.get_one_virtual_pixel_from_handler=
4953 cache_methods->get_one_virtual_pixel_from_handler;
4954 get_one_authentic_pixel_from_handler=
4955 cache_methods->get_one_authentic_pixel_from_handler;
4956 if (get_one_authentic_pixel_from_handler !=
4957 (GetOneAuthenticPixelFromHandler) NULL)
4958 cache_info->methods.get_one_authentic_pixel_from_handler=
4959 cache_methods->get_one_authentic_pixel_from_handler;
4960}
4961
4962/*
4963%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4964% %
4965% %
4966% %
4967+ S e t P i x e l C a c h e N e x u s P i x e l s %
4968% %
4969% %
4970% %
4971%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4972%
4973% SetPixelCacheNexusPixels() defines the region of the cache for the
4974% specified cache nexus.
4975%
4976% The format of the SetPixelCacheNexusPixels() method is:
4977%
cristy4c08aed2011-07-01 19:47:50 +00004978% Quantum SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00004979% const RectangleInfo *region,NexusInfo *nexus_info,
4980% ExceptionInfo *exception)
4981%
4982% A description of each parameter follows:
4983%
4984% o image: the image.
4985%
4986% o region: A pointer to the RectangleInfo structure that defines the
4987% region of this particular cache nexus.
4988%
4989% o nexus_info: the cache nexus to set.
4990%
4991% o exception: return any errors or warnings in this structure.
4992%
4993*/
cristyabd6e372010-09-15 19:11:26 +00004994
4995static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4996 NexusInfo *nexus_info,ExceptionInfo *exception)
4997{
4998 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4999 return(MagickFalse);
5000 nexus_info->mapped=MagickFalse;
cristy5e044432011-07-16 03:35:35 +00005001 nexus_info->cache=(Quantum *) AcquireAlignedMemory(1,(size_t)
cristyabd6e372010-09-15 19:11:26 +00005002 nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00005003 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00005004 {
5005 nexus_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00005006 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristyabd6e372010-09-15 19:11:26 +00005007 nexus_info->length);
5008 }
cristy4c08aed2011-07-01 19:47:50 +00005009 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00005010 {
5011 (void) ThrowMagickException(exception,GetMagickModule(),
5012 ResourceLimitError,"MemoryAllocationFailed","`%s'",
5013 cache_info->filename);
5014 return(MagickFalse);
5015 }
5016 return(MagickTrue);
5017}
5018
cristy4c08aed2011-07-01 19:47:50 +00005019static Quantum *SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005020 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
5021{
5022 CacheInfo
5023 *cache_info;
5024
5025 MagickBooleanType
5026 status;
5027
cristy3ed852e2009-09-05 21:47:34 +00005028 MagickSizeType
5029 length,
5030 number_pixels;
5031
cristy3ed852e2009-09-05 21:47:34 +00005032 cache_info=(CacheInfo *) image->cache;
5033 assert(cache_info->signature == MagickSignature);
5034 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00005035 return((Quantum *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00005036 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00005037 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
5038 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00005039 {
cristybb503372010-05-27 20:51:26 +00005040 ssize_t
cristybad067a2010-02-15 17:20:55 +00005041 x,
5042 y;
cristy3ed852e2009-09-05 21:47:34 +00005043
cristyeaedf062010-05-29 22:36:02 +00005044 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
5045 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00005046 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5047 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00005048 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00005049 ((nexus_info->region.width == cache_info->columns) ||
5050 ((nexus_info->region.width % cache_info->columns) == 0)))))
5051 {
5052 MagickOffsetType
5053 offset;
5054
5055 /*
5056 Pixels are accessed directly from memory.
5057 */
5058 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5059 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005060 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005061 offset;
5062 nexus_info->metacontent=(void *) NULL;
5063 if (cache_info->metacontent_extent != 0)
5064 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
5065 offset*cache_info->metacontent_extent;
cristy731c3532010-02-15 15:40:03 +00005066 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00005067 }
5068 }
5069 /*
5070 Pixels are stored in a cache region until they are synced to the cache.
5071 */
5072 number_pixels=(MagickSizeType) nexus_info->region.width*
5073 nexus_info->region.height;
cristyed231572011-07-14 02:18:59 +00005074 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00005075 if (cache_info->metacontent_extent != 0)
5076 length+=number_pixels*cache_info->metacontent_extent;
5077 if (nexus_info->cache == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00005078 {
5079 nexus_info->length=length;
5080 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5081 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005082 {
5083 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00005084 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00005085 }
cristy3ed852e2009-09-05 21:47:34 +00005086 }
5087 else
5088 if (nexus_info->length != length)
5089 {
5090 RelinquishCacheNexusPixels(nexus_info);
5091 nexus_info->length=length;
5092 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5093 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005094 {
5095 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00005096 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00005097 }
cristy3ed852e2009-09-05 21:47:34 +00005098 }
5099 nexus_info->pixels=nexus_info->cache;
cristy4c08aed2011-07-01 19:47:50 +00005100 nexus_info->metacontent=(void *) NULL;
5101 if (cache_info->metacontent_extent != 0)
5102 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
cristyed231572011-07-14 02:18:59 +00005103 cache_info->number_channels);
cristy3ed852e2009-09-05 21:47:34 +00005104 return(nexus_info->pixels);
5105}
5106
5107/*
5108%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5109% %
5110% %
5111% %
5112% 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 %
5113% %
5114% %
5115% %
5116%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5117%
5118% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5119% pixel cache and returns the previous setting. A virtual pixel is any pixel
5120% access that is outside the boundaries of the image cache.
5121%
5122% The format of the SetPixelCacheVirtualMethod() method is:
5123%
5124% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5125% const VirtualPixelMethod virtual_pixel_method)
5126%
5127% A description of each parameter follows:
5128%
5129% o image: the image.
5130%
5131% o virtual_pixel_method: choose the type of virtual pixel.
5132%
5133*/
5134MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5135 const VirtualPixelMethod virtual_pixel_method)
5136{
5137 CacheInfo
5138 *cache_info;
5139
5140 VirtualPixelMethod
5141 method;
5142
5143 assert(image != (Image *) NULL);
5144 assert(image->signature == MagickSignature);
5145 if (image->debug != MagickFalse)
5146 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5147 assert(image->cache != (Cache) NULL);
5148 cache_info=(CacheInfo *) image->cache;
5149 assert(cache_info->signature == MagickSignature);
5150 method=cache_info->virtual_pixel_method;
5151 cache_info->virtual_pixel_method=virtual_pixel_method;
5152 return(method);
5153}
5154
5155/*
5156%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5157% %
5158% %
5159% %
5160+ 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 %
5161% %
5162% %
5163% %
5164%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5165%
5166% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5167% in-memory or disk cache. The method returns MagickTrue if the pixel region
5168% is synced, otherwise MagickFalse.
5169%
5170% The format of the SyncAuthenticPixelCacheNexus() method is:
5171%
5172% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5173% NexusInfo *nexus_info,ExceptionInfo *exception)
5174%
5175% A description of each parameter follows:
5176%
5177% o image: the image.
5178%
5179% o nexus_info: the cache nexus to sync.
5180%
5181% o exception: return any errors or warnings in this structure.
5182%
5183*/
5184MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5185 NexusInfo *nexus_info,ExceptionInfo *exception)
5186{
5187 CacheInfo
5188 *cache_info;
5189
5190 MagickBooleanType
5191 status;
5192
5193 /*
5194 Transfer pixels to the cache.
5195 */
5196 assert(image != (Image *) NULL);
5197 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005198 if (image->cache == (Cache) NULL)
5199 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5200 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005201 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005202 if (cache_info->type == UndefinedCache)
5203 return(MagickFalse);
5204 if ((image->clip_mask != (Image *) NULL) &&
5205 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5206 return(MagickFalse);
5207 if ((image->mask != (Image *) NULL) &&
5208 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5209 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005210 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005211 return(MagickTrue);
5212 assert(cache_info->signature == MagickSignature);
5213 status=WritePixelCachePixels(cache_info,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00005214 if ((cache_info->metacontent_extent != 0) &&
5215 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00005216 return(MagickFalse);
5217 return(status);
5218}
5219
5220/*
5221%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5222% %
5223% %
5224% %
5225+ S y n c A u t h e n t i c P i x e l C a c h e %
5226% %
5227% %
5228% %
5229%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5230%
5231% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5232% or disk cache. The method returns MagickTrue if the pixel region is synced,
5233% otherwise MagickFalse.
5234%
5235% The format of the SyncAuthenticPixelsCache() method is:
5236%
5237% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5238% ExceptionInfo *exception)
5239%
5240% A description of each parameter follows:
5241%
5242% o image: the image.
5243%
5244% o exception: return any errors or warnings in this structure.
5245%
5246*/
5247static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5248 ExceptionInfo *exception)
5249{
5250 CacheInfo
5251 *cache_info;
5252
cristy5c9e6f22010-09-17 17:31:01 +00005253 const int
5254 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005255
cristy4c08aed2011-07-01 19:47:50 +00005256 MagickBooleanType
5257 status;
5258
cristye7cc7cf2010-09-21 13:26:47 +00005259 assert(image != (Image *) NULL);
5260 assert(image->signature == MagickSignature);
5261 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005262 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005263 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005264 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005265 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5266 exception);
5267 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005268}
5269
5270/*
5271%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5272% %
5273% %
5274% %
5275% S y n c A u t h e n t i c P i x e l s %
5276% %
5277% %
5278% %
5279%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5280%
5281% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5282% The method returns MagickTrue if the pixel region is flushed, otherwise
5283% MagickFalse.
5284%
5285% The format of the SyncAuthenticPixels() method is:
5286%
5287% MagickBooleanType SyncAuthenticPixels(Image *image,
5288% ExceptionInfo *exception)
5289%
5290% A description of each parameter follows:
5291%
5292% o image: the image.
5293%
5294% o exception: return any errors or warnings in this structure.
5295%
5296*/
5297MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5298 ExceptionInfo *exception)
5299{
5300 CacheInfo
5301 *cache_info;
5302
cristy2036f5c2010-09-19 21:18:17 +00005303 const int
5304 id = GetOpenMPThreadId();
5305
cristy4c08aed2011-07-01 19:47:50 +00005306 MagickBooleanType
5307 status;
5308
cristy3ed852e2009-09-05 21:47:34 +00005309 assert(image != (Image *) NULL);
5310 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005311 assert(image->cache != (Cache) NULL);
5312 cache_info=(CacheInfo *) image->cache;
5313 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005314 if (cache_info->methods.sync_authentic_pixels_handler !=
5315 (SyncAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00005316 {
5317 status=cache_info->methods.sync_authentic_pixels_handler(image,
5318 exception);
5319 return(status);
5320 }
cristy2036f5c2010-09-19 21:18:17 +00005321 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005322 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5323 exception);
5324 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005325}
5326
5327/*
5328%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5329% %
5330% %
5331% %
cristy4c08aed2011-07-01 19:47:50 +00005332+ W r i t e P i x e l C a c h e M e t a c o n t e n t %
cristy3ed852e2009-09-05 21:47:34 +00005333% %
5334% %
5335% %
5336%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5337%
cristy4c08aed2011-07-01 19:47:50 +00005338% WritePixelCacheMetacontent() writes the meta-content to the specified region
5339% of the pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00005340%
cristy4c08aed2011-07-01 19:47:50 +00005341% The format of the WritePixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00005342%
cristy4c08aed2011-07-01 19:47:50 +00005343% MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005344% NexusInfo *nexus_info,ExceptionInfo *exception)
5345%
5346% A description of each parameter follows:
5347%
5348% o cache_info: the pixel cache.
5349%
cristy4c08aed2011-07-01 19:47:50 +00005350% o nexus_info: the cache nexus to write the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00005351%
5352% o exception: return any errors or warnings in this structure.
5353%
5354*/
cristy4c08aed2011-07-01 19:47:50 +00005355static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005356 NexusInfo *nexus_info,ExceptionInfo *exception)
5357{
5358 MagickOffsetType
5359 count,
5360 offset;
5361
5362 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005363 extent,
5364 length;
cristy3ed852e2009-09-05 21:47:34 +00005365
cristy4c08aed2011-07-01 19:47:50 +00005366 register const unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005367 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005368
cristybb503372010-05-27 20:51:26 +00005369 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005370 y;
5371
cristybb503372010-05-27 20:51:26 +00005372 size_t
cristy3ed852e2009-09-05 21:47:34 +00005373 rows;
5374
cristy4c08aed2011-07-01 19:47:50 +00005375 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00005376 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005377 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005378 return(MagickTrue);
5379 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5380 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00005381 length=(MagickSizeType) nexus_info->region.width*
5382 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005383 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005384 extent=(MagickSizeType) length*rows;
cristy4c08aed2011-07-01 19:47:50 +00005385 p=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00005386 switch (cache_info->type)
5387 {
5388 case MemoryCache:
5389 case MapCache:
5390 {
cristy4c08aed2011-07-01 19:47:50 +00005391 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005392 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005393
5394 /*
cristy4c08aed2011-07-01 19:47:50 +00005395 Write associated pixels to memory.
cristy3ed852e2009-09-05 21:47:34 +00005396 */
cristydd341db2010-03-04 19:06:38 +00005397 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005398 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005399 {
cristy48078b12010-09-23 17:11:01 +00005400 length=extent;
cristydd341db2010-03-04 19:06:38 +00005401 rows=1UL;
5402 }
cristy4c08aed2011-07-01 19:47:50 +00005403 q=(unsigned char *) cache_info->metacontent+offset*
5404 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00005405 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005406 {
cristy8f036fe2010-09-18 02:02:00 +00005407 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00005408 p+=nexus_info->region.width*cache_info->metacontent_extent;
5409 q+=cache_info->columns*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005410 }
5411 break;
5412 }
5413 case DiskCache:
5414 {
5415 /*
cristy4c08aed2011-07-01 19:47:50 +00005416 Write associated pixels to disk.
cristy3ed852e2009-09-05 21:47:34 +00005417 */
5418 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5419 {
5420 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5421 cache_info->cache_filename);
5422 return(MagickFalse);
5423 }
cristydd341db2010-03-04 19:06:38 +00005424 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005425 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005426 {
cristy48078b12010-09-23 17:11:01 +00005427 length=extent;
cristydd341db2010-03-04 19:06:38 +00005428 rows=1UL;
5429 }
cristy48078b12010-09-23 17:11:01 +00005430 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005431 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005432 {
cristy48078b12010-09-23 17:11:01 +00005433 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00005434 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00005435 cache_info->metacontent_extent,length,(const unsigned char *) p);
5436 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005437 break;
cristy4c08aed2011-07-01 19:47:50 +00005438 p+=nexus_info->region.width*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005439 offset+=cache_info->columns;
5440 }
cristybb503372010-05-27 20:51:26 +00005441 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005442 {
5443 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5444 cache_info->cache_filename);
5445 return(MagickFalse);
5446 }
5447 break;
5448 }
5449 default:
5450 break;
5451 }
5452 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005453 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005454 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005455 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005456 nexus_info->region.width,(double) nexus_info->region.height,(double)
5457 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005458 return(MagickTrue);
5459}
5460
5461/*
5462%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5463% %
5464% %
5465% %
5466+ W r i t e C a c h e P i x e l s %
5467% %
5468% %
5469% %
5470%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5471%
5472% WritePixelCachePixels() writes image pixels to the specified region of the
5473% pixel cache.
5474%
5475% The format of the WritePixelCachePixels() method is:
5476%
5477% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5478% NexusInfo *nexus_info,ExceptionInfo *exception)
5479%
5480% A description of each parameter follows:
5481%
5482% o cache_info: the pixel cache.
5483%
5484% o nexus_info: the cache nexus to write the pixels.
5485%
5486% o exception: return any errors or warnings in this structure.
5487%
5488*/
5489static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5490 NexusInfo *nexus_info,ExceptionInfo *exception)
5491{
5492 MagickOffsetType
5493 count,
5494 offset;
5495
5496 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005497 extent,
5498 length;
cristy3ed852e2009-09-05 21:47:34 +00005499
cristy4c08aed2011-07-01 19:47:50 +00005500 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00005501 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005502
cristybb503372010-05-27 20:51:26 +00005503 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005504 y;
5505
cristybb503372010-05-27 20:51:26 +00005506 size_t
cristy3ed852e2009-09-05 21:47:34 +00005507 rows;
5508
cristy4c08aed2011-07-01 19:47:50 +00005509 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005510 return(MagickTrue);
5511 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5512 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005513 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005514 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00005515 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005516 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005517 p=nexus_info->pixels;
5518 switch (cache_info->type)
5519 {
5520 case MemoryCache:
5521 case MapCache:
5522 {
cristy4c08aed2011-07-01 19:47:50 +00005523 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00005524 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005525
5526 /*
5527 Write pixels to memory.
5528 */
cristydd341db2010-03-04 19:06:38 +00005529 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005530 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005531 {
cristy48078b12010-09-23 17:11:01 +00005532 length=extent;
cristydd341db2010-03-04 19:06:38 +00005533 rows=1UL;
5534 }
cristyed231572011-07-14 02:18:59 +00005535 q=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00005536 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005537 {
cristy8f036fe2010-09-18 02:02:00 +00005538 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00005539 p+=nexus_info->region.width*cache_info->number_channels;
5540 q+=cache_info->columns*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005541 }
5542 break;
5543 }
5544 case DiskCache:
5545 {
5546 /*
5547 Write pixels to disk.
5548 */
5549 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5550 {
5551 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5552 cache_info->cache_filename);
5553 return(MagickFalse);
5554 }
cristydd341db2010-03-04 19:06:38 +00005555 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005556 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005557 {
cristy48078b12010-09-23 17:11:01 +00005558 length=extent;
cristydd341db2010-03-04 19:06:38 +00005559 rows=1UL;
5560 }
cristybb503372010-05-27 20:51:26 +00005561 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005562 {
5563 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00005564 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
cristy4c08aed2011-07-01 19:47:50 +00005565 p);
5566 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005567 break;
cristyed231572011-07-14 02:18:59 +00005568 p+=nexus_info->region.width*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005569 offset+=cache_info->columns;
5570 }
cristybb503372010-05-27 20:51:26 +00005571 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005572 {
5573 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5574 cache_info->cache_filename);
5575 return(MagickFalse);
5576 }
5577 break;
5578 }
5579 default:
5580 break;
5581 }
5582 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005583 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005584 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005585 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005586 nexus_info->region.width,(double) nexus_info->region.height,(double)
5587 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005588 return(MagickTrue);
5589}