blob: 8315ad1f441b4bd8da4aa28fe6ca560a99dbe251 [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
cristy73bd4a52010-10-05 11:24:23 +0000188 cache_info=(CacheInfo *) AcquireMagickMemory(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
cristyb41ee102010-10-04 16:46:15 +0000257 nexus_info=(NexusInfo **) AcquireQuantumMemory(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");
cristy4c08aed2011-07-01 19:47:50 +0000785 blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
786 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));
951 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
952 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);
1487 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
1488 }
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 */
3249 virtual_pixel=(Quantum *) AcquireQuantumMemory(
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 {
3262 virtual_associated_pixel=(void *) AcquireMagickMemory(
3263 cache_info->metacontent_extent);
3264 if (virtual_associated_pixel == (void *) NULL)
3265 {
3266 virtual_pixel=(Quantum *) RelinquishMagickMemory(
3267 virtual_pixel);
3268 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3269 (void) ThrowMagickException(exception,GetMagickModule(),
3270 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
3271 return((const Quantum *) NULL);
3272 }
3273 (void) ResetMagickMemory(virtual_associated_pixel,0,
3274 cache_info->metacontent_extent);
3275 }
3276 switch (virtual_pixel_method)
3277 {
3278 case BlackVirtualPixelMethod:
3279 {
3280 SetPixelRed(image,0,virtual_pixel);
3281 SetPixelGreen(image,0,virtual_pixel);
3282 SetPixelBlue(image,0,virtual_pixel);
3283 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3284 break;
3285 }
3286 case GrayVirtualPixelMethod:
3287 {
3288 SetPixelRed(image,QuantumRange/2,virtual_pixel);
3289 SetPixelGreen(image,QuantumRange/2,virtual_pixel);
3290 SetPixelBlue(image,QuantumRange/2,virtual_pixel);
3291 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3292 break;
3293 }
3294 case TransparentVirtualPixelMethod:
3295 {
3296 SetPixelRed(image,0,virtual_pixel);
3297 SetPixelGreen(image,0,virtual_pixel);
3298 SetPixelBlue(image,0,virtual_pixel);
3299 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3300 break;
3301 }
3302 case MaskVirtualPixelMethod:
3303 case WhiteVirtualPixelMethod:
3304 {
3305 SetPixelRed(image,(Quantum) QuantumRange,virtual_pixel);
3306 SetPixelGreen(image,(Quantum) QuantumRange,virtual_pixel);
3307 SetPixelBlue(image,(Quantum) QuantumRange,virtual_pixel);
3308 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3309 break;
3310 }
3311 default:
3312 {
3313 SetPixelRed(image,image->background_color.red,virtual_pixel);
3314 SetPixelGreen(image,image->background_color.green,virtual_pixel);
3315 SetPixelBlue(image,image->background_color.blue,virtual_pixel);
3316 SetPixelAlpha(image,image->background_color.alpha,virtual_pixel);
3317 break;
3318 }
3319 }
cristy3ed852e2009-09-05 21:47:34 +00003320 break;
3321 }
3322 default:
cristy3ed852e2009-09-05 21:47:34 +00003323 break;
cristy3ed852e2009-09-05 21:47:34 +00003324 }
cristybb503372010-05-27 20:51:26 +00003325 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003326 {
cristybb503372010-05-27 20:51:26 +00003327 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003328 {
3329 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003330 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003331 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3332 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003333 {
3334 MagickModulo
3335 x_modulo,
3336 y_modulo;
3337
3338 /*
3339 Transfer a single pixel.
3340 */
3341 length=(MagickSizeType) 1;
3342 switch (virtual_pixel_method)
3343 {
cristy3ed852e2009-09-05 21:47:34 +00003344 default:
3345 {
3346 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003347 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003348 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003349 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003350 break;
3351 }
3352 case RandomVirtualPixelMethod:
3353 {
3354 if (cache_info->random_info == (RandomInfo *) NULL)
3355 cache_info->random_info=AcquireRandomInfo();
3356 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003357 RandomX(cache_info->random_info,cache_info->columns),
3358 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003359 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003360 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003361 break;
3362 }
3363 case DitherVirtualPixelMethod:
3364 {
3365 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003366 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy0a36c742010-10-03 02:10:53 +00003367 1UL,1UL,*virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003368 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003369 break;
3370 }
3371 case TileVirtualPixelMethod:
3372 {
3373 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3374 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3375 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003376 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003377 exception);
cristy4c08aed2011-07-01 19:47:50 +00003378 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003379 break;
3380 }
3381 case MirrorVirtualPixelMethod:
3382 {
3383 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3384 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003385 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003386 x_modulo.remainder-1L;
3387 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3388 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003389 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003390 y_modulo.remainder-1L;
3391 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy0a36c742010-10-03 02:10:53 +00003392 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
cristy3ed852e2009-09-05 21:47:34 +00003393 exception);
cristy4c08aed2011-07-01 19:47:50 +00003394 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003395 break;
3396 }
3397 case HorizontalTileEdgeVirtualPixelMethod:
3398 {
3399 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3400 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003401 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003402 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003403 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003404 break;
3405 }
3406 case VerticalTileEdgeVirtualPixelMethod:
3407 {
3408 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3409 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003410 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy0a36c742010-10-03 02:10:53 +00003411 *virtual_nexus,exception);
cristy4c08aed2011-07-01 19:47:50 +00003412 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3413 break;
3414 }
3415 case BackgroundVirtualPixelMethod:
3416 case BlackVirtualPixelMethod:
3417 case GrayVirtualPixelMethod:
3418 case TransparentVirtualPixelMethod:
3419 case MaskVirtualPixelMethod:
3420 case WhiteVirtualPixelMethod:
3421 {
3422 p=virtual_pixel;
3423 r=virtual_associated_pixel;
3424 break;
3425 }
3426 case EdgeVirtualPixelMethod:
3427 case CheckerTileVirtualPixelMethod:
3428 {
3429 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3430 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3431 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3432 {
3433 p=virtual_pixel;
3434 r=virtual_associated_pixel;
3435 break;
3436 }
3437 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3438 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3439 exception);
3440 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3441 break;
3442 }
3443 case HorizontalTileVirtualPixelMethod:
3444 {
3445 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3446 {
3447 p=virtual_pixel;
3448 r=virtual_associated_pixel;
3449 break;
3450 }
3451 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3452 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3453 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3454 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3455 exception);
3456 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3457 break;
3458 }
3459 case VerticalTileVirtualPixelMethod:
3460 {
3461 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3462 {
3463 p=virtual_pixel;
3464 r=virtual_associated_pixel;
3465 break;
3466 }
3467 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3468 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3469 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3470 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3471 exception);
3472 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristy3ed852e2009-09-05 21:47:34 +00003473 break;
3474 }
3475 }
cristy4c08aed2011-07-01 19:47:50 +00003476 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003477 break;
cristyed231572011-07-14 02:18:59 +00003478 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00003479 sizeof(*p));
cristyed231572011-07-14 02:18:59 +00003480 q+=cache_info->number_channels;
cristy4c08aed2011-07-01 19:47:50 +00003481 if ((s != (void *) NULL) &&
3482 (r != (const void *) NULL))
3483 {
3484 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3485 s+=cache_info->metacontent_extent;
3486 }
cristy3ed852e2009-09-05 21:47:34 +00003487 continue;
3488 }
3489 /*
3490 Transfer a run of pixels.
3491 */
cristy4c08aed2011-07-01 19:47:50 +00003492 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3493 length,1UL,*virtual_nexus,exception);
3494 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003495 break;
cristy4c08aed2011-07-01 19:47:50 +00003496 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
cristyed231572011-07-14 02:18:59 +00003497 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3498 q+=length*cache_info->number_channels;
cristy4c08aed2011-07-01 19:47:50 +00003499 if ((s != (void *) NULL) && (r != (const void *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003500 {
cristy4c08aed2011-07-01 19:47:50 +00003501 (void) memcpy(s,r,(size_t) length);
3502 s+=length*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00003503 }
3504 }
3505 }
cristy4c08aed2011-07-01 19:47:50 +00003506 /*
3507 Free resources.
3508 */
3509 if (virtual_associated_pixel != (void *) NULL)
3510 virtual_associated_pixel=(void *) RelinquishMagickMemory(
3511 virtual_associated_pixel);
3512 if (virtual_pixel != (Quantum *) NULL)
3513 virtual_pixel=(Quantum *) RelinquishMagickMemory(virtual_pixel);
cristy3ed852e2009-09-05 21:47:34 +00003514 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3515 return(pixels);
3516}
3517
3518/*
3519%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3520% %
3521% %
3522% %
3523+ G e t V i r t u a l P i x e l C a c h e %
3524% %
3525% %
3526% %
3527%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3528%
3529% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3530% cache as defined by the geometry parameters. A pointer to the pixels
3531% is returned if the pixels are transferred, otherwise a NULL is returned.
3532%
3533% The format of the GetVirtualPixelCache() method is:
3534%
cristy4c08aed2011-07-01 19:47:50 +00003535% const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003536% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3537% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003538% ExceptionInfo *exception)
3539%
3540% A description of each parameter follows:
3541%
3542% o image: the image.
3543%
3544% o virtual_pixel_method: the virtual pixel method.
3545%
3546% o x,y,columns,rows: These values define the perimeter of a region of
3547% pixels.
3548%
3549% o exception: return any errors or warnings in this structure.
3550%
3551*/
cristy4c08aed2011-07-01 19:47:50 +00003552static const Quantum *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003553 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3554 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003555{
3556 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003557 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003558
cristy5c9e6f22010-09-17 17:31:01 +00003559 const int
3560 id = GetOpenMPThreadId();
3561
cristy4c08aed2011-07-01 19:47:50 +00003562 const Quantum
3563 *pixels;
3564
cristye7cc7cf2010-09-21 13:26:47 +00003565 assert(image != (const Image *) NULL);
3566 assert(image->signature == MagickSignature);
3567 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003568 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003569 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003570 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00003571 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3572 cache_info->nexus_info[id],exception);
3573 return(pixels);
cristy3ed852e2009-09-05 21:47:34 +00003574}
3575
3576/*
3577%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3578% %
3579% %
3580% %
3581% G e t V i r t u a l P i x e l Q u e u e %
3582% %
3583% %
3584% %
3585%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3586%
cristy4c08aed2011-07-01 19:47:50 +00003587% GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3588% with the last call to QueueAuthenticPixels() or GetVirtualPixels().
cristy3ed852e2009-09-05 21:47:34 +00003589%
3590% The format of the GetVirtualPixelQueue() method is:
3591%
cristy4c08aed2011-07-01 19:47:50 +00003592% const Quantum *GetVirtualPixelQueue(const Image image)
cristy3ed852e2009-09-05 21:47:34 +00003593%
3594% A description of each parameter follows:
3595%
3596% o image: the image.
3597%
3598*/
cristy4c08aed2011-07-01 19:47:50 +00003599MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003600{
3601 CacheInfo
3602 *cache_info;
3603
cristy2036f5c2010-09-19 21:18:17 +00003604 const int
3605 id = GetOpenMPThreadId();
3606
cristy3ed852e2009-09-05 21:47:34 +00003607 assert(image != (const Image *) NULL);
3608 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003609 assert(image->cache != (Cache) NULL);
3610 cache_info=(CacheInfo *) image->cache;
3611 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003612 if (cache_info->methods.get_virtual_pixels_handler !=
3613 (GetVirtualPixelsHandler) NULL)
3614 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003615 assert(id < (int) cache_info->number_threads);
3616 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003617}
3618
3619/*
3620%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3621% %
3622% %
3623% %
3624% G e t V i r t u a l P i x e l s %
3625% %
3626% %
3627% %
3628%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3629%
3630% GetVirtualPixels() returns an immutable pixel region. If the
3631% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003632% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003633% copy of the pixels or it may point to the original pixels in memory.
3634% Performance is maximized if the selected region is part of one row, or one
3635% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003636% (without a copy) if the image is in memory, or in a memory-mapped file. The
3637% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003638%
3639% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00003640% Quantum. If the image type is CMYK or the storage class is PseudoClass,
3641% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3642% access the meta-content (of type void) corresponding to the the
3643% region.
cristy3ed852e2009-09-05 21:47:34 +00003644%
3645% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3646%
3647% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3648% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3649% GetCacheViewAuthenticPixels() instead.
3650%
3651% The format of the GetVirtualPixels() method is:
3652%
cristy4c08aed2011-07-01 19:47:50 +00003653% const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00003654% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003655% ExceptionInfo *exception)
3656%
3657% A description of each parameter follows:
3658%
3659% o image: the image.
3660%
3661% o x,y,columns,rows: These values define the perimeter of a region of
3662% pixels.
3663%
3664% o exception: return any errors or warnings in this structure.
3665%
3666*/
cristy4c08aed2011-07-01 19:47:50 +00003667MagickExport const Quantum *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003668 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3669 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003670{
3671 CacheInfo
3672 *cache_info;
3673
cristy2036f5c2010-09-19 21:18:17 +00003674 const int
3675 id = GetOpenMPThreadId();
3676
cristy4c08aed2011-07-01 19:47:50 +00003677 const Quantum
3678 *pixels;
3679
cristy3ed852e2009-09-05 21:47:34 +00003680 assert(image != (const Image *) NULL);
3681 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003682 assert(image->cache != (Cache) NULL);
3683 cache_info=(CacheInfo *) image->cache;
3684 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003685 if (cache_info->methods.get_virtual_pixel_handler !=
3686 (GetVirtualPixelHandler) NULL)
3687 return(cache_info->methods.get_virtual_pixel_handler(image,
3688 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003689 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00003690 pixels=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3691 columns,rows,cache_info->nexus_info[id],exception);
3692 return(pixels);
cristy3ed852e2009-09-05 21:47:34 +00003693}
3694
3695/*
3696%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3697% %
3698% %
3699% %
3700+ 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 %
3701% %
3702% %
3703% %
3704%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3705%
cristy4c08aed2011-07-01 19:47:50 +00003706% GetVirtualPixelsCache() returns the pixels associated corresponding with the
3707% last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
cristy3ed852e2009-09-05 21:47:34 +00003708%
3709% The format of the GetVirtualPixelsCache() method is:
3710%
cristy4c08aed2011-07-01 19:47:50 +00003711% Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003712%
3713% A description of each parameter follows:
3714%
3715% o image: the image.
3716%
3717*/
cristy4c08aed2011-07-01 19:47:50 +00003718static const Quantum *GetVirtualPixelsCache(const Image *image)
cristy3ed852e2009-09-05 21:47:34 +00003719{
3720 CacheInfo
3721 *cache_info;
3722
cristy5c9e6f22010-09-17 17:31:01 +00003723 const int
3724 id = GetOpenMPThreadId();
3725
cristye7cc7cf2010-09-21 13:26:47 +00003726 assert(image != (const Image *) NULL);
3727 assert(image->signature == MagickSignature);
3728 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003729 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00003730 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00003731 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003732 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003733}
3734
3735/*
3736%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3737% %
3738% %
3739% %
3740+ G e t V i r t u a l P i x e l s N e x u s %
3741% %
3742% %
3743% %
3744%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3745%
3746% GetVirtualPixelsNexus() returns the pixels associated with the specified
3747% cache nexus.
3748%
3749% The format of the GetVirtualPixelsNexus() method is:
3750%
cristy4c08aed2011-07-01 19:47:50 +00003751% const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003752% NexusInfo *nexus_info)
3753%
3754% A description of each parameter follows:
3755%
3756% o cache: the pixel cache.
3757%
3758% o nexus_info: the cache nexus to return the colormap pixels.
3759%
3760*/
cristy4c08aed2011-07-01 19:47:50 +00003761MagickExport const Quantum *GetVirtualPixelsNexus(const Cache cache,
cristy3ed852e2009-09-05 21:47:34 +00003762 NexusInfo *nexus_info)
3763{
3764 CacheInfo
3765 *cache_info;
3766
cristye7cc7cf2010-09-21 13:26:47 +00003767 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00003768 cache_info=(CacheInfo *) cache;
3769 assert(cache_info->signature == MagickSignature);
3770 if (cache_info->storage_class == UndefinedClass)
cristy4c08aed2011-07-01 19:47:50 +00003771 return((Quantum *) NULL);
3772 return((const Quantum *) nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00003773}
3774
3775/*
3776%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3777% %
3778% %
3779% %
3780+ M a s k P i x e l C a c h e N e x u s %
3781% %
3782% %
3783% %
3784%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3785%
3786% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3787% The method returns MagickTrue if the pixel region is masked, otherwise
3788% MagickFalse.
3789%
3790% The format of the MaskPixelCacheNexus() method is:
3791%
3792% MagickBooleanType MaskPixelCacheNexus(Image *image,
3793% NexusInfo *nexus_info,ExceptionInfo *exception)
3794%
3795% A description of each parameter follows:
3796%
3797% o image: the image.
3798%
3799% o nexus_info: the cache nexus to clip.
3800%
3801% o exception: return any errors or warnings in this structure.
3802%
3803*/
3804
cristy4c08aed2011-07-01 19:47:50 +00003805static inline void MagickPixelCompositeMask(const PixelInfo *p,
3806 const MagickRealType alpha,const PixelInfo *q,
3807 const MagickRealType beta,PixelInfo *composite)
cristy3ed852e2009-09-05 21:47:34 +00003808{
3809 MagickRealType
3810 gamma;
3811
cristy4c08aed2011-07-01 19:47:50 +00003812 if (alpha == TransparentAlpha)
cristy3ed852e2009-09-05 21:47:34 +00003813 {
3814 *composite=(*q);
3815 return;
3816 }
3817 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3818 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
cristyb40bd892011-04-23 00:52:38 +00003819 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3820 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3821 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
cristy3ed852e2009-09-05 21:47:34 +00003822 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
cristy4c08aed2011-07-01 19:47:50 +00003823 composite->black=gamma*MagickOver_(p->black,alpha,q->black,beta);
cristy3ed852e2009-09-05 21:47:34 +00003824}
3825
3826static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3827 ExceptionInfo *exception)
3828{
3829 CacheInfo
3830 *cache_info;
3831
cristy4c08aed2011-07-01 19:47:50 +00003832 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00003833 alpha,
3834 beta;
3835
3836 MagickSizeType
3837 number_pixels;
3838
3839 NexusInfo
3840 **clip_nexus,
3841 **image_nexus;
3842
cristy4c08aed2011-07-01 19:47:50 +00003843 register const Quantum
3844 *restrict p,
cristyc47d1f82009-11-26 01:44:43 +00003845 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003846
cristy4c08aed2011-07-01 19:47:50 +00003847 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00003848 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003849
cristye076a6e2010-08-15 19:59:43 +00003850 register ssize_t
3851 i;
3852
cristy3ed852e2009-09-05 21:47:34 +00003853 /*
3854 Apply clip mask.
3855 */
3856 if (image->debug != MagickFalse)
3857 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3858 if (image->mask == (Image *) NULL)
3859 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +00003860 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00003861 if (cache_info == (Cache) NULL)
3862 return(MagickFalse);
3863 image_nexus=AcquirePixelCacheNexus(1);
3864 clip_nexus=AcquirePixelCacheNexus(1);
3865 if ((image_nexus == (NexusInfo **) NULL) ||
3866 (clip_nexus == (NexusInfo **) NULL))
3867 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00003868 p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
3869 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3870 nexus_info->region.height,image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003871 q=nexus_info->pixels;
cristy3ed852e2009-09-05 21:47:34 +00003872 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3873 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3874 nexus_info->region.height,clip_nexus[0],&image->exception);
cristy4c08aed2011-07-01 19:47:50 +00003875 GetPixelInfo(image,&alpha);
3876 GetPixelInfo(image,&beta);
cristy3ed852e2009-09-05 21:47:34 +00003877 number_pixels=(MagickSizeType) nexus_info->region.width*
3878 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +00003879 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +00003880 {
cristy4c08aed2011-07-01 19:47:50 +00003881 if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003882 break;
cristy4c08aed2011-07-01 19:47:50 +00003883 SetPixelInfo(image,p,&alpha);
3884 SetPixelInfo(image,q,&beta);
3885 MagickPixelCompositeMask(&beta,(MagickRealType) GetPixelIntensity(image,r),
3886 &alpha,alpha.alpha,&beta);
3887 SetPixelRed(image,ClampToQuantum(beta.red),q);
3888 SetPixelGreen(image,ClampToQuantum(beta.green),q);
3889 SetPixelBlue(image,ClampToQuantum(beta.blue),q);
3890 if (cache_info->colorspace == CMYKColorspace)
3891 SetPixelBlack(image,ClampToQuantum(beta.black),q);
3892 SetPixelAlpha(image,ClampToQuantum(beta.alpha),q);
cristy3ed852e2009-09-05 21:47:34 +00003893 p++;
3894 q++;
3895 r++;
3896 }
3897 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3898 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +00003899 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003900 return(MagickFalse);
3901 return(MagickTrue);
3902}
3903
3904/*
3905%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3906% %
3907% %
3908% %
3909+ O p e n P i x e l C a c h e %
3910% %
3911% %
3912% %
3913%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3914%
3915% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3916% dimensions, allocating space for the image pixels and optionally the
cristy4c08aed2011-07-01 19:47:50 +00003917% metacontent, and memory mapping the cache if it is disk based. The cache
3918% nexus array is initialized as well.
cristy3ed852e2009-09-05 21:47:34 +00003919%
3920% The format of the OpenPixelCache() method is:
3921%
3922% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3923% ExceptionInfo *exception)
3924%
3925% A description of each parameter follows:
3926%
3927% o image: the image.
3928%
3929% o mode: ReadMode, WriteMode, or IOMode.
3930%
3931% o exception: return any errors or warnings in this structure.
3932%
3933*/
3934
cristyd43a46b2010-01-21 02:13:41 +00003935static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003936{
3937 cache_info->mapped=MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00003938 cache_info->pixels=(Quantum *) AcquireMagickMemory((size_t)
cristy3ed852e2009-09-05 21:47:34 +00003939 cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00003940 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003941 {
3942 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00003943 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristy3ed852e2009-09-05 21:47:34 +00003944 cache_info->length);
3945 }
3946}
3947
3948static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3949{
3950 CacheInfo
3951 *cache_info;
3952
3953 MagickOffsetType
3954 count,
3955 extent,
3956 offset;
3957
3958 cache_info=(CacheInfo *) image->cache;
3959 if (image->debug != MagickFalse)
3960 {
3961 char
3962 format[MaxTextExtent],
3963 message[MaxTextExtent];
3964
cristyb9080c92009-12-01 20:13:26 +00003965 (void) FormatMagickSize(length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00003966 (void) FormatLocaleString(message,MaxTextExtent,
cristyb37d4f22011-06-27 19:22:42 +00003967 "extend %s (%s[%d], disk, %s)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003968 cache_info->cache_filename,cache_info->file,format);
3969 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3970 }
3971 if (length != (MagickSizeType) ((MagickOffsetType) length))
3972 return(MagickFalse);
cristy7f317702011-02-18 20:40:28 +00003973 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
cristy3ed852e2009-09-05 21:47:34 +00003974 if (extent < 0)
3975 return(MagickFalse);
3976 if ((MagickSizeType) extent >= length)
3977 return(MagickTrue);
3978 offset=(MagickOffsetType) length-1;
3979 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3980 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3981}
3982
3983static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3984 ExceptionInfo *exception)
3985{
cristy3ed852e2009-09-05 21:47:34 +00003986 CacheInfo
3987 *cache_info,
3988 source_info;
3989
cristyf3a6a9d2010-11-07 21:02:56 +00003990 char
3991 format[MaxTextExtent],
3992 message[MaxTextExtent];
3993
cristy4c08aed2011-07-01 19:47:50 +00003994 MagickBooleanType
3995 status;
3996
cristy3ed852e2009-09-05 21:47:34 +00003997 MagickSizeType
3998 length,
3999 number_pixels;
4000
cristy3ed852e2009-09-05 21:47:34 +00004001 size_t
cristye076a6e2010-08-15 19:59:43 +00004002 columns,
cristy3ed852e2009-09-05 21:47:34 +00004003 packet_size;
4004
cristye7cc7cf2010-09-21 13:26:47 +00004005 assert(image != (const Image *) NULL);
4006 assert(image->signature == MagickSignature);
4007 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004008 if (image->debug != MagickFalse)
4009 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4010 if ((image->columns == 0) || (image->rows == 0))
4011 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
cristyed231572011-07-14 02:18:59 +00004012 StandardPixelChannelMap(image);
cristy3ed852e2009-09-05 21:47:34 +00004013 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004014 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004015 source_info=(*cache_info);
4016 source_info.file=(-1);
cristyb51dff52011-05-19 16:55:47 +00004017 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
cristye8c25f92010-06-03 00:53:06 +00004018 image->filename,(double) GetImageIndexInList(image));
cristy4c08aed2011-07-01 19:47:50 +00004019 cache_info->storage_class=image->storage_class;
4020 cache_info->colorspace=image->colorspace;
cristy87528ea2009-09-10 14:53:56 +00004021 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +00004022 cache_info->rows=image->rows;
4023 cache_info->columns=image->columns;
cristyed231572011-07-14 02:18:59 +00004024 cache_info->number_channels=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +00004025 cache_info->metacontent_extent=image->metacontent_extent;
cristy73724512010-04-12 14:43:14 +00004026 if (image->ping != MagickFalse)
4027 {
cristy73724512010-04-12 14:43:14 +00004028 cache_info->type=PingCache;
cristy4c08aed2011-07-01 19:47:50 +00004029 cache_info->pixels=(Quantum *) NULL;
4030 cache_info->metacontent=(void *) NULL;
cristy73724512010-04-12 14:43:14 +00004031 cache_info->length=0;
4032 return(MagickTrue);
4033 }
cristy3ed852e2009-09-05 21:47:34 +00004034 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristyed231572011-07-14 02:18:59 +00004035 packet_size=cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00004036 if (image->metacontent_extent != 0)
4037 packet_size+=cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004038 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00004039 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00004040 if (cache_info->columns != columns)
4041 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4042 image->filename);
4043 cache_info->length=length;
cristy4c08aed2011-07-01 19:47:50 +00004044 if ((cache_info->type != UndefinedCache) &&
4045 (cache_info->columns <= source_info.columns) &&
4046 (cache_info->rows <= source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00004047 (cache_info->number_channels <= source_info.number_channels) &&
cristy4c08aed2011-07-01 19:47:50 +00004048 (cache_info->metacontent_extent <= source_info.metacontent_extent))
4049 {
4050 /*
4051 Inline pixel cache clone optimization.
4052 */
4053 if ((cache_info->columns == source_info.columns) &&
4054 (cache_info->rows == source_info.rows) &&
cristyed231572011-07-14 02:18:59 +00004055 (cache_info->number_channels == source_info.number_channels) &&
cristy4c08aed2011-07-01 19:47:50 +00004056 (cache_info->metacontent_extent == source_info.metacontent_extent))
4057 return(MagickTrue);
4058 return(ClonePixelCachePixels(cache_info,&source_info,exception));
4059 }
cristy3ed852e2009-09-05 21:47:34 +00004060 status=AcquireMagickResource(AreaResource,cache_info->length);
cristyed231572011-07-14 02:18:59 +00004061 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00004062 cache_info->metacontent_extent);
cristy3ed852e2009-09-05 21:47:34 +00004063 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4064 {
4065 status=AcquireMagickResource(MemoryResource,cache_info->length);
4066 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4067 (cache_info->type == MemoryCache))
4068 {
cristyd43a46b2010-01-21 02:13:41 +00004069 AllocatePixelCachePixels(cache_info);
cristy4c08aed2011-07-01 19:47:50 +00004070 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004071 cache_info->pixels=source_info.pixels;
4072 else
4073 {
4074 /*
4075 Create memory pixel cache.
4076 */
cristy4c08aed2011-07-01 19:47:50 +00004077 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004078 if (image->debug != MagickFalse)
4079 {
cristy97e7a572009-12-05 15:07:53 +00004080 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004081 format);
cristyb51dff52011-05-19 16:55:47 +00004082 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004083 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
4084 cache_info->filename,cache_info->mapped != MagickFalse ?
4085 "anonymous" : "heap",(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00004086 cache_info->rows,(double) cache_info->number_channels,
cristye8c25f92010-06-03 00:53:06 +00004087 format);
cristy3ed852e2009-09-05 21:47:34 +00004088 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4089 message);
4090 }
cristy3ed852e2009-09-05 21:47:34 +00004091 cache_info->type=MemoryCache;
cristy4c08aed2011-07-01 19:47:50 +00004092 cache_info->metacontent=(void *) NULL;
4093 if (cache_info->metacontent_extent != 0)
4094 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00004095 number_pixels*cache_info->number_channels);
cristy3ed852e2009-09-05 21:47:34 +00004096 if (source_info.storage_class != UndefinedClass)
4097 {
cristy4c08aed2011-07-01 19:47:50 +00004098 status=ClonePixelCachePixels(cache_info,&source_info,
cristy3ed852e2009-09-05 21:47:34 +00004099 exception);
4100 RelinquishPixelCachePixels(&source_info);
4101 }
cristy4c08aed2011-07-01 19:47:50 +00004102 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004103 }
4104 }
4105 RelinquishMagickResource(MemoryResource,cache_info->length);
4106 }
4107 /*
4108 Create pixel cache on disk.
4109 */
4110 status=AcquireMagickResource(DiskResource,cache_info->length);
4111 if (status == MagickFalse)
4112 {
4113 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4114 "CacheResourcesExhausted","`%s'",image->filename);
4115 return(MagickFalse);
4116 }
4117 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4118 {
4119 RelinquishMagickResource(DiskResource,cache_info->length);
4120 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4121 image->filename);
4122 return(MagickFalse);
4123 }
4124 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4125 cache_info->length);
4126 if (status == MagickFalse)
4127 {
4128 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4129 image->filename);
4130 return(MagickFalse);
4131 }
cristyed231572011-07-14 02:18:59 +00004132 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
cristy4c08aed2011-07-01 19:47:50 +00004133 cache_info->metacontent_extent);
cristy3ed852e2009-09-05 21:47:34 +00004134 status=AcquireMagickResource(AreaResource,cache_info->length);
4135 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4136 cache_info->type=DiskCache;
4137 else
4138 {
4139 status=AcquireMagickResource(MapResource,cache_info->length);
4140 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4141 (cache_info->type != MemoryCache))
4142 cache_info->type=DiskCache;
4143 else
4144 {
cristy4c08aed2011-07-01 19:47:50 +00004145 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
cristy3ed852e2009-09-05 21:47:34 +00004146 cache_info->offset,(size_t) cache_info->length);
cristy4c08aed2011-07-01 19:47:50 +00004147 if (cache_info->pixels == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004148 {
cristy3ed852e2009-09-05 21:47:34 +00004149 cache_info->type=DiskCache;
cristy4c08aed2011-07-01 19:47:50 +00004150 cache_info->pixels=source_info.pixels;
cristy3ed852e2009-09-05 21:47:34 +00004151 }
4152 else
4153 {
4154 /*
4155 Create file-backed memory-mapped pixel cache.
4156 */
cristy4c08aed2011-07-01 19:47:50 +00004157 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004158 (void) ClosePixelCacheOnDisk(cache_info);
4159 cache_info->type=MapCache;
4160 cache_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00004161 cache_info->metacontent=(void *) NULL;
4162 if (cache_info->metacontent_extent != 0)
4163 cache_info->metacontent=(void *) (cache_info->pixels+
cristyed231572011-07-14 02:18:59 +00004164 number_pixels*cache_info->number_channels);
cristy4c08aed2011-07-01 19:47:50 +00004165 if (source_info.storage_class != UndefinedClass)
cristy3ed852e2009-09-05 21:47:34 +00004166 {
4167 status=ClonePixelCachePixels(cache_info,&source_info,
4168 exception);
4169 RelinquishPixelCachePixels(&source_info);
4170 }
4171 if (image->debug != MagickFalse)
4172 {
cristy97e7a572009-12-05 15:07:53 +00004173 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004174 format);
cristyb51dff52011-05-19 16:55:47 +00004175 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004176 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
cristy3ed852e2009-09-05 21:47:34 +00004177 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004178 cache_info->file,(double) cache_info->columns,(double)
cristyed231572011-07-14 02:18:59 +00004179 cache_info->rows,(double) cache_info->number_channels,
cristy4c08aed2011-07-01 19:47:50 +00004180 format);
cristy3ed852e2009-09-05 21:47:34 +00004181 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4182 message);
4183 }
cristy4c08aed2011-07-01 19:47:50 +00004184 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004185 }
4186 }
4187 RelinquishMagickResource(MapResource,cache_info->length);
4188 }
cristy4c08aed2011-07-01 19:47:50 +00004189 status=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00004190 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4191 {
4192 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4193 RelinquishPixelCachePixels(&source_info);
4194 }
4195 if (image->debug != MagickFalse)
4196 {
cristyb9080c92009-12-01 20:13:26 +00004197 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristyb51dff52011-05-19 16:55:47 +00004198 (void) FormatLocaleString(message,MaxTextExtent,
cristy4c08aed2011-07-01 19:47:50 +00004199 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
cristye8c25f92010-06-03 00:53:06 +00004200 cache_info->cache_filename,cache_info->file,(double)
cristy4c08aed2011-07-01 19:47:50 +00004201 cache_info->columns,(double) cache_info->rows,(double)
cristyed231572011-07-14 02:18:59 +00004202 cache_info->number_channels,format);
cristy3ed852e2009-09-05 21:47:34 +00004203 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4204 }
cristy4c08aed2011-07-01 19:47:50 +00004205 return(status);
cristy3ed852e2009-09-05 21:47:34 +00004206}
4207
4208/*
4209%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4210% %
4211% %
4212% %
4213+ P e r s i s t P i x e l C a c h e %
4214% %
4215% %
4216% %
4217%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4218%
4219% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4220% persistent pixel cache is one that resides on disk and is not destroyed
4221% when the program exits.
4222%
4223% The format of the PersistPixelCache() method is:
4224%
4225% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4226% const MagickBooleanType attach,MagickOffsetType *offset,
4227% ExceptionInfo *exception)
4228%
4229% A description of each parameter follows:
4230%
4231% o image: the image.
4232%
4233% o filename: the persistent pixel cache filename.
4234%
cristyf3a6a9d2010-11-07 21:02:56 +00004235% o attach: A value other than zero initializes the persistent pixel cache.
cristy01b7eb02009-09-10 23:10:14 +00004236%
cristy3ed852e2009-09-05 21:47:34 +00004237% o initialize: A value other than zero initializes the persistent pixel
4238% cache.
4239%
4240% o offset: the offset in the persistent cache to store pixels.
4241%
4242% o exception: return any errors or warnings in this structure.
4243%
4244*/
4245MagickExport MagickBooleanType PersistPixelCache(Image *image,
4246 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4247 ExceptionInfo *exception)
4248{
4249 CacheInfo
4250 *cache_info,
4251 *clone_info;
4252
4253 Image
4254 clone_image;
4255
cristy3ed852e2009-09-05 21:47:34 +00004256 MagickBooleanType
4257 status;
4258
cristye076a6e2010-08-15 19:59:43 +00004259 ssize_t
4260 page_size;
4261
cristy3ed852e2009-09-05 21:47:34 +00004262 assert(image != (Image *) NULL);
4263 assert(image->signature == MagickSignature);
4264 if (image->debug != MagickFalse)
4265 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4266 assert(image->cache != (void *) NULL);
4267 assert(filename != (const char *) NULL);
4268 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004269 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004270 cache_info=(CacheInfo *) image->cache;
4271 assert(cache_info->signature == MagickSignature);
4272 if (attach != MagickFalse)
4273 {
4274 /*
cristy01b7eb02009-09-10 23:10:14 +00004275 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004276 */
4277 if (image->debug != MagickFalse)
4278 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristye7cc7cf2010-09-21 13:26:47 +00004279 "attach persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004280 (void) CopyMagickString(cache_info->cache_filename,filename,
4281 MaxTextExtent);
4282 cache_info->type=DiskCache;
4283 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004284 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004285 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004286 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy83967712010-09-20 23:35:28 +00004287 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00004288 }
cristy01b7eb02009-09-10 23:10:14 +00004289 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4290 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004291 {
cristyf84a1932010-01-03 18:00:18 +00004292 LockSemaphoreInfo(cache_info->semaphore);
cristy09449f72010-01-23 03:08:36 +00004293 if ((cache_info->mode != ReadMode) &&
4294 (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004295 (cache_info->reference_count == 1))
4296 {
4297 int
4298 status;
4299
4300 /*
cristy01b7eb02009-09-10 23:10:14 +00004301 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004302 */
4303 status=rename(cache_info->cache_filename,filename);
4304 if (status == 0)
4305 {
4306 (void) CopyMagickString(cache_info->cache_filename,filename,
4307 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004308 *offset+=cache_info->length+page_size-(cache_info->length %
4309 page_size);
cristyf84a1932010-01-03 18:00:18 +00004310 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004311 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristye7cc7cf2010-09-21 13:26:47 +00004312 if (image->debug != MagickFalse)
4313 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4314 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004315 return(MagickTrue);
4316 }
4317 }
cristyf84a1932010-01-03 18:00:18 +00004318 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004319 }
4320 /*
cristy01b7eb02009-09-10 23:10:14 +00004321 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004322 */
4323 clone_image=(*image);
4324 clone_info=(CacheInfo *) clone_image.cache;
4325 image->cache=ClonePixelCache(cache_info);
4326 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4327 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4328 cache_info->type=DiskCache;
4329 cache_info->offset=(*offset);
4330 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004331 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004332 if (status != MagickFalse)
cristycfae90a2010-10-04 14:43:33 +00004333 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
cristy688f07b2009-09-27 15:19:13 +00004334 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004335 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4336 return(status);
4337}
4338
4339/*
4340%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4341% %
4342% %
4343% %
4344+ Q u e u e A u t h e n t i c N e x u s %
4345% %
4346% %
4347% %
4348%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4349%
4350% QueueAuthenticNexus() allocates an region to store image pixels as defined
4351% by the region rectangle and returns a pointer to the region. This region is
4352% subsequently transferred from the pixel cache with
4353% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4354% pixels are transferred, otherwise a NULL is returned.
4355%
4356% The format of the QueueAuthenticNexus() method is:
4357%
cristy4c08aed2011-07-01 19:47:50 +00004358% Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004359% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004360% NexusInfo *nexus_info,ExceptionInfo *exception)
4361%
4362% A description of each parameter follows:
4363%
4364% o image: the image.
4365%
4366% o x,y,columns,rows: These values define the perimeter of a region of
4367% pixels.
4368%
4369% o nexus_info: the cache nexus to set.
4370%
4371% o exception: return any errors or warnings in this structure.
4372%
4373*/
cristy4c08aed2011-07-01 19:47:50 +00004374MagickExport Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy30097232010-07-01 02:16:30 +00004375 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
4376 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004377{
4378 CacheInfo
4379 *cache_info;
4380
4381 MagickOffsetType
4382 offset;
4383
4384 MagickSizeType
4385 number_pixels;
4386
4387 RectangleInfo
4388 region;
4389
4390 /*
4391 Validate pixel cache geometry.
4392 */
cristye7cc7cf2010-09-21 13:26:47 +00004393 assert(image != (const Image *) NULL);
4394 assert(image->signature == MagickSignature);
4395 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004396 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
cristye7cc7cf2010-09-21 13:26:47 +00004397 assert(cache_info->signature == MagickSignature);
cristy77ff0282010-09-13 00:51:10 +00004398 if (cache_info == (Cache) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004399 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004400 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4401 {
4402 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4403 "NoPixelsDefinedInCache","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004404 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004405 }
cristybb503372010-05-27 20:51:26 +00004406 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4407 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004408 {
4409 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4410 "PixelsAreNotAuthentic","`%s'",image->filename);
cristy4c08aed2011-07-01 19:47:50 +00004411 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004412 }
4413 offset=(MagickOffsetType) y*cache_info->columns+x;
4414 if (offset < 0)
cristy4c08aed2011-07-01 19:47:50 +00004415 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004416 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4417 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4418 if ((MagickSizeType) offset >= number_pixels)
cristy4c08aed2011-07-01 19:47:50 +00004419 return((Quantum *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004420 /*
4421 Return pixel cache.
4422 */
4423 region.x=x;
4424 region.y=y;
4425 region.width=columns;
4426 region.height=rows;
4427 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4428}
4429
4430/*
4431%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4432% %
4433% %
4434% %
4435+ 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 %
4436% %
4437% %
4438% %
4439%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4440%
4441% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4442% defined by the region rectangle and returns a pointer to the region. This
4443% region is subsequently transferred from the pixel cache with
4444% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4445% pixels are transferred, otherwise a NULL is returned.
4446%
4447% The format of the QueueAuthenticPixelsCache() method is:
4448%
cristy4c08aed2011-07-01 19:47:50 +00004449% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004450% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004451% ExceptionInfo *exception)
4452%
4453% A description of each parameter follows:
4454%
4455% o image: the image.
4456%
4457% o x,y,columns,rows: These values define the perimeter of a region of
4458% pixels.
4459%
4460% o exception: return any errors or warnings in this structure.
4461%
4462*/
cristy4c08aed2011-07-01 19:47:50 +00004463static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004464 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004465 ExceptionInfo *exception)
4466{
4467 CacheInfo
4468 *cache_info;
4469
cristy5c9e6f22010-09-17 17:31:01 +00004470 const int
4471 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004472
cristy4c08aed2011-07-01 19:47:50 +00004473 Quantum
4474 *pixels;
4475
cristye7cc7cf2010-09-21 13:26:47 +00004476 assert(image != (const Image *) NULL);
4477 assert(image->signature == MagickSignature);
4478 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00004479 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00004480 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00004481 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00004482 pixels=QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4483 exception);
4484 return(pixels);
cristy3ed852e2009-09-05 21:47:34 +00004485}
4486
4487/*
4488%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4489% %
4490% %
4491% %
4492% Q u e u e A u t h e n t i c P i x e l s %
4493% %
4494% %
4495% %
4496%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4497%
4498% QueueAuthenticPixels() queues a mutable pixel region. If the region is
cristy4c08aed2011-07-01 19:47:50 +00004499% successfully initialized a pointer to a Quantum array representing the
cristy3ed852e2009-09-05 21:47:34 +00004500% region is returned, otherwise NULL is returned. The returned pointer may
4501% point to a temporary working buffer for the pixels or it may point to the
4502% final location of the pixels in memory.
4503%
4504% Write-only access means that any existing pixel values corresponding to
4505% the region are ignored. This is useful if the initial image is being
4506% created from scratch, or if the existing pixel values are to be
4507% completely replaced without need to refer to their pre-existing values.
4508% The application is free to read and write the pixel buffer returned by
4509% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4510% initialize the pixel array values. Initializing pixel array values is the
4511% application's responsibility.
4512%
4513% Performance is maximized if the selected region is part of one row, or
4514% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004515% pixels in-place (without a copy) if the image is in memory, or in a
4516% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004517% by the user.
4518%
4519% Pixels accessed via the returned pointer represent a simple array of type
cristy4c08aed2011-07-01 19:47:50 +00004520% Quantum. If the image type is CMYK or the storage class is PseudoClass,
4521% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4522% obtain the meta-content (of type void) corresponding to the region.
4523% Once the Quantum (and/or Quantum) array has been updated, the
4524% changes must be saved back to the underlying image using
4525% SyncAuthenticPixels() or they may be lost.
cristy3ed852e2009-09-05 21:47:34 +00004526%
4527% The format of the QueueAuthenticPixels() method is:
4528%
cristy4c08aed2011-07-01 19:47:50 +00004529% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristy5f959472010-05-27 22:19:46 +00004530% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004531% ExceptionInfo *exception)
4532%
4533% A description of each parameter follows:
4534%
4535% o image: the image.
4536%
4537% o x,y,columns,rows: These values define the perimeter of a region of
4538% pixels.
4539%
4540% o exception: return any errors or warnings in this structure.
4541%
4542*/
cristy4c08aed2011-07-01 19:47:50 +00004543MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
cristybb503372010-05-27 20:51:26 +00004544 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004545 ExceptionInfo *exception)
4546{
4547 CacheInfo
4548 *cache_info;
4549
cristy2036f5c2010-09-19 21:18:17 +00004550 const int
4551 id = GetOpenMPThreadId();
4552
cristy4c08aed2011-07-01 19:47:50 +00004553 Quantum
4554 *pixels;
4555
cristy3ed852e2009-09-05 21:47:34 +00004556 assert(image != (Image *) NULL);
4557 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004558 assert(image->cache != (Cache) NULL);
4559 cache_info=(CacheInfo *) image->cache;
4560 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004561 if (cache_info->methods.queue_authentic_pixels_handler !=
4562 (QueueAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00004563 {
4564 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
4565 columns,rows,exception);
4566 return(pixels);
4567 }
cristy2036f5c2010-09-19 21:18:17 +00004568 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00004569 pixels=QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4570 exception);
4571 return(pixels);
cristy3ed852e2009-09-05 21:47:34 +00004572}
4573
4574/*
4575%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4576% %
4577% %
4578% %
cristy4c08aed2011-07-01 19:47:50 +00004579+ 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 +00004580% %
4581% %
4582% %
4583%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4584%
cristy4c08aed2011-07-01 19:47:50 +00004585% ReadPixelCacheMetacontent() reads metacontent from the specified region of
cristy3ed852e2009-09-05 21:47:34 +00004586% the pixel cache.
4587%
cristy4c08aed2011-07-01 19:47:50 +00004588% The format of the ReadPixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00004589%
cristy4c08aed2011-07-01 19:47:50 +00004590% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004591% NexusInfo *nexus_info,ExceptionInfo *exception)
4592%
4593% A description of each parameter follows:
4594%
4595% o cache_info: the pixel cache.
4596%
cristy4c08aed2011-07-01 19:47:50 +00004597% o nexus_info: the cache nexus to read the metacontent.
cristy3ed852e2009-09-05 21:47:34 +00004598%
4599% o exception: return any errors or warnings in this structure.
4600%
4601*/
cristy4c08aed2011-07-01 19:47:50 +00004602static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00004603 NexusInfo *nexus_info,ExceptionInfo *exception)
4604{
4605 MagickOffsetType
4606 count,
4607 offset;
4608
4609 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004610 extent,
4611 length;
cristy3ed852e2009-09-05 21:47:34 +00004612
cristybb503372010-05-27 20:51:26 +00004613 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004614 y;
4615
cristy4c08aed2011-07-01 19:47:50 +00004616 register unsigned char
4617 *restrict q;
4618
cristybb503372010-05-27 20:51:26 +00004619 size_t
cristy3ed852e2009-09-05 21:47:34 +00004620 rows;
4621
cristy4c08aed2011-07-01 19:47:50 +00004622 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00004623 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00004624 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004625 return(MagickTrue);
4626 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4627 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00004628 length=(MagickSizeType) nexus_info->region.width*
4629 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00004630 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004631 extent=length*rows;
cristy4c08aed2011-07-01 19:47:50 +00004632 q=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00004633 switch (cache_info->type)
4634 {
4635 case MemoryCache:
4636 case MapCache:
4637 {
cristy4c08aed2011-07-01 19:47:50 +00004638 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00004639 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004640
4641 /*
cristy4c08aed2011-07-01 19:47:50 +00004642 Read meta-content from memory.
cristy3ed852e2009-09-05 21:47:34 +00004643 */
cristydd341db2010-03-04 19:06:38 +00004644 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004645 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004646 {
cristy48078b12010-09-23 17:11:01 +00004647 length=extent;
cristydd341db2010-03-04 19:06:38 +00004648 rows=1UL;
4649 }
cristy4c08aed2011-07-01 19:47:50 +00004650 p=(unsigned char *) cache_info->metacontent+offset*
4651 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00004652 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004653 {
cristy8f036fe2010-09-18 02:02:00 +00004654 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00004655 p+=cache_info->metacontent_extent*cache_info->columns;
4656 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004657 }
4658 break;
4659 }
4660 case DiskCache:
4661 {
4662 /*
cristy4c08aed2011-07-01 19:47:50 +00004663 Read meta content from disk.
cristy3ed852e2009-09-05 21:47:34 +00004664 */
4665 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4666 {
4667 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4668 cache_info->cache_filename);
4669 return(MagickFalse);
4670 }
cristydd341db2010-03-04 19:06:38 +00004671 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004672 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004673 {
cristy48078b12010-09-23 17:11:01 +00004674 length=extent;
cristydd341db2010-03-04 19:06:38 +00004675 rows=1UL;
4676 }
cristy48078b12010-09-23 17:11:01 +00004677 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004678 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004679 {
cristy48078b12010-09-23 17:11:01 +00004680 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00004681 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00004682 cache_info->metacontent_extent,length,(unsigned char *) q);
4683 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004684 break;
4685 offset+=cache_info->columns;
cristy4c08aed2011-07-01 19:47:50 +00004686 q+=cache_info->metacontent_extent*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004687 }
cristybb503372010-05-27 20:51:26 +00004688 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004689 {
4690 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4691 cache_info->cache_filename);
4692 return(MagickFalse);
4693 }
4694 break;
4695 }
4696 default:
4697 break;
4698 }
4699 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004700 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004701 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004702 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004703 nexus_info->region.width,(double) nexus_info->region.height,(double)
4704 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004705 return(MagickTrue);
4706}
4707
4708/*
4709%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4710% %
4711% %
4712% %
4713+ R e a d P i x e l C a c h e P i x e l s %
4714% %
4715% %
4716% %
4717%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4718%
4719% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4720% cache.
4721%
4722% The format of the ReadPixelCachePixels() method is:
4723%
4724% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4725% NexusInfo *nexus_info,ExceptionInfo *exception)
4726%
4727% A description of each parameter follows:
4728%
4729% o cache_info: the pixel cache.
4730%
4731% o nexus_info: the cache nexus to read the pixels.
4732%
4733% o exception: return any errors or warnings in this structure.
4734%
4735*/
4736static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4737 NexusInfo *nexus_info,ExceptionInfo *exception)
4738{
4739 MagickOffsetType
4740 count,
4741 offset;
4742
4743 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00004744 extent,
4745 length;
cristy3ed852e2009-09-05 21:47:34 +00004746
cristy4c08aed2011-07-01 19:47:50 +00004747 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004748 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004749
cristye076a6e2010-08-15 19:59:43 +00004750 register ssize_t
4751 y;
4752
cristybb503372010-05-27 20:51:26 +00004753 size_t
cristy3ed852e2009-09-05 21:47:34 +00004754 rows;
4755
cristy4c08aed2011-07-01 19:47:50 +00004756 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004757 return(MagickTrue);
4758 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4759 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00004760 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00004761 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00004762 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00004763 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004764 q=nexus_info->pixels;
4765 switch (cache_info->type)
4766 {
4767 case MemoryCache:
4768 case MapCache:
4769 {
cristy4c08aed2011-07-01 19:47:50 +00004770 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00004771 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004772
4773 /*
4774 Read pixels from memory.
4775 */
cristydd341db2010-03-04 19:06:38 +00004776 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004777 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00004778 {
cristy48078b12010-09-23 17:11:01 +00004779 length=extent;
cristydd341db2010-03-04 19:06:38 +00004780 rows=1UL;
4781 }
cristyed231572011-07-14 02:18:59 +00004782 p=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00004783 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004784 {
cristy8f036fe2010-09-18 02:02:00 +00004785 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00004786 p+=cache_info->number_channels*cache_info->columns;
4787 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004788 }
4789 break;
4790 }
4791 case DiskCache:
4792 {
4793 /*
4794 Read pixels from disk.
4795 */
4796 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4797 {
4798 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4799 cache_info->cache_filename);
4800 return(MagickFalse);
4801 }
cristydd341db2010-03-04 19:06:38 +00004802 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00004803 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00004804 {
cristy48078b12010-09-23 17:11:01 +00004805 length=extent;
cristydd341db2010-03-04 19:06:38 +00004806 rows=1UL;
4807 }
cristybb503372010-05-27 20:51:26 +00004808 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004809 {
4810 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00004811 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
cristy4c08aed2011-07-01 19:47:50 +00004812 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00004813 break;
4814 offset+=cache_info->columns;
cristyed231572011-07-14 02:18:59 +00004815 q+=cache_info->number_channels*nexus_info->region.width;
cristy3ed852e2009-09-05 21:47:34 +00004816 }
cristybb503372010-05-27 20:51:26 +00004817 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004818 {
4819 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4820 cache_info->cache_filename);
4821 return(MagickFalse);
4822 }
4823 break;
4824 }
4825 default:
4826 break;
4827 }
4828 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004829 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004830 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004831 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004832 nexus_info->region.width,(double) nexus_info->region.height,(double)
4833 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004834 return(MagickTrue);
4835}
4836
4837/*
4838%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4839% %
4840% %
4841% %
4842+ R e f e r e n c e P i x e l C a c h e %
4843% %
4844% %
4845% %
4846%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4847%
4848% ReferencePixelCache() increments the reference count associated with the
4849% pixel cache returning a pointer to the cache.
4850%
4851% The format of the ReferencePixelCache method is:
4852%
4853% Cache ReferencePixelCache(Cache cache_info)
4854%
4855% A description of each parameter follows:
4856%
4857% o cache_info: the pixel cache.
4858%
4859*/
4860MagickExport Cache ReferencePixelCache(Cache cache)
4861{
4862 CacheInfo
4863 *cache_info;
4864
4865 assert(cache != (Cache *) NULL);
4866 cache_info=(CacheInfo *) cache;
4867 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004868 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004869 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004870 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004871 return(cache_info);
4872}
4873
4874/*
4875%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4876% %
4877% %
4878% %
4879+ S e t P i x e l C a c h e M e t h o d s %
4880% %
4881% %
4882% %
4883%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4884%
4885% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4886%
4887% The format of the SetPixelCacheMethods() method is:
4888%
4889% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4890%
4891% A description of each parameter follows:
4892%
4893% o cache: the pixel cache.
4894%
4895% o cache_methods: Specifies a pointer to a CacheMethods structure.
4896%
4897*/
4898MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4899{
4900 CacheInfo
4901 *cache_info;
4902
4903 GetOneAuthenticPixelFromHandler
4904 get_one_authentic_pixel_from_handler;
4905
4906 GetOneVirtualPixelFromHandler
4907 get_one_virtual_pixel_from_handler;
4908
4909 /*
4910 Set cache pixel methods.
4911 */
4912 assert(cache != (Cache) NULL);
4913 assert(cache_methods != (CacheMethods *) NULL);
4914 cache_info=(CacheInfo *) cache;
4915 assert(cache_info->signature == MagickSignature);
4916 if (cache_info->debug != MagickFalse)
4917 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4918 cache_info->filename);
4919 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4920 cache_info->methods.get_virtual_pixel_handler=
4921 cache_methods->get_virtual_pixel_handler;
4922 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4923 cache_info->methods.destroy_pixel_handler=
4924 cache_methods->destroy_pixel_handler;
cristy4c08aed2011-07-01 19:47:50 +00004925 if (cache_methods->get_virtual_metacontent_from_handler !=
4926 (GetVirtualMetacontentFromHandler) NULL)
4927 cache_info->methods.get_virtual_metacontent_from_handler=
4928 cache_methods->get_virtual_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004929 if (cache_methods->get_authentic_pixels_handler !=
4930 (GetAuthenticPixelsHandler) NULL)
4931 cache_info->methods.get_authentic_pixels_handler=
4932 cache_methods->get_authentic_pixels_handler;
4933 if (cache_methods->queue_authentic_pixels_handler !=
4934 (QueueAuthenticPixelsHandler) NULL)
4935 cache_info->methods.queue_authentic_pixels_handler=
4936 cache_methods->queue_authentic_pixels_handler;
4937 if (cache_methods->sync_authentic_pixels_handler !=
4938 (SyncAuthenticPixelsHandler) NULL)
4939 cache_info->methods.sync_authentic_pixels_handler=
4940 cache_methods->sync_authentic_pixels_handler;
4941 if (cache_methods->get_authentic_pixels_from_handler !=
4942 (GetAuthenticPixelsFromHandler) NULL)
4943 cache_info->methods.get_authentic_pixels_from_handler=
4944 cache_methods->get_authentic_pixels_from_handler;
cristy4c08aed2011-07-01 19:47:50 +00004945 if (cache_methods->get_authentic_metacontent_from_handler !=
4946 (GetAuthenticMetacontentFromHandler) NULL)
4947 cache_info->methods.get_authentic_metacontent_from_handler=
4948 cache_methods->get_authentic_metacontent_from_handler;
cristy3ed852e2009-09-05 21:47:34 +00004949 get_one_virtual_pixel_from_handler=
4950 cache_info->methods.get_one_virtual_pixel_from_handler;
4951 if (get_one_virtual_pixel_from_handler !=
4952 (GetOneVirtualPixelFromHandler) NULL)
4953 cache_info->methods.get_one_virtual_pixel_from_handler=
4954 cache_methods->get_one_virtual_pixel_from_handler;
4955 get_one_authentic_pixel_from_handler=
4956 cache_methods->get_one_authentic_pixel_from_handler;
4957 if (get_one_authentic_pixel_from_handler !=
4958 (GetOneAuthenticPixelFromHandler) NULL)
4959 cache_info->methods.get_one_authentic_pixel_from_handler=
4960 cache_methods->get_one_authentic_pixel_from_handler;
4961}
4962
4963/*
4964%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4965% %
4966% %
4967% %
4968+ S e t P i x e l C a c h e N e x u s P i x e l s %
4969% %
4970% %
4971% %
4972%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4973%
4974% SetPixelCacheNexusPixels() defines the region of the cache for the
4975% specified cache nexus.
4976%
4977% The format of the SetPixelCacheNexusPixels() method is:
4978%
cristy4c08aed2011-07-01 19:47:50 +00004979% Quantum SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00004980% const RectangleInfo *region,NexusInfo *nexus_info,
4981% ExceptionInfo *exception)
4982%
4983% A description of each parameter follows:
4984%
4985% o image: the image.
4986%
4987% o region: A pointer to the RectangleInfo structure that defines the
4988% region of this particular cache nexus.
4989%
4990% o nexus_info: the cache nexus to set.
4991%
4992% o exception: return any errors or warnings in this structure.
4993%
4994*/
cristyabd6e372010-09-15 19:11:26 +00004995
4996static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4997 NexusInfo *nexus_info,ExceptionInfo *exception)
4998{
4999 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
5000 return(MagickFalse);
5001 nexus_info->mapped=MagickFalse;
cristy4c08aed2011-07-01 19:47:50 +00005002 nexus_info->cache=(Quantum *) AcquireMagickMemory((size_t)
cristyabd6e372010-09-15 19:11:26 +00005003 nexus_info->length);
cristy4c08aed2011-07-01 19:47:50 +00005004 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00005005 {
5006 nexus_info->mapped=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +00005007 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
cristyabd6e372010-09-15 19:11:26 +00005008 nexus_info->length);
5009 }
cristy4c08aed2011-07-01 19:47:50 +00005010 if (nexus_info->cache == (Quantum *) NULL)
cristyabd6e372010-09-15 19:11:26 +00005011 {
5012 (void) ThrowMagickException(exception,GetMagickModule(),
5013 ResourceLimitError,"MemoryAllocationFailed","`%s'",
5014 cache_info->filename);
5015 return(MagickFalse);
5016 }
5017 return(MagickTrue);
5018}
5019
cristy4c08aed2011-07-01 19:47:50 +00005020static Quantum *SetPixelCacheNexusPixels(const Image *image,
cristy3ed852e2009-09-05 21:47:34 +00005021 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
5022{
5023 CacheInfo
5024 *cache_info;
5025
5026 MagickBooleanType
5027 status;
5028
cristy3ed852e2009-09-05 21:47:34 +00005029 MagickSizeType
5030 length,
5031 number_pixels;
5032
cristy3ed852e2009-09-05 21:47:34 +00005033 cache_info=(CacheInfo *) image->cache;
5034 assert(cache_info->signature == MagickSignature);
5035 if (cache_info->type == UndefinedCache)
cristy4c08aed2011-07-01 19:47:50 +00005036 return((Quantum *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00005037 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00005038 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
5039 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00005040 {
cristybb503372010-05-27 20:51:26 +00005041 ssize_t
cristybad067a2010-02-15 17:20:55 +00005042 x,
5043 y;
cristy3ed852e2009-09-05 21:47:34 +00005044
cristyeaedf062010-05-29 22:36:02 +00005045 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
5046 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00005047 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5048 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00005049 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00005050 ((nexus_info->region.width == cache_info->columns) ||
5051 ((nexus_info->region.width % cache_info->columns) == 0)))))
5052 {
5053 MagickOffsetType
5054 offset;
5055
5056 /*
5057 Pixels are accessed directly from memory.
5058 */
5059 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5060 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005061 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005062 offset;
5063 nexus_info->metacontent=(void *) NULL;
5064 if (cache_info->metacontent_extent != 0)
5065 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
5066 offset*cache_info->metacontent_extent;
cristy731c3532010-02-15 15:40:03 +00005067 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00005068 }
5069 }
5070 /*
5071 Pixels are stored in a cache region until they are synced to the cache.
5072 */
5073 number_pixels=(MagickSizeType) nexus_info->region.width*
5074 nexus_info->region.height;
cristyed231572011-07-14 02:18:59 +00005075 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
cristy4c08aed2011-07-01 19:47:50 +00005076 if (cache_info->metacontent_extent != 0)
5077 length+=number_pixels*cache_info->metacontent_extent;
5078 if (nexus_info->cache == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00005079 {
5080 nexus_info->length=length;
5081 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5082 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005083 {
5084 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00005085 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00005086 }
cristy3ed852e2009-09-05 21:47:34 +00005087 }
5088 else
5089 if (nexus_info->length != length)
5090 {
5091 RelinquishCacheNexusPixels(nexus_info);
5092 nexus_info->length=length;
5093 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5094 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005095 {
5096 nexus_info->length=0;
cristy4c08aed2011-07-01 19:47:50 +00005097 return((Quantum *) NULL);
cristy5485e372010-09-15 19:02:29 +00005098 }
cristy3ed852e2009-09-05 21:47:34 +00005099 }
5100 nexus_info->pixels=nexus_info->cache;
cristy4c08aed2011-07-01 19:47:50 +00005101 nexus_info->metacontent=(void *) NULL;
5102 if (cache_info->metacontent_extent != 0)
5103 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
cristyed231572011-07-14 02:18:59 +00005104 cache_info->number_channels);
cristy3ed852e2009-09-05 21:47:34 +00005105 return(nexus_info->pixels);
5106}
5107
5108/*
5109%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5110% %
5111% %
5112% %
5113% 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 %
5114% %
5115% %
5116% %
5117%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5118%
5119% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5120% pixel cache and returns the previous setting. A virtual pixel is any pixel
5121% access that is outside the boundaries of the image cache.
5122%
5123% The format of the SetPixelCacheVirtualMethod() method is:
5124%
5125% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5126% const VirtualPixelMethod virtual_pixel_method)
5127%
5128% A description of each parameter follows:
5129%
5130% o image: the image.
5131%
5132% o virtual_pixel_method: choose the type of virtual pixel.
5133%
5134*/
5135MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5136 const VirtualPixelMethod virtual_pixel_method)
5137{
5138 CacheInfo
5139 *cache_info;
5140
5141 VirtualPixelMethod
5142 method;
5143
5144 assert(image != (Image *) NULL);
5145 assert(image->signature == MagickSignature);
5146 if (image->debug != MagickFalse)
5147 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5148 assert(image->cache != (Cache) NULL);
5149 cache_info=(CacheInfo *) image->cache;
5150 assert(cache_info->signature == MagickSignature);
5151 method=cache_info->virtual_pixel_method;
5152 cache_info->virtual_pixel_method=virtual_pixel_method;
5153 return(method);
5154}
5155
5156/*
5157%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5158% %
5159% %
5160% %
5161+ 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 %
5162% %
5163% %
5164% %
5165%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5166%
5167% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5168% in-memory or disk cache. The method returns MagickTrue if the pixel region
5169% is synced, otherwise MagickFalse.
5170%
5171% The format of the SyncAuthenticPixelCacheNexus() method is:
5172%
5173% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5174% NexusInfo *nexus_info,ExceptionInfo *exception)
5175%
5176% A description of each parameter follows:
5177%
5178% o image: the image.
5179%
5180% o nexus_info: the cache nexus to sync.
5181%
5182% o exception: return any errors or warnings in this structure.
5183%
5184*/
5185MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5186 NexusInfo *nexus_info,ExceptionInfo *exception)
5187{
5188 CacheInfo
5189 *cache_info;
5190
5191 MagickBooleanType
5192 status;
5193
5194 /*
5195 Transfer pixels to the cache.
5196 */
5197 assert(image != (Image *) NULL);
5198 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005199 if (image->cache == (Cache) NULL)
5200 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5201 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005202 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005203 if (cache_info->type == UndefinedCache)
5204 return(MagickFalse);
5205 if ((image->clip_mask != (Image *) NULL) &&
5206 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5207 return(MagickFalse);
5208 if ((image->mask != (Image *) NULL) &&
5209 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5210 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005211 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005212 return(MagickTrue);
5213 assert(cache_info->signature == MagickSignature);
5214 status=WritePixelCachePixels(cache_info,nexus_info,exception);
cristy4c08aed2011-07-01 19:47:50 +00005215 if ((cache_info->metacontent_extent != 0) &&
5216 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00005217 return(MagickFalse);
5218 return(status);
5219}
5220
5221/*
5222%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5223% %
5224% %
5225% %
5226+ S y n c A u t h e n t i c P i x e l C a c h e %
5227% %
5228% %
5229% %
5230%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5231%
5232% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5233% or disk cache. The method returns MagickTrue if the pixel region is synced,
5234% otherwise MagickFalse.
5235%
5236% The format of the SyncAuthenticPixelsCache() method is:
5237%
5238% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5239% ExceptionInfo *exception)
5240%
5241% A description of each parameter follows:
5242%
5243% o image: the image.
5244%
5245% o exception: return any errors or warnings in this structure.
5246%
5247*/
5248static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5249 ExceptionInfo *exception)
5250{
5251 CacheInfo
5252 *cache_info;
5253
cristy5c9e6f22010-09-17 17:31:01 +00005254 const int
5255 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005256
cristy4c08aed2011-07-01 19:47:50 +00005257 MagickBooleanType
5258 status;
5259
cristye7cc7cf2010-09-21 13:26:47 +00005260 assert(image != (Image *) NULL);
5261 assert(image->signature == MagickSignature);
5262 assert(image->cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00005263 cache_info=(CacheInfo *) image->cache;
cristye7cc7cf2010-09-21 13:26:47 +00005264 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00005265 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005266 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5267 exception);
5268 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005269}
5270
5271/*
5272%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5273% %
5274% %
5275% %
5276% S y n c A u t h e n t i c P i x e l s %
5277% %
5278% %
5279% %
5280%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5281%
5282% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5283% The method returns MagickTrue if the pixel region is flushed, otherwise
5284% MagickFalse.
5285%
5286% The format of the SyncAuthenticPixels() method is:
5287%
5288% MagickBooleanType SyncAuthenticPixels(Image *image,
5289% ExceptionInfo *exception)
5290%
5291% A description of each parameter follows:
5292%
5293% o image: the image.
5294%
5295% o exception: return any errors or warnings in this structure.
5296%
5297*/
5298MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5299 ExceptionInfo *exception)
5300{
5301 CacheInfo
5302 *cache_info;
5303
cristy2036f5c2010-09-19 21:18:17 +00005304 const int
5305 id = GetOpenMPThreadId();
5306
cristy4c08aed2011-07-01 19:47:50 +00005307 MagickBooleanType
5308 status;
5309
cristy3ed852e2009-09-05 21:47:34 +00005310 assert(image != (Image *) NULL);
5311 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005312 assert(image->cache != (Cache) NULL);
5313 cache_info=(CacheInfo *) image->cache;
5314 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005315 if (cache_info->methods.sync_authentic_pixels_handler !=
5316 (SyncAuthenticPixelsHandler) NULL)
cristy4c08aed2011-07-01 19:47:50 +00005317 {
5318 status=cache_info->methods.sync_authentic_pixels_handler(image,
5319 exception);
5320 return(status);
5321 }
cristy2036f5c2010-09-19 21:18:17 +00005322 assert(id < (int) cache_info->number_threads);
cristy4c08aed2011-07-01 19:47:50 +00005323 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5324 exception);
5325 return(status);
cristy3ed852e2009-09-05 21:47:34 +00005326}
5327
5328/*
5329%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5330% %
5331% %
5332% %
cristy4c08aed2011-07-01 19:47:50 +00005333+ 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 +00005334% %
5335% %
5336% %
5337%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5338%
cristy4c08aed2011-07-01 19:47:50 +00005339% WritePixelCacheMetacontent() writes the meta-content to the specified region
5340% of the pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00005341%
cristy4c08aed2011-07-01 19:47:50 +00005342% The format of the WritePixelCacheMetacontent() method is:
cristy3ed852e2009-09-05 21:47:34 +00005343%
cristy4c08aed2011-07-01 19:47:50 +00005344% MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005345% NexusInfo *nexus_info,ExceptionInfo *exception)
5346%
5347% A description of each parameter follows:
5348%
5349% o cache_info: the pixel cache.
5350%
cristy4c08aed2011-07-01 19:47:50 +00005351% o nexus_info: the cache nexus to write the meta-content.
cristy3ed852e2009-09-05 21:47:34 +00005352%
5353% o exception: return any errors or warnings in this structure.
5354%
5355*/
cristy4c08aed2011-07-01 19:47:50 +00005356static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
cristy3ed852e2009-09-05 21:47:34 +00005357 NexusInfo *nexus_info,ExceptionInfo *exception)
5358{
5359 MagickOffsetType
5360 count,
5361 offset;
5362
5363 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005364 extent,
5365 length;
cristy3ed852e2009-09-05 21:47:34 +00005366
cristy4c08aed2011-07-01 19:47:50 +00005367 register const unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005368 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005369
cristybb503372010-05-27 20:51:26 +00005370 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005371 y;
5372
cristybb503372010-05-27 20:51:26 +00005373 size_t
cristy3ed852e2009-09-05 21:47:34 +00005374 rows;
5375
cristy4c08aed2011-07-01 19:47:50 +00005376 if (cache_info->metacontent_extent == 0)
cristy3ed852e2009-09-05 21:47:34 +00005377 return(MagickFalse);
cristy4c08aed2011-07-01 19:47:50 +00005378 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005379 return(MagickTrue);
5380 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5381 nexus_info->region.x;
cristy4c08aed2011-07-01 19:47:50 +00005382 length=(MagickSizeType) nexus_info->region.width*
5383 cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005384 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005385 extent=(MagickSizeType) length*rows;
cristy4c08aed2011-07-01 19:47:50 +00005386 p=(unsigned char *) nexus_info->metacontent;
cristy3ed852e2009-09-05 21:47:34 +00005387 switch (cache_info->type)
5388 {
5389 case MemoryCache:
5390 case MapCache:
5391 {
cristy4c08aed2011-07-01 19:47:50 +00005392 register unsigned char
cristyc47d1f82009-11-26 01:44:43 +00005393 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005394
5395 /*
cristy4c08aed2011-07-01 19:47:50 +00005396 Write associated pixels to memory.
cristy3ed852e2009-09-05 21:47:34 +00005397 */
cristydd341db2010-03-04 19:06:38 +00005398 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005399 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005400 {
cristy48078b12010-09-23 17:11:01 +00005401 length=extent;
cristydd341db2010-03-04 19:06:38 +00005402 rows=1UL;
5403 }
cristy4c08aed2011-07-01 19:47:50 +00005404 q=(unsigned char *) cache_info->metacontent+offset*
5405 cache_info->metacontent_extent;
cristybb503372010-05-27 20:51:26 +00005406 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005407 {
cristy8f036fe2010-09-18 02:02:00 +00005408 (void) memcpy(q,p,(size_t) length);
cristy4c08aed2011-07-01 19:47:50 +00005409 p+=nexus_info->region.width*cache_info->metacontent_extent;
5410 q+=cache_info->columns*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005411 }
5412 break;
5413 }
5414 case DiskCache:
5415 {
5416 /*
cristy4c08aed2011-07-01 19:47:50 +00005417 Write associated pixels to disk.
cristy3ed852e2009-09-05 21:47:34 +00005418 */
5419 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5420 {
5421 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5422 cache_info->cache_filename);
5423 return(MagickFalse);
5424 }
cristydd341db2010-03-04 19:06:38 +00005425 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005426 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005427 {
cristy48078b12010-09-23 17:11:01 +00005428 length=extent;
cristydd341db2010-03-04 19:06:38 +00005429 rows=1UL;
5430 }
cristy48078b12010-09-23 17:11:01 +00005431 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005432 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005433 {
cristy48078b12010-09-23 17:11:01 +00005434 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
cristyed231572011-07-14 02:18:59 +00005435 cache_info->number_channels*sizeof(Quantum)+offset*
cristy4c08aed2011-07-01 19:47:50 +00005436 cache_info->metacontent_extent,length,(const unsigned char *) p);
5437 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005438 break;
cristy4c08aed2011-07-01 19:47:50 +00005439 p+=nexus_info->region.width*cache_info->metacontent_extent;
cristy3ed852e2009-09-05 21:47:34 +00005440 offset+=cache_info->columns;
5441 }
cristybb503372010-05-27 20:51:26 +00005442 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005443 {
5444 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5445 cache_info->cache_filename);
5446 return(MagickFalse);
5447 }
5448 break;
5449 }
5450 default:
5451 break;
5452 }
5453 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005454 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005455 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005456 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005457 nexus_info->region.width,(double) nexus_info->region.height,(double)
5458 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005459 return(MagickTrue);
5460}
5461
5462/*
5463%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5464% %
5465% %
5466% %
5467+ W r i t e C a c h e P i x e l s %
5468% %
5469% %
5470% %
5471%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5472%
5473% WritePixelCachePixels() writes image pixels to the specified region of the
5474% pixel cache.
5475%
5476% The format of the WritePixelCachePixels() method is:
5477%
5478% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5479% NexusInfo *nexus_info,ExceptionInfo *exception)
5480%
5481% A description of each parameter follows:
5482%
5483% o cache_info: the pixel cache.
5484%
5485% o nexus_info: the cache nexus to write the pixels.
5486%
5487% o exception: return any errors or warnings in this structure.
5488%
5489*/
5490static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5491 NexusInfo *nexus_info,ExceptionInfo *exception)
5492{
5493 MagickOffsetType
5494 count,
5495 offset;
5496
5497 MagickSizeType
cristy48078b12010-09-23 17:11:01 +00005498 extent,
5499 length;
cristy3ed852e2009-09-05 21:47:34 +00005500
cristy4c08aed2011-07-01 19:47:50 +00005501 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00005502 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005503
cristybb503372010-05-27 20:51:26 +00005504 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005505 y;
5506
cristybb503372010-05-27 20:51:26 +00005507 size_t
cristy3ed852e2009-09-05 21:47:34 +00005508 rows;
5509
cristy4c08aed2011-07-01 19:47:50 +00005510 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00005511 return(MagickTrue);
5512 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5513 nexus_info->region.x;
cristyed231572011-07-14 02:18:59 +00005514 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
cristy4c08aed2011-07-01 19:47:50 +00005515 sizeof(Quantum);
cristy3ed852e2009-09-05 21:47:34 +00005516 rows=nexus_info->region.height;
cristy48078b12010-09-23 17:11:01 +00005517 extent=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005518 p=nexus_info->pixels;
5519 switch (cache_info->type)
5520 {
5521 case MemoryCache:
5522 case MapCache:
5523 {
cristy4c08aed2011-07-01 19:47:50 +00005524 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00005525 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005526
5527 /*
5528 Write pixels to memory.
5529 */
cristydd341db2010-03-04 19:06:38 +00005530 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005531 (extent == (MagickSizeType) ((size_t) extent)))
cristydd341db2010-03-04 19:06:38 +00005532 {
cristy48078b12010-09-23 17:11:01 +00005533 length=extent;
cristydd341db2010-03-04 19:06:38 +00005534 rows=1UL;
5535 }
cristyed231572011-07-14 02:18:59 +00005536 q=cache_info->pixels+offset*cache_info->number_channels;
cristybb503372010-05-27 20:51:26 +00005537 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005538 {
cristy8f036fe2010-09-18 02:02:00 +00005539 (void) memcpy(q,p,(size_t) length);
cristyed231572011-07-14 02:18:59 +00005540 p+=nexus_info->region.width*cache_info->number_channels;
5541 q+=cache_info->columns*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005542 }
5543 break;
5544 }
5545 case DiskCache:
5546 {
5547 /*
5548 Write pixels to disk.
5549 */
5550 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5551 {
5552 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5553 cache_info->cache_filename);
5554 return(MagickFalse);
5555 }
cristydd341db2010-03-04 19:06:38 +00005556 if ((cache_info->columns == nexus_info->region.width) &&
cristy48078b12010-09-23 17:11:01 +00005557 (extent <= MagickMaxBufferExtent))
cristydd341db2010-03-04 19:06:38 +00005558 {
cristy48078b12010-09-23 17:11:01 +00005559 length=extent;
cristydd341db2010-03-04 19:06:38 +00005560 rows=1UL;
5561 }
cristybb503372010-05-27 20:51:26 +00005562 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005563 {
5564 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
cristyed231572011-07-14 02:18:59 +00005565 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
cristy4c08aed2011-07-01 19:47:50 +00005566 p);
5567 if ((MagickSizeType) count != length)
cristy3ed852e2009-09-05 21:47:34 +00005568 break;
cristyed231572011-07-14 02:18:59 +00005569 p+=nexus_info->region.width*cache_info->number_channels;
cristy3ed852e2009-09-05 21:47:34 +00005570 offset+=cache_info->columns;
5571 }
cristybb503372010-05-27 20:51:26 +00005572 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005573 {
5574 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5575 cache_info->cache_filename);
5576 return(MagickFalse);
5577 }
5578 break;
5579 }
5580 default:
5581 break;
5582 }
5583 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005584 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005585 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005586 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005587 nexus_info->region.width,(double) nexus_info->region.height,(double)
5588 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005589 return(MagickTrue);
5590}