blob: c628b9f2735904193a2223c7f97325d0ba7135e9 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% CCCC AAA CCCC H H EEEEE %
7% C A A C H H E %
8% C AAAAA C HHHHH EEE %
9% C A A C H H E %
10% CCCC A A CCCC H H EEEEE %
11% %
12% %
13% MagickCore Pixel Cache Methods %
14% %
15% Software Design %
16% John Cristy %
17% July 1999 %
18% %
19% %
cristy16af1cb2009-12-11 21:38:29 +000020% Copyright 1999-2010 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% http://www.imagemagick.org/script/license.php %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37%
38*/
39
40/*
41 Include declarations.
42*/
43#include "magick/studio.h"
44#include "magick/blob.h"
45#include "magick/blob-private.h"
46#include "magick/cache.h"
47#include "magick/cache-private.h"
48#include "magick/color-private.h"
49#include "magick/composite-private.h"
50#include "magick/exception.h"
51#include "magick/exception-private.h"
cristy365e58f2010-02-15 02:00:01 +000052#include "magick/geometry.h"
cristy3ed852e2009-09-05 21:47:34 +000053#include "magick/list.h"
54#include "magick/log.h"
55#include "magick/magick.h"
56#include "magick/memory_.h"
cristy4789f0d2010-01-10 00:01:06 +000057#include "magick/pixel.h"
cristy3ed852e2009-09-05 21:47:34 +000058#include "magick/pixel-private.h"
cristya21afde2010-07-02 00:45:40 +000059#include "magick/policy.h"
cristy3ed852e2009-09-05 21:47:34 +000060#include "magick/quantum.h"
61#include "magick/random_.h"
62#include "magick/resource_.h"
63#include "magick/semaphore.h"
64#include "magick/splay-tree.h"
65#include "magick/string_.h"
cristya21afde2010-07-02 00:45:40 +000066#include "magick/string-private.h"
cristy3ed852e2009-09-05 21:47:34 +000067#include "magick/thread-private.h"
68#include "magick/utility.h"
69#if defined(MAGICKCORE_ZLIB_DELEGATE)
70#include "zlib.h"
71#endif
72
73/*
cristy30097232010-07-01 02:16:30 +000074 Define declarations.
75*/
76#define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
77
78/*
cristy3ed852e2009-09-05 21:47:34 +000079 Typedef declarations.
80*/
81typedef struct _MagickModulo
82{
cristybb503372010-05-27 20:51:26 +000083 ssize_t
cristy3ed852e2009-09-05 21:47:34 +000084 quotient,
85 remainder;
86} MagickModulo;
87
88struct _NexusInfo
89{
90 MagickBooleanType
91 mapped;
92
93 RectangleInfo
94 region;
95
96 MagickSizeType
97 length;
98
99 PixelPacket
100 *cache,
101 *pixels;
102
103 IndexPacket
104 *indexes;
105
cristybb503372010-05-27 20:51:26 +0000106 size_t
cristy3ed852e2009-09-05 21:47:34 +0000107 signature;
108};
109
110/*
111 Forward declarations.
112*/
113#if defined(__cplusplus) || defined(c_plusplus)
114extern "C" {
115#endif
116
117static const IndexPacket
118 *GetVirtualIndexesFromCache(const Image *);
119
120static const PixelPacket
cristybb503372010-05-27 20:51:26 +0000121 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
122 const ssize_t,const size_t,const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000123 *GetVirtualPixelsCache(const Image *);
124
125static MagickBooleanType
cristy09c1c4d2010-06-30 18:23:16 +0000126 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,
127 PixelPacket *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000128 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
cristybb503372010-05-27 20:51:26 +0000129 const ssize_t,const ssize_t,PixelPacket *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000130 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
131 ReadPixelCacheIndexes(CacheInfo *,NexusInfo *,ExceptionInfo *),
132 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
133 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
134 WritePixelCacheIndexes(CacheInfo *,NexusInfo *,ExceptionInfo *),
135 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
136
137static PixelPacket
cristybb503372010-05-27 20:51:26 +0000138 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
139 const size_t,ExceptionInfo *),
140 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
141 const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000142 *SetPixelCacheNexusPixels(const Image *,const RectangleInfo *,NexusInfo *,
cristya4af2e32010-03-08 00:51:56 +0000143 ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +0000144
145#if defined(__cplusplus) || defined(c_plusplus)
146}
147#endif
148
149/*
150 Global declarations.
151*/
152static volatile MagickBooleanType
153 instantiate_cache = MagickFalse;
154
155static SemaphoreInfo
156 *cache_semaphore = (SemaphoreInfo *) NULL;
157
158static SplayTreeInfo
159 *cache_resources = (SplayTreeInfo *) NULL;
cristy3ed852e2009-09-05 21:47:34 +0000160
161/*
162%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
163% %
164% %
165% %
166+ A c q u i r e P i x e l C a c h e %
167% %
168% %
169% %
170%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
171%
172% AcquirePixelCache() acquires a pixel cache.
173%
174% The format of the AcquirePixelCache() method is:
175%
cristybb503372010-05-27 20:51:26 +0000176% Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000177%
178% A description of each parameter follows:
179%
180% o number_threads: the number of nexus threads.
181%
182*/
cristybb503372010-05-27 20:51:26 +0000183MagickExport Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000184{
185 CacheInfo
186 *cache_info;
187
188 cache_info=(CacheInfo *) AcquireAlignedMemory(1,sizeof(*cache_info));
189 if (cache_info == (CacheInfo *) NULL)
190 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
191 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
192 cache_info->type=UndefinedCache;
cristy87528ea2009-09-10 14:53:56 +0000193 cache_info->mode=IOMode;
cristy3ed852e2009-09-05 21:47:34 +0000194 cache_info->colorspace=RGBColorspace;
195 cache_info->file=(-1);
196 cache_info->id=GetMagickThreadId();
197 cache_info->number_threads=number_threads;
198 if (number_threads == 0)
199 cache_info->number_threads=GetOpenMPMaximumThreads();
200 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
201 if (cache_info->nexus_info == (NexusInfo **) NULL)
202 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
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
cristy3ed852e2009-09-05 21:47:34 +0000257 nexus_info=(NexusInfo **) AcquireAlignedMemory(number_threads,
258 sizeof(*nexus_info));
259 if (nexus_info == (NexusInfo **) NULL)
260 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristybb503372010-05-27 20:51:26 +0000261 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000262 {
263 nexus_info[i]=(NexusInfo *) AcquireAlignedMemory(1,sizeof(**nexus_info));
264 if (nexus_info[i] == (NexusInfo *) NULL)
265 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
266 (void) ResetMagickMemory(nexus_info[i],0,sizeof(*nexus_info[i]));
267 nexus_info[i]->signature=MagickSignature;
268 }
269 return(nexus_info);
270}
271
272/*
273%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
274% %
275% %
276% %
cristyd43a46b2010-01-21 02:13:41 +0000277+ A c q u i r e P i x e l C a c h e P i x e l s %
278% %
279% %
280% %
281%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
282%
283% AcquirePixelCachePixels() returns the pixels associated with the specified
284% image.
285%
286% The format of the AcquirePixelCachePixels() method is:
287%
288% const void *AcquirePixelCachePixels(const Image *image,
289% MagickSizeType *length,ExceptionInfo *exception)
290%
291% A description of each parameter follows:
292%
293% o image: the image.
294%
295% o length: the pixel cache length.
296%
297% o exception: return any errors or warnings in this structure.
298%
299*/
300MagickExport const void *AcquirePixelCachePixels(const Image *image,
301 MagickSizeType *length,ExceptionInfo *exception)
302{
303 CacheInfo
304 *cache_info;
305
306 assert(image != (const Image *) NULL);
307 assert(image->signature == MagickSignature);
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
386% mask. The method returns MagickTrue if the pixel region is clipped,
387% otherwise MagickFalse.
388%
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
416 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000417 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +0000418
419 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +0000420 *restrict nexus_indexes,
421 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +0000422
cristy3ed852e2009-09-05 21:47:34 +0000423 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000424 *restrict p,
425 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000426
cristye076a6e2010-08-15 19:59:43 +0000427 register ssize_t
428 i;
429
cristy3ed852e2009-09-05 21:47:34 +0000430 /*
431 Apply clip mask.
432 */
433 if (image->debug != MagickFalse)
434 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
435 if (image->clip_mask == (Image *) NULL)
436 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +0000437 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +0000438 if (cache_info == (Cache) NULL)
439 return(MagickFalse);
440 image_nexus=AcquirePixelCacheNexus(1);
441 clip_nexus=AcquirePixelCacheNexus(1);
442 if ((image_nexus == (NexusInfo **) NULL) ||
443 (clip_nexus == (NexusInfo **) NULL))
444 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
445 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,nexus_info->region.y,
446 nexus_info->region.width,nexus_info->region.height,image_nexus[0],
447 exception);
cristy2036f5c2010-09-19 21:18:17 +0000448 indexes=GetPixelCacheNexusIndexes(cache_info,image_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +0000449 q=nexus_info->pixels;
450 nexus_indexes=nexus_info->indexes;
451 r=GetVirtualPixelsFromNexus(image->clip_mask,MaskVirtualPixelMethod,
452 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
453 nexus_info->region.height,clip_nexus[0],exception);
454 number_pixels=(MagickSizeType) nexus_info->region.width*
455 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +0000456 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000457 {
458 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
459 break;
460 if (PixelIntensityToQuantum(r) > ((Quantum) QuantumRange/2))
461 {
cristyce70c172010-01-07 17:15:30 +0000462 SetRedPixelComponent(q,GetRedPixelComponent(p));
463 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
464 SetBluePixelComponent(q,GetBluePixelComponent(p));
465 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
cristy3ed852e2009-09-05 21:47:34 +0000466 if (cache_info->active_index_channel != MagickFalse)
467 nexus_indexes[i]=indexes[i];
468 }
469 p++;
470 q++;
471 r++;
472 }
473 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
474 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +0000475 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +0000476 return(MagickFalse);
477 return(MagickTrue);
478}
479
480/*
481%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
482% %
483% %
484% %
485+ C l o n e P i x e l C a c h e %
486% %
487% %
488% %
489%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
490%
491% ClonePixelCache() clones a pixel cache.
492%
493% The format of the ClonePixelCache() method is:
494%
495% Cache ClonePixelCache(const Cache cache)
496%
497% A description of each parameter follows:
498%
499% o cache: the pixel cache.
500%
501*/
502MagickExport Cache ClonePixelCache(const Cache cache)
503{
504 CacheInfo
505 *clone_info;
506
507 const CacheInfo
508 *cache_info;
509
510 assert(cache != (const Cache) NULL);
511 cache_info=(const CacheInfo *) cache;
512 assert(cache_info->signature == MagickSignature);
513 if (cache_info->debug != MagickFalse)
514 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
515 cache_info->filename);
516 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
517 if (clone_info == (Cache) NULL)
518 return((Cache) NULL);
519 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
520 return((Cache ) clone_info);
521}
522
523/*
524%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
525% %
526% %
527% %
cristy60c44a82009-10-07 00:58:49 +0000528+ 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 +0000529% %
530% %
531% %
532%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
533% ClonePixelCachePixels() clones the source pixel cache to the destination
534% cache.
535%
536% The format of the ClonePixelCachePixels() method is:
537%
538% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
539% CacheInfo *source_info,ExceptionInfo *exception)
540%
541% A description of each parameter follows:
542%
543% o cache_info: the pixel cache.
544%
545% o source_info: the source pixel cache.
546%
547% o exception: return any errors or warnings in this structure.
548%
549*/
550
551static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
552{
553 int
554 status;
555
cristy5ee247a2010-02-12 15:42:34 +0000556 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000557 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000558 if (cache_info->file != -1)
559 status=close(cache_info->file);
cristy3ed852e2009-09-05 21:47:34 +0000560 cache_info->file=(-1);
561 RelinquishMagickResource(FileResource,1);
cristyf84a1932010-01-03 18:00:18 +0000562 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000563 return(status == -1 ? MagickFalse : MagickTrue);
564}
565
566static void LimitPixelCacheDescriptors(void)
567{
568 register CacheInfo
569 *p,
570 *q;
571
572 /*
573 Limit # of open file descriptors.
574 */
575 if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
576 return;
cristyf84a1932010-01-03 18:00:18 +0000577 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000578 if (cache_resources == (SplayTreeInfo *) NULL)
579 {
cristyf84a1932010-01-03 18:00:18 +0000580 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000581 return;
582 }
583 ResetSplayTreeIterator(cache_resources);
584 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
585 while (p != (CacheInfo *) NULL)
586 {
587 if ((p->type == DiskCache) && (p->file != -1))
cristy508d9312010-02-10 21:10:30 +0000588 break;
cristy3ed852e2009-09-05 21:47:34 +0000589 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
590 }
591 for (q=p; p != (CacheInfo *) NULL; )
592 {
593 if ((p->type == DiskCache) && (p->file != -1) &&
594 (p->timestamp < q->timestamp))
cristy508d9312010-02-10 21:10:30 +0000595 q=p;
cristy3ed852e2009-09-05 21:47:34 +0000596 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
597 }
598 if (q != (CacheInfo *) NULL)
cristy9e116922010-02-12 20:58:13 +0000599 {
600 /*
601 Close least recently used cache.
602 */
603 (void) close(q->file);
604 q->file=(-1);
605 }
cristyf84a1932010-01-03 18:00:18 +0000606 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000607}
608
609static inline MagickSizeType MagickMax(const MagickSizeType x,
610 const MagickSizeType y)
611{
612 if (x > y)
613 return(x);
614 return(y);
615}
616
617static inline MagickSizeType MagickMin(const MagickSizeType x,
618 const MagickSizeType y)
619{
620 if (x < y)
621 return(x);
622 return(y);
623}
624
625static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
626 const MapMode mode)
627{
628 int
629 file;
630
631 /*
632 Open pixel cache on disk.
633 */
cristyf84a1932010-01-03 18:00:18 +0000634 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000635 if (cache_info->file != -1)
636 {
cristyf84a1932010-01-03 18:00:18 +0000637 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000638 return(MagickTrue); /* cache already open */
639 }
640 LimitPixelCacheDescriptors();
641 if (*cache_info->cache_filename == '\0')
642 file=AcquireUniqueFileResource(cache_info->cache_filename);
643 else
644 switch (mode)
645 {
646 case ReadMode:
647 {
648 file=open(cache_info->cache_filename,O_RDONLY | O_BINARY);
649 break;
650 }
651 case WriteMode:
652 {
653 file=open(cache_info->cache_filename,O_WRONLY | O_CREAT | O_BINARY |
654 O_EXCL,S_MODE);
655 if (file == -1)
656 file=open(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
657 break;
658 }
659 case IOMode:
660 default:
661 {
662 file=open(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
663 O_EXCL,S_MODE);
664 if (file == -1)
665 file=open(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
666 break;
667 }
668 }
669 if (file == -1)
670 {
cristyf84a1932010-01-03 18:00:18 +0000671 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000672 return(MagickFalse);
673 }
674 (void) AcquireMagickResource(FileResource,1);
675 cache_info->file=file;
676 cache_info->timestamp=time(0);
cristyf84a1932010-01-03 18:00:18 +0000677 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000678 return(MagickTrue);
679}
680
681static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
682 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000683 unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000684{
685 register MagickOffsetType
686 i;
687
688 ssize_t
689 count;
690
cristy08a88202010-03-04 19:18:05 +0000691 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000692#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000693 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000694 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
695 {
cristyf84a1932010-01-03 18:00:18 +0000696 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000697 return((MagickOffsetType) -1);
698 }
699#endif
700 count=0;
701 for (i=0; i < (MagickOffsetType) length; i+=count)
702 {
703#if !defined(MAGICKCORE_HAVE_PREAD)
704 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
705 (MagickSizeType) SSIZE_MAX));
706#else
707 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
708 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
709#endif
710 if (count > 0)
711 continue;
712 count=0;
713 if (errno != EINTR)
714 {
715 i=(-1);
716 break;
717 }
718 }
719#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000720 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000721#endif
722 return(i);
723}
724
725static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
726 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000727 const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000728{
729 register MagickOffsetType
730 i;
731
732 ssize_t
733 count;
734
cristy08a88202010-03-04 19:18:05 +0000735 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000736#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000737 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000738 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
739 {
cristyf84a1932010-01-03 18:00:18 +0000740 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000741 return((MagickOffsetType) -1);
742 }
743#endif
744 count=0;
745 for (i=0; i < (MagickOffsetType) length; i+=count)
746 {
747#if !defined(MAGICKCORE_HAVE_PWRITE)
748 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
749 (MagickSizeType) SSIZE_MAX));
750#else
751 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
752 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
753#endif
754 if (count > 0)
755 continue;
756 count=0;
757 if (errno != EINTR)
758 {
759 i=(-1);
760 break;
761 }
762 }
763#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000764 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000765#endif
766 return(i);
767}
768
769static MagickBooleanType CloneDiskToDiskPixelCache(CacheInfo *clone_info,
770 CacheInfo *cache_info,ExceptionInfo *exception)
771{
772 MagickOffsetType
773 count,
774 offset,
775 source_offset;
776
777 MagickSizeType
778 length;
779
cristy3ed852e2009-09-05 21:47:34 +0000780 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000781 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +0000782
cristye076a6e2010-08-15 19:59:43 +0000783 register ssize_t
784 y;
785
cristybb503372010-05-27 20:51:26 +0000786 size_t
cristy3ed852e2009-09-05 21:47:34 +0000787 columns,
788 rows;
789
790 if (cache_info->debug != MagickFalse)
791 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
792 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
793 {
794 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
795 clone_info->cache_filename);
796 return(MagickFalse);
797 }
798 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
799 {
800 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
801 cache_info->cache_filename);
802 return(MagickFalse);
803 }
cristybb503372010-05-27 20:51:26 +0000804 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
805 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +0000806 if ((clone_info->active_index_channel != MagickFalse) &&
807 (cache_info->active_index_channel != MagickFalse))
808 {
809 register IndexPacket
810 *indexes;
811
812 /*
813 Clone cache indexes.
814 */
815 length=MagickMax(clone_info->columns,cache_info->columns)*
816 sizeof(*indexes);
817 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
818 if (indexes == (IndexPacket *) NULL)
819 {
820 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
821 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
822 return(MagickFalse);
823 }
824 (void) ResetMagickMemory(indexes,0,(size_t) length);
825 length=columns*sizeof(*indexes);
826 source_offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
827 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
828 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
829 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +0000830 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000831 {
832 source_offset-=cache_info->columns*sizeof(*indexes);
833 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
834 length,(unsigned char *) indexes);
835 if ((MagickSizeType) count != length)
836 break;
837 offset-=clone_info->columns*sizeof(*indexes);
838 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
839 (unsigned char *) indexes);
840 if ((MagickSizeType) count != length)
841 break;
842 }
cristybb503372010-05-27 20:51:26 +0000843 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000844 {
845 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
846 ThrowFileException(exception,CacheError,"UnableToCloneCache",
847 cache_info->cache_filename);
848 return(MagickFalse);
849 }
850 if (clone_info->columns > cache_info->columns)
851 {
852 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
853 (void) ResetMagickMemory(indexes,0,(size_t) length);
854 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
855 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +0000856 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000857 {
858 offset-=clone_info->columns*sizeof(*indexes);
859 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
860 length,(unsigned char *) indexes);
861 if ((MagickSizeType) count != length)
862 break;
863 }
cristybb503372010-05-27 20:51:26 +0000864 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000865 {
866 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
867 ThrowFileException(exception,CacheError,"UnableToCloneCache",
868 cache_info->cache_filename);
869 return(MagickFalse);
870 }
871 }
872 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
873 }
874 /*
875 Clone cache pixels.
876 */
877 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
878 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
879 if (pixels == (PixelPacket *) NULL)
880 {
881 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
882 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
883 return(MagickFalse);
884 }
885 (void) ResetMagickMemory(pixels,0,(size_t) length);
886 length=columns*sizeof(*pixels);
887 source_offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
888 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +0000889 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000890 {
891 source_offset-=cache_info->columns*sizeof(*pixels);
892 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
893 length,(unsigned char *) pixels);
894 if ((MagickSizeType) count != length)
895 break;
896 offset-=clone_info->columns*sizeof(*pixels);
897 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
898 (unsigned char *) pixels);
899 if ((MagickSizeType) count != length)
900 break;
901 }
cristybb503372010-05-27 20:51:26 +0000902 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000903 {
904 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
905 ThrowFileException(exception,CacheError,"UnableToCloneCache",
906 cache_info->cache_filename);
907 return(MagickFalse);
908 }
909 if (clone_info->columns > cache_info->columns)
910 {
911 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
912 sizeof(*pixels);
913 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
914 (void) ResetMagickMemory(pixels,0,(size_t) length);
cristybb503372010-05-27 20:51:26 +0000915 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000916 {
917 offset-=clone_info->columns*sizeof(*pixels);
918 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
919 (unsigned char *) pixels);
920 if ((MagickSizeType) count != length)
921 break;
922 }
cristybb503372010-05-27 20:51:26 +0000923 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000924 {
925 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
926 ThrowFileException(exception,CacheError,"UnableToCloneCache",
927 cache_info->cache_filename);
928 return(MagickFalse);
929 }
930 }
931 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
932 return(MagickTrue);
933}
934
935static MagickBooleanType CloneDiskToMemoryPixelCache(CacheInfo *clone_info,
936 CacheInfo *cache_info,ExceptionInfo *exception)
937{
938 MagickOffsetType
939 count,
940 offset;
941
942 MagickSizeType
943 length;
944
cristy3ed852e2009-09-05 21:47:34 +0000945 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000946 *restrict pixels,
947 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000948
cristye076a6e2010-08-15 19:59:43 +0000949 register ssize_t
950 y;
951
cristybb503372010-05-27 20:51:26 +0000952 size_t
cristy3ed852e2009-09-05 21:47:34 +0000953 columns,
954 rows;
955
956 if (cache_info->debug != MagickFalse)
957 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
958 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
959 {
960 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
961 cache_info->cache_filename);
962 return(MagickFalse);
963 }
cristybb503372010-05-27 20:51:26 +0000964 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
965 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +0000966 if ((clone_info->active_index_channel != MagickFalse) &&
967 (cache_info->active_index_channel != MagickFalse))
968 {
969 register IndexPacket
970 *indexes,
971 *q;
972
973 /*
974 Clone cache indexes.
975 */
976 length=MagickMax(clone_info->columns,cache_info->columns)*
977 sizeof(*indexes);
978 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
979 if (indexes == (IndexPacket *) NULL)
980 {
981 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
982 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
983 return(MagickFalse);
984 }
985 (void) ResetMagickMemory(indexes,0,(size_t) length);
986 length=columns*sizeof(IndexPacket);
987 offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
988 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
989 q=clone_info->indexes+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +0000990 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000991 {
992 offset-=cache_info->columns*sizeof(IndexPacket);
993 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,
994 length,(unsigned char *) indexes);
995 if ((MagickSizeType) count != length)
996 break;
997 q-=clone_info->columns;
cristy8f036fe2010-09-18 02:02:00 +0000998 (void) memcpy(q,indexes,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +0000999 if ((MagickSizeType) count != length)
1000 break;
1001 }
cristybb503372010-05-27 20:51:26 +00001002 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001003 {
1004 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1005 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1006 cache_info->cache_filename);
1007 return(MagickFalse);
1008 }
1009 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1010 }
1011 /*
1012 Clone cache pixels.
1013 */
1014 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1015 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1016 if (pixels == (PixelPacket *) NULL)
1017 {
1018 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1019 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1020 return(MagickFalse);
1021 }
1022 (void) ResetMagickMemory(pixels,0,(size_t) length);
1023 length=columns*sizeof(*pixels);
1024 offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
1025 q=clone_info->pixels+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001026 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001027 {
1028 offset-=cache_info->columns*sizeof(*pixels);
1029 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,length,
1030 (unsigned char *) pixels);
1031 if ((MagickSizeType) count != length)
1032 break;
1033 q-=clone_info->columns;
cristy8f036fe2010-09-18 02:02:00 +00001034 (void) memcpy(q,pixels,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00001035 }
cristybb503372010-05-27 20:51:26 +00001036 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001037 {
1038 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1039 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1040 cache_info->cache_filename);
1041 return(MagickFalse);
1042 }
1043 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1044 return(MagickTrue);
1045}
1046
1047static MagickBooleanType CloneMemoryToDiskPixelCache(CacheInfo *clone_info,
1048 CacheInfo *cache_info,ExceptionInfo *exception)
1049{
1050 MagickOffsetType
1051 count,
1052 offset;
1053
1054 MagickSizeType
1055 length;
1056
cristy3ed852e2009-09-05 21:47:34 +00001057 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001058 *restrict p,
1059 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +00001060
cristye076a6e2010-08-15 19:59:43 +00001061 register ssize_t
1062 y;
1063
cristybb503372010-05-27 20:51:26 +00001064 size_t
cristy3ed852e2009-09-05 21:47:34 +00001065 columns,
1066 rows;
1067
1068 if (cache_info->debug != MagickFalse)
1069 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
1070 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
1071 {
1072 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1073 clone_info->cache_filename);
1074 return(MagickFalse);
1075 }
cristybb503372010-05-27 20:51:26 +00001076 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1077 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001078 if ((clone_info->active_index_channel != MagickFalse) &&
1079 (cache_info->active_index_channel != MagickFalse))
1080 {
1081 register IndexPacket
1082 *p,
1083 *indexes;
1084
1085 /*
1086 Clone cache indexes.
1087 */
1088 length=MagickMax(clone_info->columns,cache_info->columns)*
1089 sizeof(*indexes);
1090 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1091 if (indexes == (IndexPacket *) NULL)
1092 {
1093 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1094 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1095 return(MagickFalse);
1096 }
1097 (void) ResetMagickMemory(indexes,0,(size_t) length);
1098 length=columns*sizeof(*indexes);
1099 p=cache_info->indexes+cache_info->columns*rows;
1100 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1101 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +00001102 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001103 {
1104 p-=cache_info->columns;
cristy8f036fe2010-09-18 02:02:00 +00001105 (void) memcpy(indexes,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00001106 offset-=clone_info->columns*sizeof(*indexes);
1107 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1108 (unsigned char *) indexes);
1109 if ((MagickSizeType) count != length)
1110 break;
1111 }
cristybb503372010-05-27 20:51:26 +00001112 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001113 {
1114 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1115 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1116 cache_info->cache_filename);
1117 return(MagickFalse);
1118 }
1119 if (clone_info->columns > cache_info->columns)
1120 {
1121 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
1122 (void) ResetMagickMemory(indexes,0,(size_t) length);
1123 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1124 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +00001125 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001126 {
1127 offset-=clone_info->columns*sizeof(*indexes);
1128 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
1129 length,(unsigned char *) indexes);
1130 if ((MagickSizeType) count != length)
1131 break;
1132 }
cristybb503372010-05-27 20:51:26 +00001133 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001134 {
1135 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1136 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1137 cache_info->cache_filename);
1138 return(MagickFalse);
1139 }
1140 }
1141 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1142 }
1143 /*
1144 Clone cache pixels.
1145 */
1146 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1147 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1148 if (pixels == (PixelPacket *) NULL)
1149 {
1150 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1151 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1152 return(MagickFalse);
1153 }
1154 (void) ResetMagickMemory(pixels,0,(size_t) length);
1155 length=columns*sizeof(*pixels);
1156 p=cache_info->pixels+cache_info->columns*rows;
1157 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +00001158 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001159 {
1160 p-=cache_info->columns;
cristy8f036fe2010-09-18 02:02:00 +00001161 (void) memcpy(pixels,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00001162 offset-=clone_info->columns*sizeof(*pixels);
1163 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1164 (unsigned char *) pixels);
1165 if ((MagickSizeType) count != length)
1166 break;
1167 }
cristybb503372010-05-27 20:51:26 +00001168 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001169 {
1170 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1171 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1172 cache_info->cache_filename);
1173 return(MagickFalse);
1174 }
1175 if (clone_info->columns > cache_info->columns)
1176 {
1177 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
1178 sizeof(*pixels);
1179 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1180 (void) ResetMagickMemory(pixels,0,(size_t) length);
cristybb503372010-05-27 20:51:26 +00001181 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001182 {
1183 offset-=clone_info->columns*sizeof(*pixels);
1184 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1185 (unsigned char *) pixels);
1186 if ((MagickSizeType) count != length)
1187 break;
1188 }
cristybb503372010-05-27 20:51:26 +00001189 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001190 {
1191 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1192 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1193 cache_info->cache_filename);
1194 return(MagickFalse);
1195 }
1196 }
1197 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1198 return(MagickTrue);
1199}
1200
1201static MagickBooleanType CloneMemoryToMemoryPixelCache(CacheInfo *clone_info,
1202 CacheInfo *cache_info,ExceptionInfo *magick_unused(exception))
1203{
cristy3ed852e2009-09-05 21:47:34 +00001204 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001205 *restrict pixels,
1206 *restrict source_pixels;
cristy3ed852e2009-09-05 21:47:34 +00001207
cristye076a6e2010-08-15 19:59:43 +00001208 register ssize_t
1209 y;
cristy3ed852e2009-09-05 21:47:34 +00001210
cristybb503372010-05-27 20:51:26 +00001211 size_t
cristy3ed852e2009-09-05 21:47:34 +00001212 columns,
cristye076a6e2010-08-15 19:59:43 +00001213 length,
cristy3ed852e2009-09-05 21:47:34 +00001214 rows;
1215
1216 if (cache_info->debug != MagickFalse)
1217 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
cristybb503372010-05-27 20:51:26 +00001218 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1219 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001220 if ((clone_info->active_index_channel != MagickFalse) &&
1221 (cache_info->active_index_channel != MagickFalse))
1222 {
1223 register IndexPacket
1224 *indexes,
1225 *source_indexes;
1226
1227 /*
1228 Clone cache indexes.
1229 */
1230 length=columns*sizeof(*indexes);
1231 if (clone_info->columns == cache_info->columns)
cristy8f036fe2010-09-18 02:02:00 +00001232 (void) memcpy(clone_info->indexes,cache_info->indexes,length*rows);
cristy3ed852e2009-09-05 21:47:34 +00001233 else
1234 {
1235 source_indexes=cache_info->indexes+cache_info->columns*rows;
1236 indexes=clone_info->indexes+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001237 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001238 {
1239 source_indexes-=cache_info->columns;
1240 indexes-=clone_info->columns;
cristy8f036fe2010-09-18 02:02:00 +00001241 (void) memcpy(indexes,source_indexes,length);
cristy3ed852e2009-09-05 21:47:34 +00001242 }
1243 if (clone_info->columns > cache_info->columns)
1244 {
1245 length=(clone_info->columns-cache_info->columns)*
1246 sizeof(*indexes);
1247 indexes=clone_info->indexes+clone_info->columns*rows+
1248 cache_info->columns;
cristybb503372010-05-27 20:51:26 +00001249 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001250 {
1251 indexes-=clone_info->columns;
1252 (void) ResetMagickMemory(indexes,0,length);
1253 }
1254 }
1255 }
1256 }
1257 /*
1258 Clone cache pixels.
1259 */
1260 length=columns*sizeof(*pixels);
1261 if (clone_info->columns == cache_info->columns)
cristy8f036fe2010-09-18 02:02:00 +00001262 (void) memcpy(clone_info->pixels,cache_info->pixels,length*rows);
cristy3ed852e2009-09-05 21:47:34 +00001263 else
1264 {
1265 source_pixels=cache_info->pixels+cache_info->columns*rows;
1266 pixels=clone_info->pixels+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001267 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001268 {
1269 source_pixels-=cache_info->columns;
1270 pixels-=clone_info->columns;
cristy8f036fe2010-09-18 02:02:00 +00001271 (void) memcpy(pixels,source_pixels,length);
cristy3ed852e2009-09-05 21:47:34 +00001272 }
1273 if (clone_info->columns > cache_info->columns)
1274 {
1275 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1276 pixels=clone_info->pixels+clone_info->columns*rows+
1277 cache_info->columns;
cristybb503372010-05-27 20:51:26 +00001278 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001279 {
1280 pixels-=clone_info->columns;
1281 (void) ResetMagickMemory(pixels,0,length);
1282 }
1283 }
1284 }
1285 return(MagickTrue);
1286}
1287
1288static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1289 CacheInfo *cache_info,ExceptionInfo *exception)
1290{
1291 if ((clone_info->type != DiskCache) && (cache_info->type != DiskCache))
1292 return(CloneMemoryToMemoryPixelCache(clone_info,cache_info,exception));
1293 if ((clone_info->type == DiskCache) && (cache_info->type == DiskCache))
1294 return(CloneDiskToDiskPixelCache(clone_info,cache_info,exception));
1295 if (cache_info->type == DiskCache)
1296 return(CloneDiskToMemoryPixelCache(clone_info,cache_info,exception));
1297 return(CloneMemoryToDiskPixelCache(clone_info,cache_info,exception));
1298}
1299
1300/*
1301%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1302% %
1303% %
1304% %
1305+ C l o n e P i x e l C a c h e M e t h o d s %
1306% %
1307% %
1308% %
1309%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1310%
1311% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1312% another.
1313%
1314% The format of the ClonePixelCacheMethods() method is:
1315%
1316% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1317%
1318% A description of each parameter follows:
1319%
1320% o clone: Specifies a pointer to a Cache structure.
1321%
1322% o cache: the pixel cache.
1323%
1324*/
1325MagickExport void ClonePixelCacheMethods(Cache clone,const Cache cache)
1326{
1327 CacheInfo
1328 *cache_info,
1329 *source_info;
1330
1331 assert(clone != (Cache) NULL);
1332 source_info=(CacheInfo *) clone;
1333 assert(source_info->signature == MagickSignature);
1334 if (source_info->debug != MagickFalse)
1335 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1336 source_info->filename);
1337 assert(cache != (Cache) NULL);
1338 cache_info=(CacheInfo *) cache;
1339 assert(cache_info->signature == MagickSignature);
1340 source_info->methods=cache_info->methods;
1341}
1342
1343/*
1344%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1345% %
1346% %
1347% %
1348+ D e s t r o y I m a g e P i x e l C a c h e %
1349% %
1350% %
1351% %
1352%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1353%
1354% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1355%
1356% The format of the DestroyImagePixelCache() method is:
1357%
1358% void DestroyImagePixelCache(Image *image)
1359%
1360% A description of each parameter follows:
1361%
1362% o image: the image.
1363%
1364*/
1365static void DestroyImagePixelCache(Image *image)
1366{
1367 assert(image != (Image *) NULL);
1368 assert(image->signature == MagickSignature);
1369 if (image->debug != MagickFalse)
1370 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1371 if (image->cache == (void *) NULL)
1372 return;
1373 image->cache=DestroyPixelCache(image->cache);
1374}
1375
1376/*
1377%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1378% %
1379% %
1380% %
1381+ D e s t r o y I m a g e P i x e l s %
1382% %
1383% %
1384% %
1385%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1386%
1387% DestroyImagePixels() deallocates memory associated with the pixel cache.
1388%
1389% The format of the DestroyImagePixels() method is:
1390%
1391% void DestroyImagePixels(Image *image)
1392%
1393% A description of each parameter follows:
1394%
1395% o image: the image.
1396%
1397*/
1398MagickExport void DestroyImagePixels(Image *image)
1399{
1400 CacheInfo
1401 *cache_info;
1402
1403 assert(image != (const Image *) NULL);
1404 assert(image->signature == MagickSignature);
1405 if (image->debug != MagickFalse)
1406 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1407 assert(image->cache != (Cache) NULL);
1408 cache_info=(CacheInfo *) image->cache;
1409 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001410 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1411 {
1412 cache_info->methods.destroy_pixel_handler(image);
1413 return;
1414 }
cristy2036f5c2010-09-19 21:18:17 +00001415 image->cache=DestroyPixelCache(image->cache);
cristy3ed852e2009-09-05 21:47:34 +00001416}
1417
1418/*
1419%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1420% %
1421% %
1422% %
1423+ D e s t r o y P i x e l C a c h e %
1424% %
1425% %
1426% %
1427%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1428%
1429% DestroyPixelCache() deallocates memory associated with the pixel cache.
1430%
1431% The format of the DestroyPixelCache() method is:
1432%
1433% Cache DestroyPixelCache(Cache cache)
1434%
1435% A description of each parameter follows:
1436%
1437% o cache: the pixel cache.
1438%
1439*/
1440
1441static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1442{
1443 switch (cache_info->type)
1444 {
1445 case MemoryCache:
1446 {
1447 if (cache_info->mapped == MagickFalse)
1448 cache_info->pixels=(PixelPacket *) RelinquishMagickMemory(
1449 cache_info->pixels);
1450 else
1451 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,
1452 (size_t) cache_info->length);
1453 RelinquishMagickResource(MemoryResource,cache_info->length);
1454 break;
1455 }
1456 case MapCache:
1457 {
1458 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,(size_t)
1459 cache_info->length);
1460 RelinquishMagickResource(MapResource,cache_info->length);
1461 }
1462 case DiskCache:
1463 {
1464 if (cache_info->file != -1)
1465 (void) ClosePixelCacheOnDisk(cache_info);
1466 RelinquishMagickResource(DiskResource,cache_info->length);
1467 break;
1468 }
1469 default:
1470 break;
1471 }
1472 cache_info->type=UndefinedCache;
1473 cache_info->mapped=MagickFalse;
1474 cache_info->indexes=(IndexPacket *) NULL;
1475}
1476
1477MagickExport Cache DestroyPixelCache(Cache cache)
1478{
1479 CacheInfo
1480 *cache_info;
1481
cristy3ed852e2009-09-05 21:47:34 +00001482 assert(cache != (Cache) NULL);
1483 cache_info=(CacheInfo *) cache;
1484 assert(cache_info->signature == MagickSignature);
1485 if (cache_info->debug != MagickFalse)
1486 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1487 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001488 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001489 cache_info->reference_count--;
1490 if (cache_info->reference_count != 0)
1491 {
cristyf84a1932010-01-03 18:00:18 +00001492 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001493 return((Cache) NULL);
1494 }
cristyf84a1932010-01-03 18:00:18 +00001495 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001496 if (cache_resources != (SplayTreeInfo *) NULL)
1497 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
cristy5b8de732009-09-10 23:50:40 +00001498 if (cache_info->debug != MagickFalse)
1499 {
1500 char
1501 message[MaxTextExtent];
1502
1503 (void) FormatMagickString(message,MaxTextExtent,"destroy %s",
1504 cache_info->filename);
1505 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1506 }
cristyc2e1bdd2009-09-10 23:43:34 +00001507 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1508 (cache_info->type != DiskCache)))
1509 RelinquishPixelCachePixels(cache_info);
1510 else
1511 {
1512 RelinquishPixelCachePixels(cache_info);
1513 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1514 }
cristy3ed852e2009-09-05 21:47:34 +00001515 *cache_info->cache_filename='\0';
1516 if (cache_info->nexus_info != (NexusInfo **) NULL)
1517 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1518 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001519 if (cache_info->random_info != (RandomInfo *) NULL)
1520 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001521 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1522 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1523 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1524 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001525 cache_info->signature=(~MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001526 cache_info=(CacheInfo *) RelinquishAlignedMemory(cache_info);
1527 cache=(Cache) NULL;
1528 return(cache);
1529}
1530
1531/*
1532%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1533% %
1534% %
1535% %
1536+ D e s t r o y P i x e l C a c h e N e x u s %
1537% %
1538% %
1539% %
1540%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1541%
1542% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1543%
1544% The format of the DestroyPixelCacheNexus() method is:
1545%
1546% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001547% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001548%
1549% A description of each parameter follows:
1550%
1551% o nexus_info: the nexus to destroy.
1552%
1553% o number_threads: the number of nexus threads.
1554%
1555*/
1556
1557static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1558{
1559 if (nexus_info->mapped == MagickFalse)
1560 (void) RelinquishMagickMemory(nexus_info->cache);
1561 else
1562 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1563 nexus_info->cache=(PixelPacket *) NULL;
1564 nexus_info->pixels=(PixelPacket *) NULL;
1565 nexus_info->indexes=(IndexPacket *) NULL;
1566 nexus_info->length=0;
1567 nexus_info->mapped=MagickFalse;
1568}
1569
1570MagickExport NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001571 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001572{
cristybb503372010-05-27 20:51:26 +00001573 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001574 i;
1575
1576 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001577 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001578 {
1579 if (nexus_info[i]->cache != (PixelPacket *) NULL)
1580 RelinquishCacheNexusPixels(nexus_info[i]);
1581 nexus_info[i]->signature=(~MagickSignature);
1582 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
1583 }
1584 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
1585 return(nexus_info);
1586}
1587
1588/*
1589%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1590% %
1591% %
1592% %
cristy3ed852e2009-09-05 21:47:34 +00001593+ G e t A u t h e n t i c I n d e x e s F r o m C a c h e %
1594% %
1595% %
1596% %
1597%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1598%
1599% GetAuthenticIndexesFromCache() returns the indexes associated with the last
1600% call to QueueAuthenticPixelsCache() or GetAuthenticPixelsCache().
1601%
1602% The format of the GetAuthenticIndexesFromCache() method is:
1603%
1604% IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1605%
1606% A description of each parameter follows:
1607%
1608% o image: the image.
1609%
1610*/
1611static IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1612{
1613 CacheInfo
1614 *cache_info;
1615
cristy5c9e6f22010-09-17 17:31:01 +00001616 const int
1617 id = GetOpenMPThreadId();
1618
cristy3ed852e2009-09-05 21:47:34 +00001619 cache_info=(CacheInfo *) image->cache;
cristy6ebe97c2010-07-03 01:17:28 +00001620 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001621 return(GetPixelCacheNexusIndexes(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001622}
1623
1624/*
1625%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1626% %
1627% %
1628% %
1629% G e t A u t h e n t i c I n d e x Q u e u e %
1630% %
1631% %
1632% %
1633%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1634%
1635% GetAuthenticIndexQueue() returns the authentic black channel or the colormap
1636% indexes associated with the last call to QueueAuthenticPixels() or
1637% GetVirtualPixels(). NULL is returned if the black channel or colormap
1638% indexes are not available.
1639%
1640% The format of the GetAuthenticIndexQueue() method is:
1641%
1642% IndexPacket *GetAuthenticIndexQueue(const Image *image)
1643%
1644% A description of each parameter follows:
1645%
1646% o image: the image.
1647%
1648*/
1649MagickExport IndexPacket *GetAuthenticIndexQueue(const Image *image)
1650{
1651 CacheInfo
1652 *cache_info;
1653
cristy2036f5c2010-09-19 21:18:17 +00001654 const int
1655 id = GetOpenMPThreadId();
1656
cristy3ed852e2009-09-05 21:47:34 +00001657 assert(image != (const Image *) NULL);
1658 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001659 assert(image->cache != (Cache) NULL);
1660 cache_info=(CacheInfo *) image->cache;
1661 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001662 if (cache_info->methods.get_authentic_indexes_from_handler !=
cristy3ed852e2009-09-05 21:47:34 +00001663 (GetAuthenticIndexesFromHandler) NULL)
cristyd317f372010-09-18 01:42:20 +00001664 return(cache_info->methods.get_authentic_indexes_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001665 assert(id < (int) cache_info->number_threads);
1666 return(GetPixelCacheNexusIndexes(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001667}
1668
1669/*
1670%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1671% %
1672% %
1673% %
1674+ 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 %
1675% %
1676% %
1677% %
1678%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1679%
1680% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1681% disk pixel cache as defined by the geometry parameters. A pointer to the
1682% pixels is returned if the pixels are transferred, otherwise a NULL is
1683% returned.
1684%
1685% The format of the GetAuthenticPixelCacheNexus() method is:
1686%
cristybb503372010-05-27 20:51:26 +00001687% PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1688% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001689% NexusInfo *nexus_info,ExceptionInfo *exception)
1690%
1691% A description of each parameter follows:
1692%
1693% o image: the image.
1694%
1695% o x,y,columns,rows: These values define the perimeter of a region of
1696% pixels.
1697%
1698% o nexus_info: the cache nexus to return.
1699%
1700% o exception: return any errors or warnings in this structure.
1701%
1702*/
1703
1704static inline MagickBooleanType IsNexusInCore(const CacheInfo *cache_info,
1705 NexusInfo *nexus_info)
1706{
1707 MagickOffsetType
1708 offset;
1709
cristy73724512010-04-12 14:43:14 +00001710 if (cache_info->type == PingCache)
1711 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001712 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1713 nexus_info->region.x;
1714 if (nexus_info->pixels != (cache_info->pixels+offset))
1715 return(MagickFalse);
1716 return(MagickTrue);
1717}
1718
cristye076a6e2010-08-15 19:59:43 +00001719MagickExport PixelPacket *GetAuthenticPixelCacheNexus(Image *image,
1720 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001721 NexusInfo *nexus_info,ExceptionInfo *exception)
1722{
1723 CacheInfo
1724 *cache_info;
1725
1726 PixelPacket
1727 *pixels;
1728
1729 /*
1730 Transfer pixels from the cache.
1731 */
1732 assert(image != (Image *) NULL);
1733 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001734 pixels=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
1735 if (pixels == (PixelPacket *) NULL)
1736 return((PixelPacket *) NULL);
1737 cache_info=(CacheInfo *) image->cache;
1738 assert(cache_info->signature == MagickSignature);
1739 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
1740 return(pixels);
1741 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1742 return((PixelPacket *) NULL);
1743 if (cache_info->active_index_channel != MagickFalse)
1744 if (ReadPixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse)
1745 return((PixelPacket *) NULL);
1746 return(pixels);
1747}
1748
1749/*
1750%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1751% %
1752% %
1753% %
1754+ 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 %
1755% %
1756% %
1757% %
1758%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1759%
1760% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1761% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1762%
1763% The format of the GetAuthenticPixelsFromCache() method is:
1764%
1765% PixelPacket *GetAuthenticPixelsFromCache(const Image image)
1766%
1767% A description of each parameter follows:
1768%
1769% o image: the image.
1770%
1771*/
1772static PixelPacket *GetAuthenticPixelsFromCache(const Image *image)
1773{
1774 CacheInfo
1775 *cache_info;
1776
cristy5c9e6f22010-09-17 17:31:01 +00001777 const int
1778 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001779
cristy3ed852e2009-09-05 21:47:34 +00001780 cache_info=(CacheInfo *) image->cache;
cristy6ebe97c2010-07-03 01:17:28 +00001781 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001782 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001783}
1784
1785/*
1786%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1787% %
1788% %
1789% %
1790% G e t A u t h e n t i c P i x e l Q u e u e %
1791% %
1792% %
1793% %
1794%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1795%
1796% GetAuthenticPixelQueue() returns the authentic pixels associated with the
1797% last call to QueueAuthenticPixels() or GetAuthenticPixels().
1798%
1799% The format of the GetAuthenticPixelQueue() method is:
1800%
1801% PixelPacket *GetAuthenticPixelQueue(const Image image)
1802%
1803% A description of each parameter follows:
1804%
1805% o image: the image.
1806%
1807*/
1808MagickExport PixelPacket *GetAuthenticPixelQueue(const Image *image)
1809{
1810 CacheInfo
1811 *cache_info;
1812
cristy2036f5c2010-09-19 21:18:17 +00001813 const int
1814 id = GetOpenMPThreadId();
1815
cristy3ed852e2009-09-05 21:47:34 +00001816 assert(image != (const 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_from_handler !=
1822 (GetAuthenticPixelsFromHandler) NULL)
1823 return(cache_info->methods.get_authentic_pixels_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001824 assert(id < (int) cache_info->number_threads);
1825 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001826}
1827
1828/*
1829%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1830% %
1831% %
1832% %
1833% G e t A u t h e n t i c P i x e l s %
1834% %
1835% %
1836% %
1837%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1838%
1839% GetAuthenticPixels() obtains a pixel region for read/write access. If the
1840% region is successfully accessed, a pointer to a PixelPacket array
1841% representing the region is returned, otherwise NULL is returned.
1842%
1843% The returned pointer may point to a temporary working copy of the pixels
1844% or it may point to the original pixels in memory. Performance is maximized
1845% if the selected region is part of one row, or one or more full rows, since
1846% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001847% if the image is in memory, or in a memory-mapped file. The returned pointer
1848% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001849%
1850% Pixels accessed via the returned pointer represent a simple array of type
1851% PixelPacket. If the image type is CMYK or if the storage class is
1852% PseduoClass, call GetAuthenticIndexQueue() after invoking
1853% GetAuthenticPixels() to obtain the black color component or colormap indexes
1854% (of type IndexPacket) corresponding to the region. Once the PixelPacket
1855% (and/or IndexPacket) array has been updated, the changes must be saved back
1856% to the underlying image using SyncAuthenticPixels() or they may be lost.
1857%
1858% The format of the GetAuthenticPixels() method is:
1859%
cristy5f959472010-05-27 22:19:46 +00001860% PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1861% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001862% ExceptionInfo *exception)
1863%
1864% A description of each parameter follows:
1865%
1866% o image: the image.
1867%
1868% o x,y,columns,rows: These values define the perimeter of a region of
1869% pixels.
1870%
1871% o exception: return any errors or warnings in this structure.
1872%
1873*/
cristybb503372010-05-27 20:51:26 +00001874MagickExport PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1875 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001876 ExceptionInfo *exception)
1877{
1878 CacheInfo
1879 *cache_info;
1880
cristy2036f5c2010-09-19 21:18:17 +00001881 const int
1882 id = GetOpenMPThreadId();
1883
cristy3ed852e2009-09-05 21:47:34 +00001884 assert(image != (Image *) NULL);
1885 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001886 assert(image->cache != (Cache) NULL);
1887 cache_info=(CacheInfo *) image->cache;
1888 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001889 if (cache_info->methods.get_authentic_pixels_handler !=
1890 (GetAuthenticPixelsHandler) NULL)
1891 return(cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1892 rows,exception));
1893 return(GetAuthenticPixelsCache(image,x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00001894 assert(id < (int) cache_info->number_threads);
1895 return(GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1896 cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00001897}
1898
1899/*
1900%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1901% %
1902% %
1903% %
1904+ G e t A u t h e n t i c P i x e l s C a c h e %
1905% %
1906% %
1907% %
1908%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1909%
1910% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1911% as defined by the geometry parameters. A pointer to the pixels is returned
1912% if the pixels are transferred, otherwise a NULL is returned.
1913%
1914% The format of the GetAuthenticPixelsCache() method is:
1915%
cristybb503372010-05-27 20:51:26 +00001916% PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1917% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001918% ExceptionInfo *exception)
1919%
1920% A description of each parameter follows:
1921%
1922% o image: the image.
1923%
1924% o x,y,columns,rows: These values define the perimeter of a region of
1925% pixels.
1926%
1927% o exception: return any errors or warnings in this structure.
1928%
1929*/
cristybb503372010-05-27 20:51:26 +00001930static PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1931 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001932 ExceptionInfo *exception)
1933{
1934 CacheInfo
1935 *cache_info;
1936
cristy5c9e6f22010-09-17 17:31:01 +00001937 const int
1938 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001939
cristy77ff0282010-09-13 00:51:10 +00001940 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001941 if (cache_info == (Cache) NULL)
1942 return((PixelPacket *) NULL);
cristy6ebe97c2010-07-03 01:17:28 +00001943 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001944 return(GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1945 cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00001946}
1947
1948/*
1949%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1950% %
1951% %
1952% %
1953+ G e t I m a g e E x t e n t %
1954% %
1955% %
1956% %
1957%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1958%
1959% GetImageExtent() returns the extent of the pixels associated with the
1960% last call to QueueAuthenticPixels() or GetAuthenticPixels().
1961%
1962% The format of the GetImageExtent() method is:
1963%
1964% MagickSizeType GetImageExtent(const Image *image)
1965%
1966% A description of each parameter follows:
1967%
1968% o image: the image.
1969%
1970*/
1971MagickExport MagickSizeType GetImageExtent(const Image *image)
1972{
1973 CacheInfo
1974 *cache_info;
1975
cristy5c9e6f22010-09-17 17:31:01 +00001976 const int
1977 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001978
cristy3ed852e2009-09-05 21:47:34 +00001979 assert(image != (Image *) NULL);
1980 assert(image->signature == MagickSignature);
1981 if (image->debug != MagickFalse)
1982 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1983 assert(image->cache != (Cache) NULL);
1984 cache_info=(CacheInfo *) image->cache;
1985 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001986 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001987 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001988}
1989
1990/*
1991%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1992% %
1993% %
1994% %
1995+ G e t I m a g e P i x e l C a c h e %
1996% %
1997% %
1998% %
1999%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2000%
2001% GetImagePixelCache() ensures that there is only a single reference to the
2002% pixel cache to be modified, updating the provided cache pointer to point to
2003% a clone of the original pixel cache if necessary.
2004%
2005% The format of the GetImagePixelCache method is:
2006%
2007% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2008% ExceptionInfo *exception)
2009%
2010% A description of each parameter follows:
2011%
2012% o image: the image.
2013%
2014% o clone: any value other than MagickFalse clones the cache pixels.
2015%
2016% o exception: return any errors or warnings in this structure.
2017%
2018*/
cristy3ed852e2009-09-05 21:47:34 +00002019static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
2020{
2021 CacheInfo
2022 *cache_info;
2023
2024 /*
2025 Does the image match the pixel cache morphology?
2026 */
2027 cache_info=(CacheInfo *) image->cache;
2028 if ((image->storage_class != cache_info->storage_class) ||
2029 (image->colorspace != cache_info->colorspace) ||
2030 (image->columns != cache_info->columns) ||
2031 (image->rows != cache_info->rows) ||
2032 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2033 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2034 return(MagickFalse);
2035 return(MagickTrue);
2036}
2037
cristy77ff0282010-09-13 00:51:10 +00002038static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2039 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002040{
2041 CacheInfo
2042 *cache_info;
2043
cristy3ed852e2009-09-05 21:47:34 +00002044 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00002045 destroy,
cristy3ed852e2009-09-05 21:47:34 +00002046 status;
2047
cristy50a10922010-02-15 18:35:25 +00002048 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00002049 cpu_throttle = 0,
2050 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00002051 time_limit = 0;
2052
cristy1ea34962010-07-01 19:49:21 +00002053 static time_t
cristya21afde2010-07-02 00:45:40 +00002054 cache_genesis = 0;
cristy1ea34962010-07-01 19:49:21 +00002055
cristyc4f9f132010-03-04 18:50:01 +00002056 status=MagickTrue;
2057 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00002058 if (cpu_throttle == 0)
2059 {
2060 char
2061 *limit;
2062
2063 /*
2064 Set CPU throttle in milleseconds.
2065 */
2066 cpu_throttle=MagickResourceInfinity;
2067 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2068 if (limit == (char *) NULL)
2069 limit=GetPolicyValue("throttle");
2070 if (limit != (char *) NULL)
2071 {
2072 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2073 limit=DestroyString(limit);
2074 }
2075 }
2076 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2077 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00002078 if (time_limit == 0)
2079 {
cristy6ebe97c2010-07-03 01:17:28 +00002080 /*
2081 Set the exire time in seconds.
2082 */
cristy1ea34962010-07-01 19:49:21 +00002083 time_limit=GetMagickResourceLimit(TimeResource);
cristya21afde2010-07-02 00:45:40 +00002084 cache_genesis=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00002085 }
2086 if ((time_limit != MagickResourceInfinity) &&
cristya21afde2010-07-02 00:45:40 +00002087 ((MagickSizeType) (time((time_t *) NULL)-cache_genesis) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00002088 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00002089 assert(image->cache != (Cache) NULL);
2090 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002091 destroy=MagickFalse;
cristy01b7eb02009-09-10 23:10:14 +00002092 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002093 {
cristyaaa0cb62010-02-15 17:47:27 +00002094 LockSemaphoreInfo(cache_info->semaphore);
2095 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002096 {
cristyaaa0cb62010-02-15 17:47:27 +00002097 Image
2098 clone_image;
2099
2100 CacheInfo
2101 *clone_info;
2102
2103 /*
2104 Clone pixel cache.
2105 */
2106 clone_image=(*image);
cristy93505cf2010-08-10 21:37:49 +00002107 clone_image.semaphore=AllocateSemaphoreInfo();
2108 clone_image.reference_count=1;
cristyaaa0cb62010-02-15 17:47:27 +00002109 clone_image.cache=ClonePixelCache(cache_info);
2110 clone_info=(CacheInfo *) clone_image.cache;
cristyabd6e372010-09-15 19:11:26 +00002111 status=OpenPixelCache(&clone_image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00002112 if (status != MagickFalse)
2113 {
cristyabd6e372010-09-15 19:11:26 +00002114 if (clone != MagickFalse)
2115 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002116 if (status != MagickFalse)
2117 {
cristyabd6e372010-09-15 19:11:26 +00002118 destroy=MagickTrue;
2119 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00002120 }
2121 }
cristy93505cf2010-08-10 21:37:49 +00002122 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002123 }
cristyaaa0cb62010-02-15 17:47:27 +00002124 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002125 }
cristy4320e0e2009-09-10 15:00:08 +00002126 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002127 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002128 if (status != MagickFalse)
2129 {
2130 /*
2131 Ensure the image matches the pixel cache morphology.
2132 */
2133 image->taint=MagickTrue;
2134 image->type=UndefinedType;
cristydd438462010-05-06 13:44:04 +00002135 if (image->colorspace == GRAYColorspace)
2136 image->colorspace=RGBColorspace;
cristy3ed852e2009-09-05 21:47:34 +00002137 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2138 status=OpenPixelCache(image,IOMode,exception);
2139 }
cristyf84a1932010-01-03 18:00:18 +00002140 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002141 if (status == MagickFalse)
2142 return((Cache) NULL);
2143 return(image->cache);
2144}
2145
2146/*
2147%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2148% %
2149% %
2150% %
2151% G e t O n e A u t h e n t i c P i x e l %
2152% %
2153% %
2154% %
2155%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2156%
2157% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2158% location. The image background color is returned if an error occurs.
2159%
2160% The format of the GetOneAuthenticPixel() method is:
2161%
cristybb503372010-05-27 20:51:26 +00002162% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2163% const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002164%
2165% A description of each parameter follows:
2166%
2167% o image: the image.
2168%
2169% o x,y: These values define the location of the pixel to return.
2170%
2171% o pixel: return a pixel at the specified (x,y) location.
2172%
2173% o exception: return any errors or warnings in this structure.
2174%
2175*/
cristyacbbb7c2010-06-30 18:56:48 +00002176MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2177 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002178{
2179 CacheInfo
2180 *cache_info;
2181
cristy2036f5c2010-09-19 21:18:17 +00002182 PixelPacket
2183 *pixels;
2184
cristy3ed852e2009-09-05 21:47:34 +00002185 assert(image != (Image *) NULL);
2186 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002187 assert(image->cache != (Cache) NULL);
2188 cache_info=(CacheInfo *) image->cache;
2189 assert(cache_info->signature == MagickSignature);
2190 *pixel=image->background_color;
cristyd317f372010-09-18 01:42:20 +00002191 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2192 (GetOneAuthenticPixelFromHandler) NULL)
2193 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2194 pixel,exception));
cristy2036f5c2010-09-19 21:18:17 +00002195 *pixel=image->background_color;
2196 pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2197 if (pixels == (PixelPacket *) NULL)
2198 return(MagickFalse);
2199 *pixel=(*pixels);
2200 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002201}
2202
2203/*
2204%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2205% %
2206% %
2207% %
2208+ 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 %
2209% %
2210% %
2211% %
2212%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2213%
2214% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2215% location. The image background color is returned if an error occurs.
2216%
2217% The format of the GetOneAuthenticPixelFromCache() method is:
2218%
2219% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy5f959472010-05-27 22:19:46 +00002220% const ssize_t x,const ssize_t y,PixelPacket *pixel,
2221% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002222%
2223% A description of each parameter follows:
2224%
2225% o image: the image.
2226%
2227% o x,y: These values define the location of the pixel to return.
2228%
2229% o pixel: return a pixel at the specified (x,y) location.
2230%
2231% o exception: return any errors or warnings in this structure.
2232%
2233*/
2234static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristybb503372010-05-27 20:51:26 +00002235 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002236{
2237 PixelPacket
2238 *pixels;
2239
cristy3ed852e2009-09-05 21:47:34 +00002240 *pixel=image->background_color;
2241 pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2242 if (pixels == (PixelPacket *) NULL)
2243 return(MagickFalse);
2244 *pixel=(*pixels);
2245 return(MagickTrue);
2246}
2247
2248/*
2249%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2250% %
2251% %
2252% %
2253% G e t O n e V i r t u a l M a g i c k P i x e l %
2254% %
2255% %
2256% %
2257%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2258%
2259% GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2260% location. The image background color is returned if an error occurs. If
2261% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2262%
2263% The format of the GetOneVirtualMagickPixel() method is:
2264%
2265% MagickBooleanType GetOneVirtualMagickPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002266% const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
cristy3ed852e2009-09-05 21:47:34 +00002267% ExceptionInfo exception)
2268%
2269% A description of each parameter follows:
2270%
2271% o image: the image.
2272%
2273% o x,y: these values define the location of the pixel to return.
2274%
2275% o pixel: return a pixel at the specified (x,y) location.
2276%
2277% o exception: return any errors or warnings in this structure.
2278%
2279*/
2280MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
cristyacbbb7c2010-06-30 18:56:48 +00002281 const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
2282 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002283{
2284 CacheInfo
2285 *cache_info;
2286
2287 register const IndexPacket
2288 *indexes;
2289
2290 register const PixelPacket
2291 *p;
2292
2293 assert(image != (const Image *) NULL);
2294 assert(image->signature == MagickSignature);
2295 assert(image->cache != (Cache) NULL);
2296 cache_info=(CacheInfo *) image->cache;
2297 assert(cache_info->signature == MagickSignature);
2298 GetMagickPixelPacket(image,pixel);
2299 p=GetVirtualPixelCache(image,GetPixelCacheVirtualMethod(image),x,y,1,1,
2300 exception);
2301 if (p == (const PixelPacket *) NULL)
2302 return(MagickFalse);
2303 indexes=GetVirtualIndexQueue(image);
2304 SetMagickPixelPacket(image,p,indexes,pixel);
2305 return(MagickTrue);
2306}
2307
2308/*
2309%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2310% %
2311% %
2312% %
2313% G e t O n e V i r t u a l M e t h o d P i x e l %
2314% %
2315% %
2316% %
2317%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2318%
2319% GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2320% location as defined by specified pixel method. The image background color
2321% is returned if an error occurs. If you plan to modify the pixel, use
2322% GetOneAuthenticPixel() instead.
2323%
2324% The format of the GetOneVirtualMethodPixel() method is:
2325%
2326% MagickBooleanType GetOneVirtualMethodPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002327% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2328% const ssize_t y,Pixelpacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002329%
2330% A description of each parameter follows:
2331%
2332% o image: the image.
2333%
2334% o virtual_pixel_method: the virtual pixel method.
2335%
2336% o x,y: These values define the location of the pixel to return.
2337%
2338% o pixel: return a pixel at the specified (x,y) location.
2339%
2340% o exception: return any errors or warnings in this structure.
2341%
2342*/
2343MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002344 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002345 PixelPacket *pixel,ExceptionInfo *exception)
2346{
cristy3ed852e2009-09-05 21:47:34 +00002347 CacheInfo
2348 *cache_info;
2349
cristy2036f5c2010-09-19 21:18:17 +00002350 const PixelPacket
2351 *pixels;
2352
cristy3ed852e2009-09-05 21:47:34 +00002353 assert(image != (const Image *) NULL);
2354 assert(image->signature == MagickSignature);
2355 assert(image->cache != (Cache) NULL);
2356 cache_info=(CacheInfo *) image->cache;
2357 assert(cache_info->signature == MagickSignature);
2358 *pixel=image->background_color;
cristyd317f372010-09-18 01:42:20 +00002359 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2360 (GetOneVirtualPixelFromHandler) NULL)
2361 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2362 virtual_pixel_method,x,y,pixel,exception));
cristy2036f5c2010-09-19 21:18:17 +00002363 *pixel=image->background_color;
2364 pixels=GetVirtualPixelCache(image,virtual_pixel_method,x,y,1UL,1UL,exception);
2365 if (pixels == (const PixelPacket *) NULL)
2366 return(MagickFalse);
2367 *pixel=(*pixels);
2368 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002369}
2370
2371/*
2372%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2373% %
2374% %
2375% %
2376% G e t O n e V i r t u a l P i x e l %
2377% %
2378% %
2379% %
2380%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2381%
2382% GetOneVirtualPixel() returns a single virtual pixel at the specified
2383% (x,y) location. The image background color is returned if an error occurs.
2384% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2385%
2386% The format of the GetOneVirtualPixel() method is:
2387%
cristybb503372010-05-27 20:51:26 +00002388% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2389% const ssize_t y,PixelPacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002390%
2391% A description of each parameter follows:
2392%
2393% o image: the image.
2394%
2395% o x,y: These values define the location of the pixel to return.
2396%
2397% o pixel: return a pixel at the specified (x,y) location.
2398%
2399% o exception: return any errors or warnings in this structure.
2400%
2401*/
2402MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002403 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002404{
cristy3ed852e2009-09-05 21:47:34 +00002405 CacheInfo
2406 *cache_info;
2407
cristy2036f5c2010-09-19 21:18:17 +00002408 const PixelPacket
2409 *pixels;
2410
cristy3ed852e2009-09-05 21:47:34 +00002411 assert(image != (const Image *) NULL);
2412 assert(image->signature == MagickSignature);
2413 assert(image->cache != (Cache) NULL);
2414 cache_info=(CacheInfo *) image->cache;
2415 assert(cache_info->signature == MagickSignature);
2416 *pixel=image->background_color;
cristyd317f372010-09-18 01:42:20 +00002417 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2418 (GetOneVirtualPixelFromHandler) NULL)
2419 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2420 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
2421 return(GetOneVirtualPixelFromCache(image,GetPixelCacheVirtualMethod(image),
2422 x,y,pixel,exception));
cristy2036f5c2010-09-19 21:18:17 +00002423 *pixel=image->background_color;
2424 pixels=GetVirtualPixelCache(image,GetPixelCacheVirtualMethod(image),x,y,
2425 1UL,1UL,exception);
2426 if (pixels == (const PixelPacket *) NULL)
2427 return(MagickFalse);
2428 *pixel=(*pixels);
2429 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002430}
2431
2432/*
2433%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2434% %
2435% %
2436% %
2437+ 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 %
2438% %
2439% %
2440% %
2441%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2442%
2443% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2444% specified (x,y) location. The image background color is returned if an
2445% error occurs.
2446%
2447% The format of the GetOneVirtualPixelFromCache() method is:
2448%
2449% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristybb503372010-05-27 20:51:26 +00002450% const VirtualPixelPacket method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002451% PixelPacket *pixel,ExceptionInfo *exception)
2452%
2453% A description of each parameter follows:
2454%
2455% o image: the image.
2456%
2457% o virtual_pixel_method: the virtual pixel method.
2458%
2459% o x,y: These values define the location of the pixel to return.
2460%
2461% o pixel: return a pixel at the specified (x,y) location.
2462%
2463% o exception: return any errors or warnings in this structure.
2464%
2465*/
2466static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002467 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002468 PixelPacket *pixel,ExceptionInfo *exception)
2469{
2470 const PixelPacket
2471 *pixels;
2472
2473 *pixel=image->background_color;
2474 pixels=GetVirtualPixelCache(image,virtual_pixel_method,x,y,1UL,1UL,exception);
2475 if (pixels == (const PixelPacket *) NULL)
2476 return(MagickFalse);
2477 *pixel=(*pixels);
2478 return(MagickTrue);
2479}
2480
2481/*
2482%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2483% %
2484% %
2485% %
2486+ G e t P i x e l C a c h e C o l o r s p a c e %
2487% %
2488% %
2489% %
2490%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2491%
2492% GetPixelCacheColorspace() returns the class type of the pixel cache.
2493%
2494% The format of the GetPixelCacheColorspace() method is:
2495%
2496% Colorspace GetPixelCacheColorspace(Cache cache)
2497%
2498% A description of each parameter follows:
2499%
2500% o cache: the pixel cache.
2501%
2502*/
2503MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
2504{
2505 CacheInfo
2506 *cache_info;
2507
2508 assert(cache != (Cache) NULL);
2509 cache_info=(CacheInfo *) cache;
2510 assert(cache_info->signature == MagickSignature);
2511 if (cache_info->debug != MagickFalse)
2512 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2513 cache_info->filename);
2514 return(cache_info->colorspace);
2515}
2516
2517/*
2518%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2519% %
2520% %
2521% %
2522+ G e t P i x e l C a c h e M e t h o d s %
2523% %
2524% %
2525% %
2526%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2527%
2528% GetPixelCacheMethods() initializes the CacheMethods structure.
2529%
2530% The format of the GetPixelCacheMethods() method is:
2531%
2532% void GetPixelCacheMethods(CacheMethods *cache_methods)
2533%
2534% A description of each parameter follows:
2535%
2536% o cache_methods: Specifies a pointer to a CacheMethods structure.
2537%
2538*/
2539MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
2540{
2541 assert(cache_methods != (CacheMethods *) NULL);
2542 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2543 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2544 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2545 cache_methods->get_virtual_indexes_from_handler=GetVirtualIndexesFromCache;
2546 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2547 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2548 cache_methods->get_authentic_indexes_from_handler=
2549 GetAuthenticIndexesFromCache;
2550 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2551 cache_methods->get_one_authentic_pixel_from_handler=
2552 GetOneAuthenticPixelFromCache;
2553 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2554 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2555 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2556}
2557
2558/*
2559%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2560% %
2561% %
2562% %
2563+ G e t P i x e l C a c h e N e x u s E x t e n t %
2564% %
2565% %
2566% %
2567%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2568%
2569% GetPixelCacheNexusExtent() returns the extent of the pixels associated with
2570% the last call to SetPixelCacheNexusPixels() or GetPixelCacheNexusPixels().
2571%
2572% The format of the GetPixelCacheNexusExtent() method is:
2573%
2574% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2575% NexusInfo *nexus_info)
2576%
2577% A description of each parameter follows:
2578%
2579% o nexus_info: the nexus info.
2580%
2581*/
2582MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2583 NexusInfo *nexus_info)
2584{
2585 CacheInfo
2586 *cache_info;
2587
2588 MagickSizeType
2589 extent;
2590
2591 if (cache == (Cache) NULL)
2592 return(0);
2593 cache_info=(CacheInfo *) cache;
2594 assert(cache_info->signature == MagickSignature);
2595 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2596 if (extent == 0)
2597 return((MagickSizeType) cache_info->columns*cache_info->rows);
2598 return(extent);
2599}
2600
2601/*
2602%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2603% %
2604% %
2605% %
2606+ G e t P i x e l C a c h e N e x u s I n d e x e s %
2607% %
2608% %
2609% %
2610%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2611%
2612% GetPixelCacheNexusIndexes() returns the indexes associated with the
2613% specified cache nexus.
2614%
2615% The format of the GetPixelCacheNexusIndexes() method is:
2616%
2617% IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2618% NexusInfo *nexus_info)
2619%
2620% A description of each parameter follows:
2621%
2622% o cache: the pixel cache.
2623%
2624% o nexus_info: the cache nexus to return the colormap indexes.
2625%
2626*/
2627MagickExport IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2628 NexusInfo *nexus_info)
2629{
2630 CacheInfo
2631 *cache_info;
2632
2633 if (cache == (Cache) NULL)
2634 return((IndexPacket *) NULL);
2635 cache_info=(CacheInfo *) cache;
2636 assert(cache_info->signature == MagickSignature);
2637 if (cache_info->storage_class == UndefinedClass)
2638 return((IndexPacket *) NULL);
2639 return(nexus_info->indexes);
2640}
2641
2642/*
2643%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2644% %
2645% %
2646% %
2647+ G e t P i x e l C a c h e N e x u s P i x e l s %
2648% %
2649% %
2650% %
2651%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2652%
2653% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2654% cache nexus.
2655%
2656% The format of the GetPixelCacheNexusPixels() method is:
2657%
2658% PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2659% NexusInfo *nexus_info)
2660%
2661% A description of each parameter follows:
2662%
2663% o cache: the pixel cache.
2664%
2665% o nexus_info: the cache nexus to return the pixels.
2666%
2667*/
2668MagickExport PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2669 NexusInfo *nexus_info)
2670{
2671 CacheInfo
2672 *cache_info;
2673
2674 if (cache == (Cache) NULL)
2675 return((PixelPacket *) NULL);
2676 cache_info=(CacheInfo *) cache;
2677 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002678 if (cache_info->storage_class == UndefinedClass)
2679 return((PixelPacket *) NULL);
2680 return(nexus_info->pixels);
2681}
2682
2683/*
2684%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2685% %
2686% %
2687% %
cristy056ba772010-01-02 23:33:54 +00002688+ G e t P i x e l C a c h e P i x e l s %
2689% %
2690% %
2691% %
2692%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2693%
2694% GetPixelCachePixels() returns the pixels associated with the specified image.
2695%
2696% The format of the GetPixelCachePixels() method is:
2697%
cristyf84a1932010-01-03 18:00:18 +00002698% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2699% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002700%
2701% A description of each parameter follows:
2702%
2703% o image: the image.
2704%
2705% o length: the pixel cache length.
2706%
cristyf84a1932010-01-03 18:00:18 +00002707% o exception: return any errors or warnings in this structure.
2708%
cristy056ba772010-01-02 23:33:54 +00002709*/
cristyf84a1932010-01-03 18:00:18 +00002710MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2711 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002712{
2713 CacheInfo
2714 *cache_info;
2715
2716 assert(image != (const Image *) NULL);
2717 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002718 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00002719 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002720 assert(cache_info->signature == MagickSignature);
2721 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002722 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002723 return((void *) NULL);
2724 *length=cache_info->length;
2725 return((void *) cache_info->pixels);
2726}
2727
2728/*
2729%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2730% %
2731% %
2732% %
cristyb32b90a2009-09-07 21:45:48 +00002733+ 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 +00002734% %
2735% %
2736% %
2737%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2738%
2739% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2740%
2741% The format of the GetPixelCacheStorageClass() method is:
2742%
2743% ClassType GetPixelCacheStorageClass(Cache cache)
2744%
2745% A description of each parameter follows:
2746%
2747% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2748%
2749% o cache: the pixel cache.
2750%
2751*/
2752MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
2753{
2754 CacheInfo
2755 *cache_info;
2756
2757 assert(cache != (Cache) NULL);
2758 cache_info=(CacheInfo *) cache;
2759 assert(cache_info->signature == MagickSignature);
2760 if (cache_info->debug != MagickFalse)
2761 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2762 cache_info->filename);
2763 return(cache_info->storage_class);
2764}
2765
2766/*
2767%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2768% %
2769% %
2770% %
cristyb32b90a2009-09-07 21:45:48 +00002771+ G e t P i x e l C a c h e T i l e S i z e %
2772% %
2773% %
2774% %
2775%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2776%
2777% GetPixelCacheTileSize() returns the pixel cache tile size.
2778%
2779% The format of the GetPixelCacheTileSize() method is:
2780%
cristybb503372010-05-27 20:51:26 +00002781% void GetPixelCacheTileSize(const Image *image,size_t *width,
2782% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002783%
2784% A description of each parameter follows:
2785%
2786% o image: the image.
2787%
2788% o width: the optimize cache tile width in pixels.
2789%
2790% o height: the optimize cache tile height in pixels.
2791%
2792*/
cristybb503372010-05-27 20:51:26 +00002793MagickExport void GetPixelCacheTileSize(const Image *image,size_t *width,
2794 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002795{
2796 CacheInfo
2797 *cache_info;
2798
2799 assert(image != (Image *) NULL);
2800 assert(image->signature == MagickSignature);
2801 if (image->debug != MagickFalse)
2802 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2803 assert(image->cache != (Cache) NULL);
2804 cache_info=(CacheInfo *) image->cache;
2805 assert(cache_info->signature == MagickSignature);
2806 *width=2048UL/sizeof(PixelPacket);
2807 if (GetPixelCacheType(image) == DiskCache)
cristydaa97692009-09-13 02:10:35 +00002808 *width=8192UL/sizeof(PixelPacket);
cristyb32b90a2009-09-07 21:45:48 +00002809 *height=(*width);
2810}
2811
2812/*
2813%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2814% %
2815% %
2816% %
2817+ G e t P i x e l C a c h e T y p e %
2818% %
2819% %
2820% %
2821%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2822%
2823% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2824%
2825% The format of the GetPixelCacheType() method is:
2826%
2827% CacheType GetPixelCacheType(const Image *image)
2828%
2829% A description of each parameter follows:
2830%
2831% o image: the image.
2832%
2833*/
2834MagickExport CacheType GetPixelCacheType(const Image *image)
2835{
2836 CacheInfo
2837 *cache_info;
2838
2839 assert(image != (Image *) NULL);
2840 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002841 assert(image->cache != (Cache) NULL);
2842 cache_info=(CacheInfo *) image->cache;
2843 assert(cache_info->signature == MagickSignature);
2844 return(cache_info->type);
2845}
2846
2847/*
2848%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2849% %
2850% %
2851% %
cristy3ed852e2009-09-05 21:47:34 +00002852+ 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 %
2853% %
2854% %
2855% %
2856%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2857%
2858% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2859% pixel cache. A virtual pixel is any pixel access that is outside the
2860% boundaries of the image cache.
2861%
2862% The format of the GetPixelCacheVirtualMethod() method is:
2863%
2864% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2865%
2866% A description of each parameter follows:
2867%
2868% o image: the image.
2869%
2870*/
2871MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2872{
2873 CacheInfo
2874 *cache_info;
2875
2876 assert(image != (Image *) NULL);
2877 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002878 assert(image->cache != (Cache) NULL);
2879 cache_info=(CacheInfo *) image->cache;
2880 assert(cache_info->signature == MagickSignature);
2881 return(cache_info->virtual_pixel_method);
2882}
2883
2884/*
2885%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2886% %
2887% %
2888% %
2889+ G e t V i r t u a l I n d e x e s F r o m C a c h e %
2890% %
2891% %
2892% %
2893%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2894%
2895% GetVirtualIndexesFromCache() returns the indexes associated with the last
2896% call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2897%
2898% The format of the GetVirtualIndexesFromCache() method is:
2899%
2900% IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2901%
2902% A description of each parameter follows:
2903%
2904% o image: the image.
2905%
2906*/
2907static const IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2908{
2909 CacheInfo
2910 *cache_info;
2911
cristy5c9e6f22010-09-17 17:31:01 +00002912 const int
2913 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002914
cristy3ed852e2009-09-05 21:47:34 +00002915 cache_info=(CacheInfo *) image->cache;
cristy6ebe97c2010-07-03 01:17:28 +00002916 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00002917 return(GetVirtualIndexesFromNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00002918}
2919
2920/*
2921%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2922% %
2923% %
2924% %
2925+ G e t V i r t u a l I n d e x e s F r o m N e x u s %
2926% %
2927% %
2928% %
2929%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2930%
2931% GetVirtualIndexesFromNexus() returns the indexes associated with the
2932% specified cache nexus.
2933%
2934% The format of the GetVirtualIndexesFromNexus() method is:
2935%
2936% const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2937% NexusInfo *nexus_info)
2938%
2939% A description of each parameter follows:
2940%
2941% o cache: the pixel cache.
2942%
2943% o nexus_info: the cache nexus to return the colormap indexes.
2944%
2945*/
2946MagickExport const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2947 NexusInfo *nexus_info)
2948{
2949 CacheInfo
2950 *cache_info;
2951
2952 if (cache == (Cache) NULL)
2953 return((IndexPacket *) NULL);
2954 cache_info=(CacheInfo *) cache;
2955 assert(cache_info->signature == MagickSignature);
2956 if (cache_info->storage_class == UndefinedClass)
2957 return((IndexPacket *) NULL);
2958 return(nexus_info->indexes);
2959}
2960
2961/*
2962%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2963% %
2964% %
2965% %
2966% G e t V i r t u a l I n d e x Q u e u e %
2967% %
2968% %
2969% %
2970%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2971%
2972% GetVirtualIndexQueue() returns the virtual black channel or the
2973% colormap indexes associated with the last call to QueueAuthenticPixels() or
2974% GetVirtualPixels(). NULL is returned if the black channel or colormap
2975% indexes are not available.
2976%
2977% The format of the GetVirtualIndexQueue() method is:
2978%
2979% const IndexPacket *GetVirtualIndexQueue(const Image *image)
2980%
2981% A description of each parameter follows:
2982%
2983% o image: the image.
2984%
2985*/
2986MagickExport const IndexPacket *GetVirtualIndexQueue(const Image *image)
2987{
2988 CacheInfo
2989 *cache_info;
2990
cristy2036f5c2010-09-19 21:18:17 +00002991 const int
2992 id = GetOpenMPThreadId();
2993
cristy3ed852e2009-09-05 21:47:34 +00002994 assert(image != (const Image *) NULL);
2995 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002996 assert(image->cache != (Cache) NULL);
2997 cache_info=(CacheInfo *) image->cache;
2998 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00002999 if (cache_info->methods.get_virtual_indexes_from_handler !=
3000 (GetVirtualIndexesFromHandler) NULL)
3001 return(cache_info->methods.get_virtual_indexes_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003002 assert(id < (int) cache_info->number_threads);
3003 return(GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003004}
3005
3006/*
3007%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3008% %
3009% %
3010% %
3011+ 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 %
3012% %
3013% %
3014% %
3015%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3016%
3017% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3018% pixel cache as defined by the geometry parameters. A pointer to the pixels
3019% is returned if the pixels are transferred, otherwise a NULL is returned.
3020%
3021% The format of the GetVirtualPixelsFromNexus() method is:
3022%
3023% PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003024% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00003025% const size_t columns,const size_t rows,NexusInfo *nexus_info,
3026% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003027%
3028% A description of each parameter follows:
3029%
3030% o image: the image.
3031%
3032% o virtual_pixel_method: the virtual pixel method.
3033%
3034% o x,y,columns,rows: These values define the perimeter of a region of
3035% pixels.
3036%
3037% o nexus_info: the cache nexus to acquire.
3038%
3039% o exception: return any errors or warnings in this structure.
3040%
3041*/
3042
cristybb503372010-05-27 20:51:26 +00003043static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003044 DitherMatrix[64] =
3045 {
3046 0, 48, 12, 60, 3, 51, 15, 63,
3047 32, 16, 44, 28, 35, 19, 47, 31,
3048 8, 56, 4, 52, 11, 59, 7, 55,
3049 40, 24, 36, 20, 43, 27, 39, 23,
3050 2, 50, 14, 62, 1, 49, 13, 61,
3051 34, 18, 46, 30, 33, 17, 45, 29,
3052 10, 58, 6, 54, 9, 57, 5, 53,
3053 42, 26, 38, 22, 41, 25, 37, 21
3054 };
3055
cristybb503372010-05-27 20:51:26 +00003056static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003057{
cristybb503372010-05-27 20:51:26 +00003058 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003059 index;
3060
3061 index=x+DitherMatrix[x & 0x07]-32L;
3062 if (index < 0L)
3063 return(0L);
cristybb503372010-05-27 20:51:26 +00003064 if (index >= (ssize_t) columns)
3065 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00003066 return(index);
3067}
3068
cristybb503372010-05-27 20:51:26 +00003069static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003070{
cristybb503372010-05-27 20:51:26 +00003071 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003072 index;
3073
3074 index=y+DitherMatrix[y & 0x07]-32L;
3075 if (index < 0L)
3076 return(0L);
cristybb503372010-05-27 20:51:26 +00003077 if (index >= (ssize_t) rows)
3078 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00003079 return(index);
3080}
3081
cristybb503372010-05-27 20:51:26 +00003082static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003083{
3084 if (x < 0L)
3085 return(0L);
cristybb503372010-05-27 20:51:26 +00003086 if (x >= (ssize_t) columns)
3087 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003088 return(x);
3089}
3090
cristybb503372010-05-27 20:51:26 +00003091static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003092{
3093 if (y < 0L)
3094 return(0L);
cristybb503372010-05-27 20:51:26 +00003095 if (y >= (ssize_t) rows)
3096 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003097 return(y);
3098}
3099
cristybb503372010-05-27 20:51:26 +00003100static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003101{
cristybb503372010-05-27 20:51:26 +00003102 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003103}
3104
cristybb503372010-05-27 20:51:26 +00003105static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003106{
cristybb503372010-05-27 20:51:26 +00003107 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003108}
3109
3110/*
3111 VirtualPixelModulo() computes the remainder of dividing offset by extent. It
3112 returns not only the quotient (tile the offset falls in) but also the positive
3113 remainer within that tile such that 0 <= remainder < extent. This method is
3114 essentially a ldiv() using a floored modulo division rather than the normal
3115 default truncated modulo division.
3116*/
cristybb503372010-05-27 20:51:26 +00003117static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3118 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003119{
3120 MagickModulo
3121 modulo;
3122
cristybb503372010-05-27 20:51:26 +00003123 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003124 if (offset < 0L)
3125 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003126 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003127 return(modulo);
3128}
3129
3130MagickExport const PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003131 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3132 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003133 ExceptionInfo *exception)
3134{
3135 CacheInfo
3136 *cache_info;
3137
cristyc3ec0d42010-04-07 01:18:08 +00003138 IndexPacket
3139 virtual_index;
3140
cristy3ed852e2009-09-05 21:47:34 +00003141 MagickOffsetType
3142 offset;
3143
3144 MagickSizeType
3145 length,
3146 number_pixels;
3147
3148 NexusInfo
3149 **virtual_nexus;
3150
3151 PixelPacket
3152 *pixels,
3153 virtual_pixel;
3154
3155 RectangleInfo
3156 region;
3157
3158 register const IndexPacket
cristyc3ec0d42010-04-07 01:18:08 +00003159 *restrict virtual_indexes;
cristy3ed852e2009-09-05 21:47:34 +00003160
3161 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003162 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003163
3164 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003165 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003166
cristye076a6e2010-08-15 19:59:43 +00003167 register PixelPacket
3168 *restrict q;
3169
cristybb503372010-05-27 20:51:26 +00003170 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003171 u,
3172 v;
3173
cristy3ed852e2009-09-05 21:47:34 +00003174 /*
3175 Acquire pixels.
3176 */
cristy3ed852e2009-09-05 21:47:34 +00003177 cache_info=(CacheInfo *) image->cache;
cristy4cfbb3f2010-03-14 20:40:23 +00003178 if (cache_info->type == UndefinedCache)
cristy3ed852e2009-09-05 21:47:34 +00003179 return((const PixelPacket *) NULL);
3180 region.x=x;
3181 region.y=y;
3182 region.width=columns;
3183 region.height=rows;
3184 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
3185 if (pixels == (PixelPacket *) NULL)
3186 return((const PixelPacket *) NULL);
cristydf415c82010-03-11 16:47:50 +00003187 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3188 nexus_info->region.x;
3189 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3190 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003191 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3192 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003193 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3194 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003195 {
3196 MagickBooleanType
3197 status;
3198
3199 /*
3200 Pixel request is inside cache extents.
3201 */
3202 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
3203 return(pixels);
3204 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3205 if (status == MagickFalse)
3206 return((const PixelPacket *) NULL);
3207 if ((cache_info->storage_class == PseudoClass) ||
3208 (cache_info->colorspace == CMYKColorspace))
3209 {
3210 status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
3211 if (status == MagickFalse)
3212 return((const PixelPacket *) NULL);
3213 }
3214 return(pixels);
3215 }
3216 /*
3217 Pixel request is outside cache extents.
3218 */
3219 q=pixels;
3220 indexes=GetPixelCacheNexusIndexes(cache_info,nexus_info);
3221 virtual_nexus=AcquirePixelCacheNexus(1);
3222 if (virtual_nexus == (NexusInfo **) NULL)
3223 {
3224 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3225 "UnableToGetCacheNexus","`%s'",image->filename);
3226 return((const PixelPacket *) NULL);
3227 }
3228 switch (virtual_pixel_method)
3229 {
3230 case BlackVirtualPixelMethod:
3231 {
cristy4789f0d2010-01-10 00:01:06 +00003232 SetRedPixelComponent(&virtual_pixel,0);
3233 SetGreenPixelComponent(&virtual_pixel,0);
3234 SetBluePixelComponent(&virtual_pixel,0);
3235 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003236 break;
3237 }
3238 case GrayVirtualPixelMethod:
3239 {
cristy4789f0d2010-01-10 00:01:06 +00003240 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3241 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3242 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3243 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003244 break;
3245 }
3246 case TransparentVirtualPixelMethod:
3247 {
cristy4789f0d2010-01-10 00:01:06 +00003248 SetRedPixelComponent(&virtual_pixel,0);
3249 SetGreenPixelComponent(&virtual_pixel,0);
3250 SetBluePixelComponent(&virtual_pixel,0);
3251 SetOpacityPixelComponent(&virtual_pixel,TransparentOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003252 break;
3253 }
3254 case MaskVirtualPixelMethod:
3255 case WhiteVirtualPixelMethod:
3256 {
cristy4789f0d2010-01-10 00:01:06 +00003257 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3258 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3259 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3260 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003261 break;
3262 }
3263 default:
3264 {
3265 virtual_pixel=image->background_color;
3266 break;
3267 }
3268 }
cristyc3ec0d42010-04-07 01:18:08 +00003269 virtual_index=0;
cristybb503372010-05-27 20:51:26 +00003270 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003271 {
cristybb503372010-05-27 20:51:26 +00003272 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003273 {
3274 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003275 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003276 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3277 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003278 {
3279 MagickModulo
3280 x_modulo,
3281 y_modulo;
3282
3283 /*
3284 Transfer a single pixel.
3285 */
3286 length=(MagickSizeType) 1;
3287 switch (virtual_pixel_method)
3288 {
3289 case BackgroundVirtualPixelMethod:
3290 case ConstantVirtualPixelMethod:
3291 case BlackVirtualPixelMethod:
3292 case GrayVirtualPixelMethod:
3293 case TransparentVirtualPixelMethod:
3294 case MaskVirtualPixelMethod:
3295 case WhiteVirtualPixelMethod:
3296 {
3297 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003298 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003299 break;
3300 }
3301 case EdgeVirtualPixelMethod:
3302 default:
3303 {
3304 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003305 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003306 1UL,1UL,virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003307 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3308 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003309 break;
3310 }
3311 case RandomVirtualPixelMethod:
3312 {
3313 if (cache_info->random_info == (RandomInfo *) NULL)
3314 cache_info->random_info=AcquireRandomInfo();
3315 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003316 RandomX(cache_info->random_info,cache_info->columns),
3317 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003318 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003319 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3320 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003321 break;
3322 }
3323 case DitherVirtualPixelMethod:
3324 {
3325 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003326 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003327 1UL,1UL,virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003328 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3329 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003330 break;
3331 }
3332 case TileVirtualPixelMethod:
3333 {
3334 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3335 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3336 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3337 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3338 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003339 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3340 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003341 break;
3342 }
3343 case MirrorVirtualPixelMethod:
3344 {
3345 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3346 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003347 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003348 x_modulo.remainder-1L;
3349 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3350 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003351 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003352 y_modulo.remainder-1L;
3353 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3354 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3355 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003356 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3357 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003358 break;
3359 }
3360 case CheckerTileVirtualPixelMethod:
3361 {
3362 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3363 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3364 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3365 {
3366 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003367 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003368 break;
3369 }
3370 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3371 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3372 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003373 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3374 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003375 break;
3376 }
3377 case HorizontalTileVirtualPixelMethod:
3378 {
cristybb503372010-05-27 20:51:26 +00003379 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003380 {
3381 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003382 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003383 break;
3384 }
3385 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3386 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3387 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3388 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3389 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003390 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3391 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003392 break;
3393 }
3394 case VerticalTileVirtualPixelMethod:
3395 {
cristybb503372010-05-27 20:51:26 +00003396 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
cristy3ed852e2009-09-05 21:47:34 +00003397 {
3398 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003399 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003400 break;
3401 }
3402 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3403 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3404 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3405 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3406 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003407 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3408 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003409 break;
3410 }
3411 case HorizontalTileEdgeVirtualPixelMethod:
3412 {
3413 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3414 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003415 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003416 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003417 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3418 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003419 break;
3420 }
3421 case VerticalTileEdgeVirtualPixelMethod:
3422 {
3423 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3424 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003425 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003426 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003427 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3428 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003429 break;
3430 }
3431 }
3432 if (p == (const PixelPacket *) NULL)
3433 break;
3434 *q++=(*p);
cristyc3ec0d42010-04-07 01:18:08 +00003435 if ((indexes != (IndexPacket *) NULL) &&
3436 (virtual_indexes != (const IndexPacket *) NULL))
3437 *indexes++=(*virtual_indexes);
cristy3ed852e2009-09-05 21:47:34 +00003438 continue;
3439 }
3440 /*
3441 Transfer a run of pixels.
3442 */
3443 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,
cristybb503372010-05-27 20:51:26 +00003444 (size_t) length,1UL,virtual_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003445 if (p == (const PixelPacket *) NULL)
3446 break;
cristyc3ec0d42010-04-07 01:18:08 +00003447 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,virtual_nexus[0]);
cristy8f036fe2010-09-18 02:02:00 +00003448 (void) memcpy(q,p,(size_t) length*sizeof(*p));
cristy3ed852e2009-09-05 21:47:34 +00003449 q+=length;
cristyc3ec0d42010-04-07 01:18:08 +00003450 if ((indexes != (IndexPacket *) NULL) &&
3451 (virtual_indexes != (const IndexPacket *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003452 {
cristy8f036fe2010-09-18 02:02:00 +00003453 (void) memcpy(indexes,virtual_indexes,(size_t) length*
cristyc3ec0d42010-04-07 01:18:08 +00003454 sizeof(*virtual_indexes));
3455 indexes+=length;
cristy3ed852e2009-09-05 21:47:34 +00003456 }
3457 }
3458 }
3459 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3460 return(pixels);
3461}
3462
3463/*
3464%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3465% %
3466% %
3467% %
3468+ G e t V i r t u a l P i x e l C a c h e %
3469% %
3470% %
3471% %
3472%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3473%
3474% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3475% cache as defined by the geometry parameters. A pointer to the pixels
3476% is returned if the pixels are transferred, otherwise a NULL is returned.
3477%
3478% The format of the GetVirtualPixelCache() method is:
3479%
3480% const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003481% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3482% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003483% ExceptionInfo *exception)
3484%
3485% A description of each parameter follows:
3486%
3487% o image: the image.
3488%
3489% o virtual_pixel_method: the virtual pixel method.
3490%
3491% o x,y,columns,rows: These values define the perimeter of a region of
3492% pixels.
3493%
3494% o exception: return any errors or warnings in this structure.
3495%
3496*/
3497static const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003498 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3499 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003500{
3501 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003502 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003503
cristy5c9e6f22010-09-17 17:31:01 +00003504 const int
3505 id = GetOpenMPThreadId();
3506
cristy3ed852e2009-09-05 21:47:34 +00003507 cache_info=(CacheInfo *) image->cache;
cristy6ebe97c2010-07-03 01:17:28 +00003508 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003509 return(GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3510 cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00003511}
3512
3513/*
3514%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3515% %
3516% %
3517% %
3518% G e t V i r t u a l P i x e l Q u e u e %
3519% %
3520% %
3521% %
3522%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3523%
3524% GetVirtualPixelQueue() returns the virtual pixels associated with the
3525% last call to QueueAuthenticPixels() or GetVirtualPixels().
3526%
3527% The format of the GetVirtualPixelQueue() method is:
3528%
3529% const PixelPacket *GetVirtualPixelQueue(const Image image)
3530%
3531% A description of each parameter follows:
3532%
3533% o image: the image.
3534%
3535*/
3536MagickExport const PixelPacket *GetVirtualPixelQueue(const Image *image)
3537{
3538 CacheInfo
3539 *cache_info;
3540
cristy2036f5c2010-09-19 21:18:17 +00003541 const int
3542 id = GetOpenMPThreadId();
3543
cristy3ed852e2009-09-05 21:47:34 +00003544 assert(image != (const Image *) NULL);
3545 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003546 assert(image->cache != (Cache) NULL);
3547 cache_info=(CacheInfo *) image->cache;
3548 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003549 if (cache_info->methods.get_virtual_pixels_handler !=
3550 (GetVirtualPixelsHandler) NULL)
3551 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003552 assert(id < (int) cache_info->number_threads);
3553 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003554}
3555
3556/*
3557%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3558% %
3559% %
3560% %
3561% G e t V i r t u a l P i x e l s %
3562% %
3563% %
3564% %
3565%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3566%
3567% GetVirtualPixels() returns an immutable pixel region. If the
3568% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003569% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003570% copy of the pixels or it may point to the original pixels in memory.
3571% Performance is maximized if the selected region is part of one row, or one
3572% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003573% (without a copy) if the image is in memory, or in a memory-mapped file. The
3574% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003575%
3576% Pixels accessed via the returned pointer represent a simple array of type
3577% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
3578% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access
3579% the black color component or to obtain the colormap indexes (of type
3580% IndexPacket) corresponding to the region.
3581%
3582% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3583%
3584% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3585% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3586% GetCacheViewAuthenticPixels() instead.
3587%
3588% The format of the GetVirtualPixels() method is:
3589%
cristybb503372010-05-27 20:51:26 +00003590% const PixelPacket *GetVirtualPixels(const Image *image,const ssize_t x,
3591% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003592% ExceptionInfo *exception)
3593%
3594% A description of each parameter follows:
3595%
3596% o image: the image.
3597%
3598% o x,y,columns,rows: These values define the perimeter of a region of
3599% pixels.
3600%
3601% o exception: return any errors or warnings in this structure.
3602%
3603*/
3604MagickExport const PixelPacket *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003605 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3606 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003607{
3608 CacheInfo
3609 *cache_info;
3610
cristy2036f5c2010-09-19 21:18:17 +00003611 const int
3612 id = GetOpenMPThreadId();
3613
cristy3ed852e2009-09-05 21:47:34 +00003614 assert(image != (const Image *) NULL);
3615 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003616 assert(image->cache != (Cache) NULL);
3617 cache_info=(CacheInfo *) image->cache;
3618 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003619 if (cache_info->methods.get_virtual_pixel_handler !=
3620 (GetVirtualPixelHandler) NULL)
3621 return(cache_info->methods.get_virtual_pixel_handler(image,
3622 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003623 assert(id < (int) cache_info->number_threads);
3624 return(GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3625 columns,rows,cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00003626}
3627
3628/*
3629%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3630% %
3631% %
3632% %
3633+ 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 %
3634% %
3635% %
3636% %
3637%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3638%
3639% GetVirtualPixelsCache() returns the pixels associated with the last call
3640% to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3641%
3642% The format of the GetVirtualPixelsCache() method is:
3643%
3644% PixelPacket *GetVirtualPixelsCache(const Image *image)
3645%
3646% A description of each parameter follows:
3647%
3648% o image: the image.
3649%
3650*/
3651static const PixelPacket *GetVirtualPixelsCache(const Image *image)
3652{
3653 CacheInfo
3654 *cache_info;
3655
cristy5c9e6f22010-09-17 17:31:01 +00003656 const int
3657 id = GetOpenMPThreadId();
3658
cristy3ed852e2009-09-05 21:47:34 +00003659 cache_info=(CacheInfo *) image->cache;
cristy6ebe97c2010-07-03 01:17:28 +00003660 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003661 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003662}
3663
3664/*
3665%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3666% %
3667% %
3668% %
3669+ G e t V i r t u a l P i x e l s N e x u s %
3670% %
3671% %
3672% %
3673%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3674%
3675% GetVirtualPixelsNexus() returns the pixels associated with the specified
3676% cache nexus.
3677%
3678% The format of the GetVirtualPixelsNexus() method is:
3679%
3680% const IndexPacket *GetVirtualPixelsNexus(const Cache cache,
3681% NexusInfo *nexus_info)
3682%
3683% A description of each parameter follows:
3684%
3685% o cache: the pixel cache.
3686%
3687% o nexus_info: the cache nexus to return the colormap pixels.
3688%
3689*/
3690MagickExport const PixelPacket *GetVirtualPixelsNexus(const Cache cache,
3691 NexusInfo *nexus_info)
3692{
3693 CacheInfo
3694 *cache_info;
3695
3696 if (cache == (Cache) NULL)
3697 return((PixelPacket *) NULL);
3698 cache_info=(CacheInfo *) cache;
3699 assert(cache_info->signature == MagickSignature);
3700 if (cache_info->storage_class == UndefinedClass)
3701 return((PixelPacket *) NULL);
3702 return((const PixelPacket *) nexus_info->pixels);
3703}
3704
3705/*
3706%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3707% %
3708% %
3709% %
3710+ M a s k P i x e l C a c h e N e x u s %
3711% %
3712% %
3713% %
3714%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3715%
3716% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3717% The method returns MagickTrue if the pixel region is masked, otherwise
3718% MagickFalse.
3719%
3720% The format of the MaskPixelCacheNexus() method is:
3721%
3722% MagickBooleanType MaskPixelCacheNexus(Image *image,
3723% NexusInfo *nexus_info,ExceptionInfo *exception)
3724%
3725% A description of each parameter follows:
3726%
3727% o image: the image.
3728%
3729% o nexus_info: the cache nexus to clip.
3730%
3731% o exception: return any errors or warnings in this structure.
3732%
3733*/
3734
3735static inline void MagickPixelCompositeMask(const MagickPixelPacket *p,
3736 const MagickRealType alpha,const MagickPixelPacket *q,
3737 const MagickRealType beta,MagickPixelPacket *composite)
3738{
3739 MagickRealType
3740 gamma;
3741
3742 if (alpha == TransparentOpacity)
3743 {
3744 *composite=(*q);
3745 return;
3746 }
3747 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3748 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3749 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3750 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3751 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3752 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3753 composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
3754}
3755
3756static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3757 ExceptionInfo *exception)
3758{
3759 CacheInfo
3760 *cache_info;
3761
3762 MagickPixelPacket
3763 alpha,
3764 beta;
3765
3766 MagickSizeType
3767 number_pixels;
3768
3769 NexusInfo
3770 **clip_nexus,
3771 **image_nexus;
3772
3773 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003774 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003775
3776 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003777 *restrict nexus_indexes,
3778 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003779
cristy3ed852e2009-09-05 21:47:34 +00003780 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003781 *restrict p,
3782 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003783
cristye076a6e2010-08-15 19:59:43 +00003784 register ssize_t
3785 i;
3786
cristy3ed852e2009-09-05 21:47:34 +00003787 /*
3788 Apply clip mask.
3789 */
3790 if (image->debug != MagickFalse)
3791 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3792 if (image->mask == (Image *) NULL)
3793 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +00003794 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00003795 if (cache_info == (Cache) NULL)
3796 return(MagickFalse);
3797 image_nexus=AcquirePixelCacheNexus(1);
3798 clip_nexus=AcquirePixelCacheNexus(1);
3799 if ((image_nexus == (NexusInfo **) NULL) ||
3800 (clip_nexus == (NexusInfo **) NULL))
3801 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy09449f72010-01-23 03:08:36 +00003802 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,
3803 nexus_info->region.y,nexus_info->region.width,nexus_info->region.height,
3804 image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003805 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
3806 q=nexus_info->pixels;
3807 nexus_indexes=nexus_info->indexes;
3808 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3809 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3810 nexus_info->region.height,clip_nexus[0],&image->exception);
3811 GetMagickPixelPacket(image,&alpha);
3812 GetMagickPixelPacket(image,&beta);
3813 number_pixels=(MagickSizeType) nexus_info->region.width*
3814 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +00003815 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +00003816 {
3817 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
3818 break;
3819 SetMagickPixelPacket(image,p,indexes+i,&alpha);
3820 SetMagickPixelPacket(image,q,nexus_indexes+i,&beta);
3821 MagickPixelCompositeMask(&beta,(MagickRealType) PixelIntensityToQuantum(r),
3822 &alpha,alpha.opacity,&beta);
cristyce70c172010-01-07 17:15:30 +00003823 q->red=ClampToQuantum(beta.red);
3824 q->green=ClampToQuantum(beta.green);
3825 q->blue=ClampToQuantum(beta.blue);
3826 q->opacity=ClampToQuantum(beta.opacity);
cristy3ed852e2009-09-05 21:47:34 +00003827 if (cache_info->active_index_channel != MagickFalse)
3828 nexus_indexes[i]=indexes[i];
3829 p++;
3830 q++;
3831 r++;
3832 }
3833 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3834 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +00003835 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003836 return(MagickFalse);
3837 return(MagickTrue);
3838}
3839
3840/*
3841%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3842% %
3843% %
3844% %
3845+ O p e n P i x e l C a c h e %
3846% %
3847% %
3848% %
3849%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3850%
3851% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3852% dimensions, allocating space for the image pixels and optionally the
3853% colormap indexes, and memory mapping the cache if it is disk based. The
3854% cache nexus array is initialized as well.
3855%
3856% The format of the OpenPixelCache() method is:
3857%
3858% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3859% ExceptionInfo *exception)
3860%
3861% A description of each parameter follows:
3862%
3863% o image: the image.
3864%
3865% o mode: ReadMode, WriteMode, or IOMode.
3866%
3867% o exception: return any errors or warnings in this structure.
3868%
3869*/
3870
cristyd43a46b2010-01-21 02:13:41 +00003871static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003872{
3873 cache_info->mapped=MagickFalse;
3874 cache_info->pixels=(PixelPacket *) AcquireMagickMemory((size_t)
3875 cache_info->length);
3876 if (cache_info->pixels == (PixelPacket *) NULL)
3877 {
3878 cache_info->mapped=MagickTrue;
3879 cache_info->pixels=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
3880 cache_info->length);
3881 }
3882}
3883
3884static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3885{
3886 CacheInfo
3887 *cache_info;
3888
3889 MagickOffsetType
3890 count,
3891 extent,
3892 offset;
3893
3894 cache_info=(CacheInfo *) image->cache;
3895 if (image->debug != MagickFalse)
3896 {
3897 char
3898 format[MaxTextExtent],
3899 message[MaxTextExtent];
3900
cristyb9080c92009-12-01 20:13:26 +00003901 (void) FormatMagickSize(length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00003902 (void) FormatMagickString(message,MaxTextExtent,
cristy2ce15c92010-03-12 14:03:41 +00003903 "extend %s (%s[%d], disk, %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003904 cache_info->cache_filename,cache_info->file,format);
3905 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3906 }
3907 if (length != (MagickSizeType) ((MagickOffsetType) length))
3908 return(MagickFalse);
3909 extent=(MagickOffsetType) MagickSeek(cache_info->file,0,SEEK_END);
3910 if (extent < 0)
3911 return(MagickFalse);
3912 if ((MagickSizeType) extent >= length)
3913 return(MagickTrue);
3914 offset=(MagickOffsetType) length-1;
3915 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3916 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3917}
3918
3919static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3920 ExceptionInfo *exception)
3921{
3922 char
3923 format[MaxTextExtent],
3924 message[MaxTextExtent];
3925
3926 CacheInfo
3927 *cache_info,
3928 source_info;
3929
3930 MagickSizeType
3931 length,
3932 number_pixels;
3933
3934 MagickStatusType
3935 status;
3936
3937 size_t
cristye076a6e2010-08-15 19:59:43 +00003938 columns,
cristy3ed852e2009-09-05 21:47:34 +00003939 packet_size;
3940
cristy3ed852e2009-09-05 21:47:34 +00003941 if (image->debug != MagickFalse)
3942 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3943 if ((image->columns == 0) || (image->rows == 0))
3944 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3945 cache_info=(CacheInfo *) image->cache;
3946 source_info=(*cache_info);
3947 source_info.file=(-1);
cristye8c25f92010-06-03 00:53:06 +00003948 (void) FormatMagickString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3949 image->filename,(double) GetImageIndexInList(image));
cristy87528ea2009-09-10 14:53:56 +00003950 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +00003951 cache_info->rows=image->rows;
3952 cache_info->columns=image->columns;
3953 cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
3954 (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
cristy73724512010-04-12 14:43:14 +00003955 if (image->ping != MagickFalse)
3956 {
3957 cache_info->storage_class=image->storage_class;
3958 cache_info->colorspace=image->colorspace;
3959 cache_info->type=PingCache;
3960 cache_info->pixels=(PixelPacket *) NULL;
3961 cache_info->indexes=(IndexPacket *) NULL;
3962 cache_info->length=0;
3963 return(MagickTrue);
3964 }
cristy3ed852e2009-09-05 21:47:34 +00003965 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3966 packet_size=sizeof(PixelPacket);
3967 if (cache_info->active_index_channel != MagickFalse)
3968 packet_size+=sizeof(IndexPacket);
3969 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00003970 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00003971 if (cache_info->columns != columns)
3972 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3973 image->filename);
3974 cache_info->length=length;
3975 status=AcquireMagickResource(AreaResource,cache_info->length);
3976 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
3977 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3978 {
3979 status=AcquireMagickResource(MemoryResource,cache_info->length);
3980 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3981 (cache_info->type == MemoryCache))
3982 {
cristyd43a46b2010-01-21 02:13:41 +00003983 AllocatePixelCachePixels(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00003984 if (cache_info->pixels == (PixelPacket *) NULL)
3985 cache_info->pixels=source_info.pixels;
3986 else
3987 {
3988 /*
3989 Create memory pixel cache.
3990 */
3991 if (image->debug != MagickFalse)
3992 {
cristy97e7a572009-12-05 15:07:53 +00003993 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00003994 format);
cristy3ed852e2009-09-05 21:47:34 +00003995 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00003996 "open %s (%s memory, %.20gx%.20g %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003997 cache_info->mapped != MagickFalse ? "anonymous" : "heap",
cristye8c25f92010-06-03 00:53:06 +00003998 (double) cache_info->columns,(double) cache_info->rows,
3999 format);
cristy3ed852e2009-09-05 21:47:34 +00004000 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4001 message);
4002 }
4003 cache_info->storage_class=image->storage_class;
4004 cache_info->colorspace=image->colorspace;
4005 cache_info->type=MemoryCache;
4006 cache_info->indexes=(IndexPacket *) NULL;
4007 if (cache_info->active_index_channel != MagickFalse)
4008 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4009 number_pixels);
4010 if (source_info.storage_class != UndefinedClass)
4011 {
4012 status|=ClonePixelCachePixels(cache_info,&source_info,
4013 exception);
4014 RelinquishPixelCachePixels(&source_info);
4015 }
4016 return(MagickTrue);
4017 }
4018 }
4019 RelinquishMagickResource(MemoryResource,cache_info->length);
4020 }
4021 /*
4022 Create pixel cache on disk.
4023 */
4024 status=AcquireMagickResource(DiskResource,cache_info->length);
4025 if (status == MagickFalse)
4026 {
4027 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4028 "CacheResourcesExhausted","`%s'",image->filename);
4029 return(MagickFalse);
4030 }
4031 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4032 {
4033 RelinquishMagickResource(DiskResource,cache_info->length);
4034 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4035 image->filename);
4036 return(MagickFalse);
4037 }
4038 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4039 cache_info->length);
4040 if (status == MagickFalse)
4041 {
4042 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4043 image->filename);
4044 return(MagickFalse);
4045 }
4046 cache_info->storage_class=image->storage_class;
4047 cache_info->colorspace=image->colorspace;
4048 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4049 status=AcquireMagickResource(AreaResource,cache_info->length);
4050 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4051 cache_info->type=DiskCache;
4052 else
4053 {
4054 status=AcquireMagickResource(MapResource,cache_info->length);
4055 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4056 (cache_info->type != MemoryCache))
4057 cache_info->type=DiskCache;
4058 else
4059 {
4060 cache_info->pixels=(PixelPacket *) MapBlob(cache_info->file,mode,
4061 cache_info->offset,(size_t) cache_info->length);
4062 if (cache_info->pixels == (PixelPacket *) NULL)
4063 {
4064 cache_info->pixels=source_info.pixels;
4065 cache_info->type=DiskCache;
4066 }
4067 else
4068 {
4069 /*
4070 Create file-backed memory-mapped pixel cache.
4071 */
4072 (void) ClosePixelCacheOnDisk(cache_info);
4073 cache_info->type=MapCache;
4074 cache_info->mapped=MagickTrue;
4075 cache_info->indexes=(IndexPacket *) NULL;
4076 if (cache_info->active_index_channel != MagickFalse)
4077 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4078 number_pixels);
4079 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4080 {
4081 status=ClonePixelCachePixels(cache_info,&source_info,
4082 exception);
4083 RelinquishPixelCachePixels(&source_info);
4084 }
4085 if (image->debug != MagickFalse)
4086 {
cristy97e7a572009-12-05 15:07:53 +00004087 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004088 format);
cristy3ed852e2009-09-05 21:47:34 +00004089 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004090 "open %s (%s[%d], memory-mapped, %.20gx%.20g %sB)",
cristy3ed852e2009-09-05 21:47:34 +00004091 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004092 cache_info->file,(double) cache_info->columns,(double)
4093 cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004094 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4095 message);
4096 }
4097 return(MagickTrue);
4098 }
4099 }
4100 RelinquishMagickResource(MapResource,cache_info->length);
4101 }
4102 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4103 {
4104 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4105 RelinquishPixelCachePixels(&source_info);
4106 }
4107 if (image->debug != MagickFalse)
4108 {
cristyb9080c92009-12-01 20:13:26 +00004109 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00004110 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004111 "open %s (%s[%d], disk, %.20gx%.20g %sB)",cache_info->filename,
4112 cache_info->cache_filename,cache_info->file,(double)
4113 cache_info->columns,(double) cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004114 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4115 }
4116 return(MagickTrue);
4117}
4118
4119/*
4120%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4121% %
4122% %
4123% %
4124+ P e r s i s t P i x e l C a c h e %
4125% %
4126% %
4127% %
4128%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4129%
4130% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4131% persistent pixel cache is one that resides on disk and is not destroyed
4132% when the program exits.
4133%
4134% The format of the PersistPixelCache() method is:
4135%
4136% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4137% const MagickBooleanType attach,MagickOffsetType *offset,
4138% ExceptionInfo *exception)
4139%
4140% A description of each parameter follows:
4141%
4142% o image: the image.
4143%
4144% o filename: the persistent pixel cache filename.
4145%
cristy01b7eb02009-09-10 23:10:14 +00004146% o attach: A value other than zero initializes the persistent pixel
4147% cache.
4148%
cristy3ed852e2009-09-05 21:47:34 +00004149% o initialize: A value other than zero initializes the persistent pixel
4150% cache.
4151%
4152% o offset: the offset in the persistent cache to store pixels.
4153%
4154% o exception: return any errors or warnings in this structure.
4155%
4156*/
4157MagickExport MagickBooleanType PersistPixelCache(Image *image,
4158 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4159 ExceptionInfo *exception)
4160{
4161 CacheInfo
4162 *cache_info,
4163 *clone_info;
4164
4165 Image
4166 clone_image;
4167
cristy3ed852e2009-09-05 21:47:34 +00004168 MagickBooleanType
4169 status;
4170
cristye076a6e2010-08-15 19:59:43 +00004171 ssize_t
4172 page_size;
4173
cristy3ed852e2009-09-05 21:47:34 +00004174 assert(image != (Image *) NULL);
4175 assert(image->signature == MagickSignature);
4176 if (image->debug != MagickFalse)
4177 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4178 assert(image->cache != (void *) NULL);
4179 assert(filename != (const char *) NULL);
4180 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004181 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004182 cache_info=(CacheInfo *) image->cache;
4183 assert(cache_info->signature == MagickSignature);
4184 if (attach != MagickFalse)
4185 {
4186 /*
cristy01b7eb02009-09-10 23:10:14 +00004187 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004188 */
4189 if (image->debug != MagickFalse)
4190 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4191 "attach persistent cache");
4192 (void) CopyMagickString(cache_info->cache_filename,filename,
4193 MaxTextExtent);
4194 cache_info->type=DiskCache;
4195 cache_info->offset=(*offset);
4196 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4197 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004198 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004199 return(MagickTrue);
4200 }
cristy01b7eb02009-09-10 23:10:14 +00004201 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4202 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004203 {
cristyf84a1932010-01-03 18:00:18 +00004204 LockSemaphoreInfo(cache_info->semaphore);
cristy09449f72010-01-23 03:08:36 +00004205 if ((cache_info->mode != ReadMode) &&
4206 (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004207 (cache_info->reference_count == 1))
4208 {
4209 int
4210 status;
4211
4212 /*
cristy01b7eb02009-09-10 23:10:14 +00004213 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004214 */
4215 status=rename(cache_info->cache_filename,filename);
4216 if (status == 0)
4217 {
4218 (void) CopyMagickString(cache_info->cache_filename,filename,
4219 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004220 *offset+=cache_info->length+page_size-(cache_info->length %
4221 page_size);
cristyf84a1932010-01-03 18:00:18 +00004222 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004223 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004224 if (image->debug != MagickFalse)
4225 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4226 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004227 return(MagickTrue);
4228 }
4229 }
cristyf84a1932010-01-03 18:00:18 +00004230 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004231 }
4232 /*
cristy01b7eb02009-09-10 23:10:14 +00004233 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004234 */
4235 clone_image=(*image);
4236 clone_info=(CacheInfo *) clone_image.cache;
4237 image->cache=ClonePixelCache(cache_info);
4238 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4239 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4240 cache_info->type=DiskCache;
4241 cache_info->offset=(*offset);
4242 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004243 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004244 if (status != MagickFalse)
cristyabd6e372010-09-15 19:11:26 +00004245 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
cristy688f07b2009-09-27 15:19:13 +00004246 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004247 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4248 return(status);
4249}
4250
4251/*
4252%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4253% %
4254% %
4255% %
4256+ Q u e u e A u t h e n t i c N e x u s %
4257% %
4258% %
4259% %
4260%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4261%
4262% QueueAuthenticNexus() allocates an region to store image pixels as defined
4263% by the region rectangle and returns a pointer to the region. This region is
4264% subsequently transferred from the pixel cache with
4265% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4266% pixels are transferred, otherwise a NULL is returned.
4267%
4268% The format of the QueueAuthenticNexus() method is:
4269%
cristy5f959472010-05-27 22:19:46 +00004270% PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
4271% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004272% NexusInfo *nexus_info,ExceptionInfo *exception)
4273%
4274% A description of each parameter follows:
4275%
4276% o image: the image.
4277%
4278% o x,y,columns,rows: These values define the perimeter of a region of
4279% pixels.
4280%
4281% o nexus_info: the cache nexus to set.
4282%
4283% o exception: return any errors or warnings in this structure.
4284%
4285*/
cristybb503372010-05-27 20:51:26 +00004286MagickExport PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy30097232010-07-01 02:16:30 +00004287 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
4288 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004289{
4290 CacheInfo
4291 *cache_info;
4292
4293 MagickOffsetType
4294 offset;
4295
4296 MagickSizeType
4297 number_pixels;
4298
4299 RectangleInfo
4300 region;
4301
4302 /*
4303 Validate pixel cache geometry.
4304 */
cristy77ff0282010-09-13 00:51:10 +00004305 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
4306 if (cache_info == (Cache) NULL)
4307 return((PixelPacket *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004308 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4309 {
4310 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4311 "NoPixelsDefinedInCache","`%s'",image->filename);
4312 return((PixelPacket *) NULL);
4313 }
cristybb503372010-05-27 20:51:26 +00004314 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4315 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004316 {
4317 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4318 "PixelsAreNotAuthentic","`%s'",image->filename);
4319 return((PixelPacket *) NULL);
4320 }
4321 offset=(MagickOffsetType) y*cache_info->columns+x;
4322 if (offset < 0)
4323 return((PixelPacket *) NULL);
4324 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4325 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4326 if ((MagickSizeType) offset >= number_pixels)
4327 return((PixelPacket *) NULL);
4328 /*
4329 Return pixel cache.
4330 */
4331 region.x=x;
4332 region.y=y;
4333 region.width=columns;
4334 region.height=rows;
4335 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4336}
4337
4338/*
4339%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4340% %
4341% %
4342% %
4343+ 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 %
4344% %
4345% %
4346% %
4347%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4348%
4349% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4350% defined by the region rectangle and returns a pointer to the region. This
4351% region is subsequently transferred from the pixel cache with
4352% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4353% pixels are transferred, otherwise a NULL is returned.
4354%
4355% The format of the QueueAuthenticPixelsCache() method is:
4356%
cristybb503372010-05-27 20:51:26 +00004357% PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4358% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004359% ExceptionInfo *exception)
4360%
4361% A description of each parameter follows:
4362%
4363% o image: the image.
4364%
4365% o x,y,columns,rows: These values define the perimeter of a region of
4366% pixels.
4367%
4368% o exception: return any errors or warnings in this structure.
4369%
4370*/
cristybb503372010-05-27 20:51:26 +00004371static PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4372 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004373 ExceptionInfo *exception)
4374{
4375 CacheInfo
4376 *cache_info;
4377
cristy5c9e6f22010-09-17 17:31:01 +00004378 const int
4379 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004380
cristy77ff0282010-09-13 00:51:10 +00004381 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00004382 if (cache_info == (Cache) NULL)
4383 return((PixelPacket *) NULL);
cristy6ebe97c2010-07-03 01:17:28 +00004384 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00004385 return(QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4386 exception));
cristy3ed852e2009-09-05 21:47:34 +00004387}
4388
4389/*
4390%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4391% %
4392% %
4393% %
4394% Q u e u e A u t h e n t i c P i x e l s %
4395% %
4396% %
4397% %
4398%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4399%
4400% QueueAuthenticPixels() queues a mutable pixel region. If the region is
4401% successfully intialized a pointer to a PixelPacket array representing the
4402% region is returned, otherwise NULL is returned. The returned pointer may
4403% point to a temporary working buffer for the pixels or it may point to the
4404% final location of the pixels in memory.
4405%
4406% Write-only access means that any existing pixel values corresponding to
4407% the region are ignored. This is useful if the initial image is being
4408% created from scratch, or if the existing pixel values are to be
4409% completely replaced without need to refer to their pre-existing values.
4410% The application is free to read and write the pixel buffer returned by
4411% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4412% initialize the pixel array values. Initializing pixel array values is the
4413% application's responsibility.
4414%
4415% Performance is maximized if the selected region is part of one row, or
4416% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004417% pixels in-place (without a copy) if the image is in memory, or in a
4418% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004419% by the user.
4420%
4421% Pixels accessed via the returned pointer represent a simple array of type
4422% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
4423% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
4424% the black color component or the colormap indexes (of type IndexPacket)
4425% corresponding to the region. Once the PixelPacket (and/or IndexPacket)
4426% array has been updated, the changes must be saved back to the underlying
4427% image using SyncAuthenticPixels() or they may be lost.
4428%
4429% The format of the QueueAuthenticPixels() method is:
4430%
cristy5f959472010-05-27 22:19:46 +00004431% PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4432% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004433% ExceptionInfo *exception)
4434%
4435% A description of each parameter follows:
4436%
4437% o image: the image.
4438%
4439% o x,y,columns,rows: These values define the perimeter of a region of
4440% pixels.
4441%
4442% o exception: return any errors or warnings in this structure.
4443%
4444*/
cristybb503372010-05-27 20:51:26 +00004445MagickExport PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4446 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004447 ExceptionInfo *exception)
4448{
4449 CacheInfo
4450 *cache_info;
4451
cristy2036f5c2010-09-19 21:18:17 +00004452 const int
4453 id = GetOpenMPThreadId();
4454
cristy3ed852e2009-09-05 21:47:34 +00004455 assert(image != (Image *) NULL);
4456 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004457 assert(image->cache != (Cache) NULL);
4458 cache_info=(CacheInfo *) image->cache;
4459 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004460 if (cache_info->methods.queue_authentic_pixels_handler !=
4461 (QueueAuthenticPixelsHandler) NULL)
4462 return(cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4463 rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00004464 assert(id < (int) cache_info->number_threads);
4465 return(QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4466 exception));
cristy3ed852e2009-09-05 21:47:34 +00004467}
4468
4469/*
4470%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4471% %
4472% %
4473% %
4474+ R e a d P i x e l C a c h e I n d e x e s %
4475% %
4476% %
4477% %
4478%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4479%
4480% ReadPixelCacheIndexes() reads colormap indexes from the specified region of
4481% the pixel cache.
4482%
4483% The format of the ReadPixelCacheIndexes() method is:
4484%
4485% MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4486% NexusInfo *nexus_info,ExceptionInfo *exception)
4487%
4488% A description of each parameter follows:
4489%
4490% o cache_info: the pixel cache.
4491%
4492% o nexus_info: the cache nexus to read the colormap indexes.
4493%
4494% o exception: return any errors or warnings in this structure.
4495%
4496*/
4497static MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4498 NexusInfo *nexus_info,ExceptionInfo *exception)
4499{
4500 MagickOffsetType
4501 count,
4502 offset;
4503
4504 MagickSizeType
4505 length,
4506 number_pixels;
4507
4508 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004509 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004510
cristybb503372010-05-27 20:51:26 +00004511 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004512 y;
4513
cristybb503372010-05-27 20:51:26 +00004514 size_t
cristy3ed852e2009-09-05 21:47:34 +00004515 rows;
4516
cristy3ed852e2009-09-05 21:47:34 +00004517 if (cache_info->active_index_channel == MagickFalse)
4518 return(MagickFalse);
4519 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4520 return(MagickTrue);
4521 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4522 nexus_info->region.x;
4523 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
4524 rows=nexus_info->region.height;
4525 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004526 q=nexus_info->indexes;
4527 switch (cache_info->type)
4528 {
4529 case MemoryCache:
4530 case MapCache:
4531 {
4532 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004533 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004534
4535 /*
4536 Read indexes from memory.
4537 */
cristydd341db2010-03-04 19:06:38 +00004538 if ((cache_info->columns == nexus_info->region.width) &&
4539 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4540 {
4541 length=number_pixels;
4542 rows=1UL;
4543 }
cristy3ed852e2009-09-05 21:47:34 +00004544 p=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00004545 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004546 {
cristy8f036fe2010-09-18 02:02:00 +00004547 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00004548 p+=cache_info->columns;
4549 q+=nexus_info->region.width;
4550 }
4551 break;
4552 }
4553 case DiskCache:
4554 {
4555 /*
4556 Read indexes from disk.
4557 */
4558 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4559 {
4560 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4561 cache_info->cache_filename);
4562 return(MagickFalse);
4563 }
cristydd341db2010-03-04 19:06:38 +00004564 if ((cache_info->columns == nexus_info->region.width) &&
4565 (number_pixels < MagickMaxBufferExtent))
4566 {
4567 length=number_pixels;
4568 rows=1UL;
4569 }
cristy3ed852e2009-09-05 21:47:34 +00004570 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004571 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004572 {
4573 count=ReadPixelCacheRegion(cache_info,cache_info->offset+number_pixels*
4574 sizeof(PixelPacket)+offset*sizeof(*q),length,(unsigned char *) q);
4575 if ((MagickSizeType) count < length)
4576 break;
4577 offset+=cache_info->columns;
4578 q+=nexus_info->region.width;
4579 }
cristybb503372010-05-27 20:51:26 +00004580 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004581 {
4582 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4583 cache_info->cache_filename);
4584 return(MagickFalse);
4585 }
4586 break;
4587 }
4588 default:
4589 break;
4590 }
4591 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004592 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004593 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004594 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004595 nexus_info->region.width,(double) nexus_info->region.height,(double)
4596 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004597 return(MagickTrue);
4598}
4599
4600/*
4601%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4602% %
4603% %
4604% %
4605+ R e a d P i x e l C a c h e P i x e l s %
4606% %
4607% %
4608% %
4609%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4610%
4611% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4612% cache.
4613%
4614% The format of the ReadPixelCachePixels() method is:
4615%
4616% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4617% NexusInfo *nexus_info,ExceptionInfo *exception)
4618%
4619% A description of each parameter follows:
4620%
4621% o cache_info: the pixel cache.
4622%
4623% o nexus_info: the cache nexus to read the pixels.
4624%
4625% o exception: return any errors or warnings in this structure.
4626%
4627*/
4628static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4629 NexusInfo *nexus_info,ExceptionInfo *exception)
4630{
4631 MagickOffsetType
4632 count,
4633 offset;
4634
4635 MagickSizeType
4636 length,
4637 number_pixels;
4638
cristy3ed852e2009-09-05 21:47:34 +00004639 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004640 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004641
cristye076a6e2010-08-15 19:59:43 +00004642 register ssize_t
4643 y;
4644
cristybb503372010-05-27 20:51:26 +00004645 size_t
cristy3ed852e2009-09-05 21:47:34 +00004646 rows;
4647
cristy3ed852e2009-09-05 21:47:34 +00004648 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4649 return(MagickTrue);
4650 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4651 nexus_info->region.x;
4652 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
4653 rows=nexus_info->region.height;
4654 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004655 q=nexus_info->pixels;
4656 switch (cache_info->type)
4657 {
4658 case MemoryCache:
4659 case MapCache:
4660 {
4661 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004662 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004663
4664 /*
4665 Read pixels from memory.
4666 */
cristydd341db2010-03-04 19:06:38 +00004667 if ((cache_info->columns == nexus_info->region.width) &&
4668 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4669 {
4670 length=number_pixels;
4671 rows=1UL;
4672 }
cristy3ed852e2009-09-05 21:47:34 +00004673 p=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00004674 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004675 {
cristy8f036fe2010-09-18 02:02:00 +00004676 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00004677 p+=cache_info->columns;
4678 q+=nexus_info->region.width;
4679 }
4680 break;
4681 }
4682 case DiskCache:
4683 {
4684 /*
4685 Read pixels from disk.
4686 */
4687 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4688 {
4689 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4690 cache_info->cache_filename);
4691 return(MagickFalse);
4692 }
cristydd341db2010-03-04 19:06:38 +00004693 if ((cache_info->columns == nexus_info->region.width) &&
4694 (number_pixels < MagickMaxBufferExtent))
4695 {
4696 length=number_pixels;
4697 rows=1UL;
4698 }
cristybb503372010-05-27 20:51:26 +00004699 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004700 {
4701 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4702 sizeof(*q),length,(unsigned char *) q);
4703 if ((MagickSizeType) count < length)
4704 break;
4705 offset+=cache_info->columns;
4706 q+=nexus_info->region.width;
4707 }
cristybb503372010-05-27 20:51:26 +00004708 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004709 {
4710 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4711 cache_info->cache_filename);
4712 return(MagickFalse);
4713 }
4714 break;
4715 }
4716 default:
4717 break;
4718 }
4719 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004720 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004721 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004722 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004723 nexus_info->region.width,(double) nexus_info->region.height,(double)
4724 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004725 return(MagickTrue);
4726}
4727
4728/*
4729%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4730% %
4731% %
4732% %
4733+ R e f e r e n c e P i x e l C a c h e %
4734% %
4735% %
4736% %
4737%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4738%
4739% ReferencePixelCache() increments the reference count associated with the
4740% pixel cache returning a pointer to the cache.
4741%
4742% The format of the ReferencePixelCache method is:
4743%
4744% Cache ReferencePixelCache(Cache cache_info)
4745%
4746% A description of each parameter follows:
4747%
4748% o cache_info: the pixel cache.
4749%
4750*/
4751MagickExport Cache ReferencePixelCache(Cache cache)
4752{
4753 CacheInfo
4754 *cache_info;
4755
4756 assert(cache != (Cache *) NULL);
4757 cache_info=(CacheInfo *) cache;
4758 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004759 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004760 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004761 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004762 return(cache_info);
4763}
4764
4765/*
4766%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4767% %
4768% %
4769% %
4770+ S e t P i x e l C a c h e M e t h o d s %
4771% %
4772% %
4773% %
4774%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4775%
4776% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4777%
4778% The format of the SetPixelCacheMethods() method is:
4779%
4780% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4781%
4782% A description of each parameter follows:
4783%
4784% o cache: the pixel cache.
4785%
4786% o cache_methods: Specifies a pointer to a CacheMethods structure.
4787%
4788*/
4789MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4790{
4791 CacheInfo
4792 *cache_info;
4793
4794 GetOneAuthenticPixelFromHandler
4795 get_one_authentic_pixel_from_handler;
4796
4797 GetOneVirtualPixelFromHandler
4798 get_one_virtual_pixel_from_handler;
4799
4800 /*
4801 Set cache pixel methods.
4802 */
4803 assert(cache != (Cache) NULL);
4804 assert(cache_methods != (CacheMethods *) NULL);
4805 cache_info=(CacheInfo *) cache;
4806 assert(cache_info->signature == MagickSignature);
4807 if (cache_info->debug != MagickFalse)
4808 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4809 cache_info->filename);
4810 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4811 cache_info->methods.get_virtual_pixel_handler=
4812 cache_methods->get_virtual_pixel_handler;
4813 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4814 cache_info->methods.destroy_pixel_handler=
4815 cache_methods->destroy_pixel_handler;
4816 if (cache_methods->get_virtual_indexes_from_handler !=
4817 (GetVirtualIndexesFromHandler) NULL)
4818 cache_info->methods.get_virtual_indexes_from_handler=
4819 cache_methods->get_virtual_indexes_from_handler;
4820 if (cache_methods->get_authentic_pixels_handler !=
4821 (GetAuthenticPixelsHandler) NULL)
4822 cache_info->methods.get_authentic_pixels_handler=
4823 cache_methods->get_authentic_pixels_handler;
4824 if (cache_methods->queue_authentic_pixels_handler !=
4825 (QueueAuthenticPixelsHandler) NULL)
4826 cache_info->methods.queue_authentic_pixels_handler=
4827 cache_methods->queue_authentic_pixels_handler;
4828 if (cache_methods->sync_authentic_pixels_handler !=
4829 (SyncAuthenticPixelsHandler) NULL)
4830 cache_info->methods.sync_authentic_pixels_handler=
4831 cache_methods->sync_authentic_pixels_handler;
4832 if (cache_methods->get_authentic_pixels_from_handler !=
4833 (GetAuthenticPixelsFromHandler) NULL)
4834 cache_info->methods.get_authentic_pixels_from_handler=
4835 cache_methods->get_authentic_pixels_from_handler;
4836 if (cache_methods->get_authentic_indexes_from_handler !=
4837 (GetAuthenticIndexesFromHandler) NULL)
4838 cache_info->methods.get_authentic_indexes_from_handler=
4839 cache_methods->get_authentic_indexes_from_handler;
4840 get_one_virtual_pixel_from_handler=
4841 cache_info->methods.get_one_virtual_pixel_from_handler;
4842 if (get_one_virtual_pixel_from_handler !=
4843 (GetOneVirtualPixelFromHandler) NULL)
4844 cache_info->methods.get_one_virtual_pixel_from_handler=
4845 cache_methods->get_one_virtual_pixel_from_handler;
4846 get_one_authentic_pixel_from_handler=
4847 cache_methods->get_one_authentic_pixel_from_handler;
4848 if (get_one_authentic_pixel_from_handler !=
4849 (GetOneAuthenticPixelFromHandler) NULL)
4850 cache_info->methods.get_one_authentic_pixel_from_handler=
4851 cache_methods->get_one_authentic_pixel_from_handler;
4852}
4853
4854/*
4855%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4856% %
4857% %
4858% %
4859+ S e t P i x e l C a c h e N e x u s P i x e l s %
4860% %
4861% %
4862% %
4863%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4864%
4865% SetPixelCacheNexusPixels() defines the region of the cache for the
4866% specified cache nexus.
4867%
4868% The format of the SetPixelCacheNexusPixels() method is:
4869%
4870% PixelPacket SetPixelCacheNexusPixels(const Image *image,
4871% const RectangleInfo *region,NexusInfo *nexus_info,
4872% ExceptionInfo *exception)
4873%
4874% A description of each parameter follows:
4875%
4876% o image: the image.
4877%
4878% o region: A pointer to the RectangleInfo structure that defines the
4879% region of this particular cache nexus.
4880%
4881% o nexus_info: the cache nexus to set.
4882%
4883% o exception: return any errors or warnings in this structure.
4884%
4885*/
cristyabd6e372010-09-15 19:11:26 +00004886
4887static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4888 NexusInfo *nexus_info,ExceptionInfo *exception)
4889{
4890 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4891 return(MagickFalse);
4892 nexus_info->mapped=MagickFalse;
4893 nexus_info->cache=(PixelPacket *) AcquireMagickMemory((size_t)
4894 nexus_info->length);
4895 if (nexus_info->cache == (PixelPacket *) NULL)
4896 {
4897 nexus_info->mapped=MagickTrue;
4898 nexus_info->cache=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
4899 nexus_info->length);
4900 }
4901 if (nexus_info->cache == (PixelPacket *) NULL)
4902 {
4903 (void) ThrowMagickException(exception,GetMagickModule(),
4904 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4905 cache_info->filename);
4906 return(MagickFalse);
4907 }
4908 return(MagickTrue);
4909}
4910
cristy3ed852e2009-09-05 21:47:34 +00004911static PixelPacket *SetPixelCacheNexusPixels(const Image *image,
4912 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4913{
4914 CacheInfo
4915 *cache_info;
4916
4917 MagickBooleanType
4918 status;
4919
cristy3ed852e2009-09-05 21:47:34 +00004920 MagickSizeType
4921 length,
4922 number_pixels;
4923
cristy3ed852e2009-09-05 21:47:34 +00004924 cache_info=(CacheInfo *) image->cache;
4925 assert(cache_info->signature == MagickSignature);
4926 if (cache_info->type == UndefinedCache)
4927 return((PixelPacket *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00004928 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00004929 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
4930 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00004931 {
cristybb503372010-05-27 20:51:26 +00004932 ssize_t
cristybad067a2010-02-15 17:20:55 +00004933 x,
4934 y;
cristy3ed852e2009-09-05 21:47:34 +00004935
cristyeaedf062010-05-29 22:36:02 +00004936 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4937 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00004938 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4939 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00004940 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00004941 ((nexus_info->region.width == cache_info->columns) ||
4942 ((nexus_info->region.width % cache_info->columns) == 0)))))
4943 {
4944 MagickOffsetType
4945 offset;
4946
4947 /*
4948 Pixels are accessed directly from memory.
4949 */
4950 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4951 nexus_info->region.x;
4952 nexus_info->pixels=cache_info->pixels+offset;
4953 nexus_info->indexes=(IndexPacket *) NULL;
4954 if (cache_info->active_index_channel != MagickFalse)
4955 nexus_info->indexes=cache_info->indexes+offset;
4956 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00004957 }
4958 }
4959 /*
4960 Pixels are stored in a cache region until they are synced to the cache.
4961 */
4962 number_pixels=(MagickSizeType) nexus_info->region.width*
4963 nexus_info->region.height;
4964 length=number_pixels*sizeof(PixelPacket);
4965 if (cache_info->active_index_channel != MagickFalse)
4966 length+=number_pixels*sizeof(IndexPacket);
4967 if (nexus_info->cache == (PixelPacket *) NULL)
4968 {
4969 nexus_info->length=length;
4970 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4971 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004972 {
4973 nexus_info->length=0;
4974 return((PixelPacket *) NULL);
4975 }
cristy3ed852e2009-09-05 21:47:34 +00004976 }
4977 else
4978 if (nexus_info->length != length)
4979 {
4980 RelinquishCacheNexusPixels(nexus_info);
4981 nexus_info->length=length;
4982 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4983 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004984 {
4985 nexus_info->length=0;
4986 return((PixelPacket *) NULL);
4987 }
cristy3ed852e2009-09-05 21:47:34 +00004988 }
4989 nexus_info->pixels=nexus_info->cache;
4990 nexus_info->indexes=(IndexPacket *) NULL;
4991 if (cache_info->active_index_channel != MagickFalse)
4992 nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
4993 return(nexus_info->pixels);
4994}
4995
4996/*
4997%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4998% %
4999% %
5000% %
5001% 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 %
5002% %
5003% %
5004% %
5005%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5006%
5007% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5008% pixel cache and returns the previous setting. A virtual pixel is any pixel
5009% access that is outside the boundaries of the image cache.
5010%
5011% The format of the SetPixelCacheVirtualMethod() method is:
5012%
5013% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5014% const VirtualPixelMethod virtual_pixel_method)
5015%
5016% A description of each parameter follows:
5017%
5018% o image: the image.
5019%
5020% o virtual_pixel_method: choose the type of virtual pixel.
5021%
5022*/
5023MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5024 const VirtualPixelMethod virtual_pixel_method)
5025{
5026 CacheInfo
5027 *cache_info;
5028
5029 VirtualPixelMethod
5030 method;
5031
5032 assert(image != (Image *) NULL);
5033 assert(image->signature == MagickSignature);
5034 if (image->debug != MagickFalse)
5035 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5036 assert(image->cache != (Cache) NULL);
5037 cache_info=(CacheInfo *) image->cache;
5038 assert(cache_info->signature == MagickSignature);
5039 method=cache_info->virtual_pixel_method;
5040 cache_info->virtual_pixel_method=virtual_pixel_method;
5041 return(method);
5042}
5043
5044/*
5045%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5046% %
5047% %
5048% %
5049+ 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 %
5050% %
5051% %
5052% %
5053%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5054%
5055% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5056% in-memory or disk cache. The method returns MagickTrue if the pixel region
5057% is synced, otherwise MagickFalse.
5058%
5059% The format of the SyncAuthenticPixelCacheNexus() method is:
5060%
5061% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5062% NexusInfo *nexus_info,ExceptionInfo *exception)
5063%
5064% A description of each parameter follows:
5065%
5066% o image: the image.
5067%
5068% o nexus_info: the cache nexus to sync.
5069%
5070% o exception: return any errors or warnings in this structure.
5071%
5072*/
5073MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5074 NexusInfo *nexus_info,ExceptionInfo *exception)
5075{
5076 CacheInfo
5077 *cache_info;
5078
5079 MagickBooleanType
5080 status;
5081
5082 /*
5083 Transfer pixels to the cache.
5084 */
5085 assert(image != (Image *) NULL);
5086 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005087 if (image->cache == (Cache) NULL)
5088 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5089 cache_info=(CacheInfo *) image->cache;
5090 if (cache_info->type == UndefinedCache)
5091 return(MagickFalse);
5092 if ((image->clip_mask != (Image *) NULL) &&
5093 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5094 return(MagickFalse);
5095 if ((image->mask != (Image *) NULL) &&
5096 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5097 return(MagickFalse);
5098 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5099 return(MagickTrue);
5100 assert(cache_info->signature == MagickSignature);
5101 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5102 if ((cache_info->active_index_channel != MagickFalse) &&
5103 (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
5104 return(MagickFalse);
5105 return(status);
5106}
5107
5108/*
5109%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5110% %
5111% %
5112% %
5113+ S y n c A u t h e n t i c P i x e l C a c h e %
5114% %
5115% %
5116% %
5117%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5118%
5119% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5120% or disk cache. The method returns MagickTrue if the pixel region is synced,
5121% otherwise MagickFalse.
5122%
5123% The format of the SyncAuthenticPixelsCache() method is:
5124%
5125% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5126% ExceptionInfo *exception)
5127%
5128% A description of each parameter follows:
5129%
5130% o image: the image.
5131%
5132% o exception: return any errors or warnings in this structure.
5133%
5134*/
5135static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5136 ExceptionInfo *exception)
5137{
5138 CacheInfo
5139 *cache_info;
5140
cristy5c9e6f22010-09-17 17:31:01 +00005141 const int
5142 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005143
cristy3ed852e2009-09-05 21:47:34 +00005144 cache_info=(CacheInfo *) image->cache;
cristy6ebe97c2010-07-03 01:17:28 +00005145 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00005146 return(SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5147 exception));
cristy3ed852e2009-09-05 21:47:34 +00005148}
5149
5150/*
5151%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5152% %
5153% %
5154% %
5155% S y n c A u t h e n t i c P i x e l s %
5156% %
5157% %
5158% %
5159%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5160%
5161% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5162% The method returns MagickTrue if the pixel region is flushed, otherwise
5163% MagickFalse.
5164%
5165% The format of the SyncAuthenticPixels() method is:
5166%
5167% MagickBooleanType SyncAuthenticPixels(Image *image,
5168% ExceptionInfo *exception)
5169%
5170% A description of each parameter follows:
5171%
5172% o image: the image.
5173%
5174% o exception: return any errors or warnings in this structure.
5175%
5176*/
5177MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5178 ExceptionInfo *exception)
5179{
5180 CacheInfo
5181 *cache_info;
5182
cristy2036f5c2010-09-19 21:18:17 +00005183 const int
5184 id = GetOpenMPThreadId();
5185
cristy3ed852e2009-09-05 21:47:34 +00005186 assert(image != (Image *) NULL);
5187 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005188 assert(image->cache != (Cache) NULL);
5189 cache_info=(CacheInfo *) image->cache;
5190 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005191 if (cache_info->methods.sync_authentic_pixels_handler !=
5192 (SyncAuthenticPixelsHandler) NULL)
5193 return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
cristy2036f5c2010-09-19 21:18:17 +00005194 assert(id < (int) cache_info->number_threads);
5195 return(SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5196 exception));
cristy3ed852e2009-09-05 21:47:34 +00005197}
5198
5199/*
5200%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5201% %
5202% %
5203% %
5204+ W r i t e P i x e l C a c h e I n d e x e s %
5205% %
5206% %
5207% %
5208%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5209%
5210% WritePixelCacheIndexes() writes the colormap indexes to the specified
5211% region of the pixel cache.
5212%
5213% The format of the WritePixelCacheIndexes() method is:
5214%
5215% MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5216% NexusInfo *nexus_info,ExceptionInfo *exception)
5217%
5218% A description of each parameter follows:
5219%
5220% o cache_info: the pixel cache.
5221%
5222% o nexus_info: the cache nexus to write the colormap indexes.
5223%
5224% o exception: return any errors or warnings in this structure.
5225%
5226*/
5227static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5228 NexusInfo *nexus_info,ExceptionInfo *exception)
5229{
5230 MagickOffsetType
5231 count,
5232 offset;
5233
5234 MagickSizeType
5235 length,
5236 number_pixels;
5237
5238 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005239 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005240
cristybb503372010-05-27 20:51:26 +00005241 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005242 y;
5243
cristybb503372010-05-27 20:51:26 +00005244 size_t
cristy3ed852e2009-09-05 21:47:34 +00005245 rows;
5246
cristy3ed852e2009-09-05 21:47:34 +00005247 if (cache_info->active_index_channel == MagickFalse)
5248 return(MagickFalse);
5249 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5250 return(MagickTrue);
5251 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5252 nexus_info->region.x;
5253 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
5254 rows=nexus_info->region.height;
5255 number_pixels=(MagickSizeType) length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005256 p=nexus_info->indexes;
5257 switch (cache_info->type)
5258 {
5259 case MemoryCache:
5260 case MapCache:
5261 {
5262 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005263 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005264
5265 /*
5266 Write indexes to memory.
5267 */
cristydd341db2010-03-04 19:06:38 +00005268 if ((cache_info->columns == nexus_info->region.width) &&
5269 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5270 {
5271 length=number_pixels;
5272 rows=1UL;
5273 }
cristy3ed852e2009-09-05 21:47:34 +00005274 q=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00005275 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005276 {
cristy8f036fe2010-09-18 02:02:00 +00005277 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00005278 p+=nexus_info->region.width;
5279 q+=cache_info->columns;
5280 }
5281 break;
5282 }
5283 case DiskCache:
5284 {
5285 /*
5286 Write indexes to disk.
5287 */
5288 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5289 {
5290 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5291 cache_info->cache_filename);
5292 return(MagickFalse);
5293 }
cristydd341db2010-03-04 19:06:38 +00005294 if ((cache_info->columns == nexus_info->region.width) &&
5295 (number_pixels < MagickMaxBufferExtent))
5296 {
5297 length=number_pixels;
5298 rows=1UL;
5299 }
cristy3ed852e2009-09-05 21:47:34 +00005300 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005301 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005302 {
5303 count=WritePixelCacheRegion(cache_info,cache_info->offset+number_pixels*
5304 sizeof(PixelPacket)+offset*sizeof(*p),length,
5305 (const unsigned char *) p);
5306 if ((MagickSizeType) count < length)
5307 break;
5308 p+=nexus_info->region.width;
5309 offset+=cache_info->columns;
5310 }
cristybb503372010-05-27 20:51:26 +00005311 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005312 {
5313 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5314 cache_info->cache_filename);
5315 return(MagickFalse);
5316 }
5317 break;
5318 }
5319 default:
5320 break;
5321 }
5322 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005323 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005324 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005325 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005326 nexus_info->region.width,(double) nexus_info->region.height,(double)
5327 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005328 return(MagickTrue);
5329}
5330
5331/*
5332%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5333% %
5334% %
5335% %
5336+ W r i t e C a c h e P i x e l s %
5337% %
5338% %
5339% %
5340%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5341%
5342% WritePixelCachePixels() writes image pixels to the specified region of the
5343% pixel cache.
5344%
5345% The format of the WritePixelCachePixels() method is:
5346%
5347% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5348% NexusInfo *nexus_info,ExceptionInfo *exception)
5349%
5350% A description of each parameter follows:
5351%
5352% o cache_info: the pixel cache.
5353%
5354% o nexus_info: the cache nexus to write the pixels.
5355%
5356% o exception: return any errors or warnings in this structure.
5357%
5358*/
5359static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5360 NexusInfo *nexus_info,ExceptionInfo *exception)
5361{
5362 MagickOffsetType
5363 count,
5364 offset;
5365
5366 MagickSizeType
5367 length,
5368 number_pixels;
5369
cristy3ed852e2009-09-05 21:47:34 +00005370 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005371 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005372
cristybb503372010-05-27 20:51:26 +00005373 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005374 y;
5375
cristybb503372010-05-27 20:51:26 +00005376 size_t
cristy3ed852e2009-09-05 21:47:34 +00005377 rows;
5378
cristy3ed852e2009-09-05 21:47:34 +00005379 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5380 return(MagickTrue);
5381 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5382 nexus_info->region.x;
5383 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
5384 rows=nexus_info->region.height;
5385 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005386 p=nexus_info->pixels;
5387 switch (cache_info->type)
5388 {
5389 case MemoryCache:
5390 case MapCache:
5391 {
5392 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005393 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005394
5395 /*
5396 Write pixels to memory.
5397 */
cristydd341db2010-03-04 19:06:38 +00005398 if ((cache_info->columns == nexus_info->region.width) &&
5399 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5400 {
5401 length=number_pixels;
5402 rows=1UL;
5403 }
cristy3ed852e2009-09-05 21:47:34 +00005404 q=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00005405 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005406 {
cristy8f036fe2010-09-18 02:02:00 +00005407 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00005408 p+=nexus_info->region.width;
5409 q+=cache_info->columns;
5410 }
5411 break;
5412 }
5413 case DiskCache:
5414 {
5415 /*
5416 Write pixels to disk.
5417 */
5418 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5419 {
5420 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5421 cache_info->cache_filename);
5422 return(MagickFalse);
5423 }
cristydd341db2010-03-04 19:06:38 +00005424 if ((cache_info->columns == nexus_info->region.width) &&
5425 (number_pixels < MagickMaxBufferExtent))
5426 {
5427 length=number_pixels;
5428 rows=1UL;
5429 }
cristybb503372010-05-27 20:51:26 +00005430 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005431 {
5432 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5433 sizeof(*p),length,(const unsigned char *) p);
5434 if ((MagickSizeType) count < length)
5435 break;
5436 p+=nexus_info->region.width;
5437 offset+=cache_info->columns;
5438 }
cristybb503372010-05-27 20:51:26 +00005439 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005440 {
5441 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5442 cache_info->cache_filename);
5443 return(MagickFalse);
5444 }
5445 break;
5446 }
5447 default:
5448 break;
5449 }
5450 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005451 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005452 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005453 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005454 nexus_info->region.width,(double) nexus_info->region.height,(double)
5455 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005456 return(MagickTrue);
5457}