blob: 83446aaa4182243df8b1b76e5a1ea5a08be16d0f [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% CCCC AAA CCCC H H EEEEE %
7% C A A C H H E %
8% C AAAAA C HHHHH EEE %
9% C A A C H H E %
10% CCCC A A CCCC H H EEEEE %
11% %
12% %
13% MagickCore Pixel Cache Methods %
14% %
15% Software Design %
16% John Cristy %
17% July 1999 %
18% %
19% %
cristy16af1cb2009-12-11 21:38:29 +000020% Copyright 1999-2010 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% http://www.imagemagick.org/script/license.php %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37%
38*/
39
40/*
41 Include declarations.
42*/
43#include "magick/studio.h"
44#include "magick/blob.h"
45#include "magick/blob-private.h"
46#include "magick/cache.h"
47#include "magick/cache-private.h"
48#include "magick/color-private.h"
49#include "magick/composite-private.h"
50#include "magick/exception.h"
51#include "magick/exception-private.h"
cristy365e58f2010-02-15 02:00:01 +000052#include "magick/geometry.h"
cristy3ed852e2009-09-05 21:47:34 +000053#include "magick/list.h"
54#include "magick/log.h"
55#include "magick/magick.h"
56#include "magick/memory_.h"
cristy4789f0d2010-01-10 00:01:06 +000057#include "magick/pixel.h"
cristy3ed852e2009-09-05 21:47:34 +000058#include "magick/pixel-private.h"
cristya21afde2010-07-02 00:45:40 +000059#include "magick/policy.h"
cristy3ed852e2009-09-05 21:47:34 +000060#include "magick/quantum.h"
61#include "magick/random_.h"
62#include "magick/resource_.h"
63#include "magick/semaphore.h"
64#include "magick/splay-tree.h"
65#include "magick/string_.h"
cristya21afde2010-07-02 00:45:40 +000066#include "magick/string-private.h"
cristy3ed852e2009-09-05 21:47:34 +000067#include "magick/thread-private.h"
68#include "magick/utility.h"
69#if defined(MAGICKCORE_ZLIB_DELEGATE)
70#include "zlib.h"
71#endif
72
73/*
cristy30097232010-07-01 02:16:30 +000074 Define declarations.
75*/
76#define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
77
78/*
cristy3ed852e2009-09-05 21:47:34 +000079 Typedef declarations.
80*/
81typedef struct _MagickModulo
82{
cristybb503372010-05-27 20:51:26 +000083 ssize_t
cristy3ed852e2009-09-05 21:47:34 +000084 quotient,
85 remainder;
86} MagickModulo;
87
88struct _NexusInfo
89{
90 MagickBooleanType
91 mapped;
92
93 RectangleInfo
94 region;
95
96 MagickSizeType
97 length;
98
99 PixelPacket
100 *cache,
101 *pixels;
102
103 IndexPacket
104 *indexes;
105
cristybb503372010-05-27 20:51:26 +0000106 size_t
cristy3ed852e2009-09-05 21:47:34 +0000107 signature;
108};
109
110/*
111 Forward declarations.
112*/
113#if defined(__cplusplus) || defined(c_plusplus)
114extern "C" {
115#endif
116
117static const IndexPacket
118 *GetVirtualIndexesFromCache(const Image *);
119
120static const PixelPacket
cristybb503372010-05-27 20:51:26 +0000121 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
122 const ssize_t,const size_t,const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000123 *GetVirtualPixelsCache(const Image *);
124
125static MagickBooleanType
cristy09c1c4d2010-06-30 18:23:16 +0000126 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,
127 PixelPacket *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000128 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
cristybb503372010-05-27 20:51:26 +0000129 const ssize_t,const ssize_t,PixelPacket *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000130 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
131 ReadPixelCacheIndexes(CacheInfo *,NexusInfo *,ExceptionInfo *),
132 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
133 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
134 WritePixelCacheIndexes(CacheInfo *,NexusInfo *,ExceptionInfo *),
135 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
136
137static PixelPacket
cristybb503372010-05-27 20:51:26 +0000138 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
139 const size_t,ExceptionInfo *),
140 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
141 const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000142 *SetPixelCacheNexusPixels(const Image *,const RectangleInfo *,NexusInfo *,
cristya4af2e32010-03-08 00:51:56 +0000143 ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +0000144
145#if defined(__cplusplus) || defined(c_plusplus)
146}
147#endif
148
149/*
150 Global declarations.
151*/
152static volatile MagickBooleanType
153 instantiate_cache = MagickFalse;
154
155static SemaphoreInfo
156 *cache_semaphore = (SemaphoreInfo *) NULL;
157
158static SplayTreeInfo
159 *cache_resources = (SplayTreeInfo *) NULL;
cristy3ed852e2009-09-05 21:47:34 +0000160
161/*
162%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
163% %
164% %
165% %
166+ A c q u i r e P i x e l C a c h e %
167% %
168% %
169% %
170%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
171%
172% AcquirePixelCache() acquires a pixel cache.
173%
174% The format of the AcquirePixelCache() method is:
175%
cristybb503372010-05-27 20:51:26 +0000176% Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000177%
178% A description of each parameter follows:
179%
180% o number_threads: the number of nexus threads.
181%
182*/
cristybb503372010-05-27 20:51:26 +0000183MagickExport Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000184{
185 CacheInfo
186 *cache_info;
187
188 cache_info=(CacheInfo *) AcquireAlignedMemory(1,sizeof(*cache_info));
189 if (cache_info == (CacheInfo *) NULL)
190 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
191 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
192 cache_info->type=UndefinedCache;
cristy87528ea2009-09-10 14:53:56 +0000193 cache_info->mode=IOMode;
cristy3ed852e2009-09-05 21:47:34 +0000194 cache_info->colorspace=RGBColorspace;
195 cache_info->file=(-1);
196 cache_info->id=GetMagickThreadId();
197 cache_info->number_threads=number_threads;
198 if (number_threads == 0)
199 cache_info->number_threads=GetOpenMPMaximumThreads();
200 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
201 if (cache_info->nexus_info == (NexusInfo **) NULL)
202 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
203 GetPixelCacheMethods(&cache_info->methods);
204 cache_info->reference_count=1;
205 cache_info->semaphore=AllocateSemaphoreInfo();
206 cache_info->disk_semaphore=AllocateSemaphoreInfo();
207 cache_info->debug=IsEventLogging();
208 cache_info->signature=MagickSignature;
209 if ((cache_resources == (SplayTreeInfo *) NULL) &&
210 (instantiate_cache == MagickFalse))
211 {
cristy4e1dff62009-10-25 20:36:03 +0000212 if (cache_semaphore == (SemaphoreInfo *) NULL)
213 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000214 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000215 if ((cache_resources == (SplayTreeInfo *) NULL) &&
216 (instantiate_cache == MagickFalse))
217 {
218 cache_resources=NewSplayTree((int (*)(const void *,const void *))
219 NULL,(void *(*)(void *)) NULL,(void *(*)(void *)) NULL);
220 instantiate_cache=MagickTrue;
221 }
cristyf84a1932010-01-03 18:00:18 +0000222 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000223 }
224 (void) AddValueToSplayTree(cache_resources,cache_info,cache_info);
225 return((Cache ) cache_info);
226}
227
228/*
229%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
230% %
231% %
232% %
233% A c q u i r e P i x e l C a c h e N e x u s %
234% %
235% %
236% %
237%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
238%
239% AcquirePixelCacheNexus() allocates the NexusInfo structure.
240%
241% The format of the AcquirePixelCacheNexus method is:
242%
cristybb503372010-05-27 20:51:26 +0000243% NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000244%
245% A description of each parameter follows:
246%
247% o number_threads: the number of nexus threads.
248%
249*/
250MagickExport NexusInfo **AcquirePixelCacheNexus(
cristybb503372010-05-27 20:51:26 +0000251 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000252{
cristybb503372010-05-27 20:51:26 +0000253 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000254 i;
255
256 NexusInfo
257 **nexus_info;
258
259 nexus_info=(NexusInfo **) AcquireAlignedMemory(number_threads,
260 sizeof(*nexus_info));
261 if (nexus_info == (NexusInfo **) NULL)
262 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristybb503372010-05-27 20:51:26 +0000263 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000264 {
265 nexus_info[i]=(NexusInfo *) AcquireAlignedMemory(1,sizeof(**nexus_info));
266 if (nexus_info[i] == (NexusInfo *) NULL)
267 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
268 (void) ResetMagickMemory(nexus_info[i],0,sizeof(*nexus_info[i]));
269 nexus_info[i]->signature=MagickSignature;
270 }
271 return(nexus_info);
272}
273
274/*
275%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
276% %
277% %
278% %
cristyd43a46b2010-01-21 02:13:41 +0000279+ A c q u i r e P i x e l C a c h e P i x e l s %
280% %
281% %
282% %
283%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
284%
285% AcquirePixelCachePixels() returns the pixels associated with the specified
286% image.
287%
288% The format of the AcquirePixelCachePixels() method is:
289%
290% const void *AcquirePixelCachePixels(const Image *image,
291% MagickSizeType *length,ExceptionInfo *exception)
292%
293% A description of each parameter follows:
294%
295% o image: the image.
296%
297% o length: the pixel cache length.
298%
299% o exception: return any errors or warnings in this structure.
300%
301*/
302MagickExport const void *AcquirePixelCachePixels(const Image *image,
303 MagickSizeType *length,ExceptionInfo *exception)
304{
305 CacheInfo
306 *cache_info;
307
308 assert(image != (const Image *) NULL);
309 assert(image->signature == MagickSignature);
310 if (image->debug != MagickFalse)
311 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
312 assert(exception != (ExceptionInfo *) NULL);
313 assert(exception->signature == MagickSignature);
314 assert(image->cache != (Cache) NULL);
315 cache_info=(CacheInfo *) image->cache;
316 assert(cache_info->signature == MagickSignature);
317 *length=0;
318 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
319 return((const void *) NULL);
320 *length=cache_info->length;
321 return((const void *) cache_info->pixels);
322}
323
324/*
325%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
326% %
327% %
328% %
cristyf34a1452009-10-24 22:29:27 +0000329+ C a c h e C o m p o n e n t G e n e s i s %
330% %
331% %
332% %
333%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
334%
335% CacheComponentGenesis() instantiates the cache component.
336%
337% The format of the CacheComponentGenesis method is:
338%
339% MagickBooleanType CacheComponentGenesis(void)
340%
341*/
342MagickExport MagickBooleanType CacheComponentGenesis(void)
343{
cristy165b6092009-10-26 13:52:10 +0000344 AcquireSemaphoreInfo(&cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000345 return(MagickTrue);
346}
347
348/*
349%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
350% %
351% %
352% %
353+ C a c h e C o m p o n e n t T e r m i n u s %
354% %
355% %
356% %
357%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
358%
359% CacheComponentTerminus() destroys the cache component.
360%
361% The format of the CacheComponentTerminus() method is:
362%
363% CacheComponentTerminus(void)
364%
365*/
366MagickExport void CacheComponentTerminus(void)
367{
cristy18b17442009-10-25 18:36:48 +0000368 if (cache_semaphore == (SemaphoreInfo *) NULL)
369 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000370 LockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000371 if (cache_resources != (SplayTreeInfo *) NULL)
372 cache_resources=DestroySplayTree(cache_resources);
373 instantiate_cache=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +0000374 UnlockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000375 DestroySemaphoreInfo(&cache_semaphore);
376}
377
378/*
379%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
380% %
381% %
382% %
cristy3ed852e2009-09-05 21:47:34 +0000383+ C l i p P i x e l C a c h e N e x u s %
384% %
385% %
386% %
387%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
388%
389% ClipPixelCacheNexus() clips the cache nexus as defined by the image clip
390% mask. The method returns MagickTrue if the pixel region is clipped,
391% otherwise MagickFalse.
392%
393% The format of the ClipPixelCacheNexus() method is:
394%
395% MagickBooleanType ClipPixelCacheNexus(Image *image,NexusInfo *nexus_info,
396% ExceptionInfo *exception)
397%
398% A description of each parameter follows:
399%
400% o image: the image.
401%
402% o nexus_info: the cache nexus to clip.
403%
404% o exception: return any errors or warnings in this structure.
405%
406*/
407static MagickBooleanType ClipPixelCacheNexus(Image *image,
408 NexusInfo *nexus_info,ExceptionInfo *exception)
409{
410 CacheInfo
411 *cache_info;
412
413 MagickSizeType
414 number_pixels;
415
416 NexusInfo
417 **clip_nexus,
418 **image_nexus;
419
420 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000421 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +0000422
423 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +0000424 *restrict nexus_indexes,
425 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +0000426
cristybb503372010-05-27 20:51:26 +0000427 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000428 i;
429
430 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000431 *restrict p,
432 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000433
434 /*
435 Apply clip mask.
436 */
437 if (image->debug != MagickFalse)
438 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
439 if (image->clip_mask == (Image *) NULL)
440 return(MagickFalse);
441 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
442 if (cache_info == (Cache) NULL)
443 return(MagickFalse);
444 image_nexus=AcquirePixelCacheNexus(1);
445 clip_nexus=AcquirePixelCacheNexus(1);
446 if ((image_nexus == (NexusInfo **) NULL) ||
447 (clip_nexus == (NexusInfo **) NULL))
448 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
449 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,nexus_info->region.y,
450 nexus_info->region.width,nexus_info->region.height,image_nexus[0],
451 exception);
452 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
453 q=nexus_info->pixels;
454 nexus_indexes=nexus_info->indexes;
455 r=GetVirtualPixelsFromNexus(image->clip_mask,MaskVirtualPixelMethod,
456 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
457 nexus_info->region.height,clip_nexus[0],exception);
458 number_pixels=(MagickSizeType) nexus_info->region.width*
459 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +0000460 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000461 {
462 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
463 break;
464 if (PixelIntensityToQuantum(r) > ((Quantum) QuantumRange/2))
465 {
cristyce70c172010-01-07 17:15:30 +0000466 SetRedPixelComponent(q,GetRedPixelComponent(p));
467 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
468 SetBluePixelComponent(q,GetBluePixelComponent(p));
469 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
cristy3ed852e2009-09-05 21:47:34 +0000470 if (cache_info->active_index_channel != MagickFalse)
471 nexus_indexes[i]=indexes[i];
472 }
473 p++;
474 q++;
475 r++;
476 }
477 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
478 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +0000479 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +0000480 return(MagickFalse);
481 return(MagickTrue);
482}
483
484/*
485%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
486% %
487% %
488% %
489+ C l o n e P i x e l C a c h e %
490% %
491% %
492% %
493%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
494%
495% ClonePixelCache() clones a pixel cache.
496%
497% The format of the ClonePixelCache() method is:
498%
499% Cache ClonePixelCache(const Cache cache)
500%
501% A description of each parameter follows:
502%
503% o cache: the pixel cache.
504%
505*/
506MagickExport Cache ClonePixelCache(const Cache cache)
507{
508 CacheInfo
509 *clone_info;
510
511 const CacheInfo
512 *cache_info;
513
514 assert(cache != (const Cache) NULL);
515 cache_info=(const CacheInfo *) cache;
516 assert(cache_info->signature == MagickSignature);
517 if (cache_info->debug != MagickFalse)
518 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
519 cache_info->filename);
520 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
521 if (clone_info == (Cache) NULL)
522 return((Cache) NULL);
523 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
524 return((Cache ) clone_info);
525}
526
527/*
528%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
529% %
530% %
531% %
532+ C l o n e P i x e l C a c h e N e x u s %
533% %
534% %
535% %
536%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
537%
538% ClonePixelCacheNexus() clones the source cache nexus to the destination
539% nexus.
540%
541% The format of the ClonePixelCacheNexus() method is:
542%
543% MagickBooleanType ClonePixelCacheNexus(CacheInfo *destination,
544% CacheInfo *source,ExceptionInfo *exception)
545%
546% A description of each parameter follows:
547%
548% o destination: the destination cache nexus.
549%
550% o source: the source cache nexus.
551%
552% o exception: return any errors or warnings in this structure.
553%
554*/
555
556static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
557 NexusInfo *nexus_info,ExceptionInfo *exception)
558{
559 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
560 return(MagickFalse);
561 nexus_info->mapped=MagickFalse;
562 nexus_info->cache=(PixelPacket *) AcquireMagickMemory((size_t)
563 nexus_info->length);
564 if (nexus_info->cache == (PixelPacket *) NULL)
565 {
566 nexus_info->mapped=MagickTrue;
567 nexus_info->cache=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
568 nexus_info->length);
569 }
570 if (nexus_info->cache == (PixelPacket *) NULL)
571 {
572 (void) ThrowMagickException(exception,GetMagickModule(),
573 ResourceLimitError,"MemoryAllocationFailed","`%s'",
574 cache_info->filename);
575 return(MagickFalse);
576 }
577 return(MagickTrue);
578}
579
580static MagickBooleanType ClonePixelCacheNexus(CacheInfo *destination,
581 CacheInfo *source,ExceptionInfo *exception)
582{
583 MagickBooleanType
584 status;
585
586 MagickSizeType
587 number_pixels;
588
cristybb503372010-05-27 20:51:26 +0000589 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000590 i;
591
592 register const NexusInfo
593 *p;
594
595 register NexusInfo
596 *q;
597
598 status=MagickTrue;
cristybb503372010-05-27 20:51:26 +0000599 for (i=0; i < (ssize_t) source->number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000600 {
601 p=source->nexus_info[i];
602 q=destination->nexus_info[i];
603 q->mapped=p->mapped;
604 q->region=p->region;
605 q->length=p->length;
606 q->cache=p->cache;
607 q->pixels=p->pixels;
608 q->indexes=p->indexes;
609 if (p->cache != (PixelPacket *) NULL)
610 {
611 status=AcquireCacheNexusPixels(source,q,exception);
612 if (status != MagickFalse)
613 {
614 (void) CopyMagickMemory(q->cache,p->cache,(size_t) p->length);
615 q->pixels=q->cache;
616 q->indexes=(IndexPacket *) NULL;
617 number_pixels=(MagickSizeType) q->region.width*q->region.height;
618 if (p->indexes != (IndexPacket *) NULL)
619 q->indexes=(IndexPacket *) (q->pixels+number_pixels);
620 }
621 }
622 }
623 return(status);
624}
625
626/*
627%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
628% %
629% %
630% %
cristy60c44a82009-10-07 00:58:49 +0000631+ C l o n e P i x e l C a c h e P i x e l s %
cristy3ed852e2009-09-05 21:47:34 +0000632% %
633% %
634% %
635%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
636% ClonePixelCachePixels() clones the source pixel cache to the destination
637% cache.
638%
639% The format of the ClonePixelCachePixels() method is:
640%
641% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
642% CacheInfo *source_info,ExceptionInfo *exception)
643%
644% A description of each parameter follows:
645%
646% o cache_info: the pixel cache.
647%
648% o source_info: the source pixel cache.
649%
650% o exception: return any errors or warnings in this structure.
651%
652*/
653
654static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
655{
656 int
657 status;
658
cristy5ee247a2010-02-12 15:42:34 +0000659 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000660 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000661 if (cache_info->file != -1)
662 status=close(cache_info->file);
cristy3ed852e2009-09-05 21:47:34 +0000663 cache_info->file=(-1);
664 RelinquishMagickResource(FileResource,1);
cristyf84a1932010-01-03 18:00:18 +0000665 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000666 return(status == -1 ? MagickFalse : MagickTrue);
667}
668
669static void LimitPixelCacheDescriptors(void)
670{
671 register CacheInfo
672 *p,
673 *q;
674
675 /*
676 Limit # of open file descriptors.
677 */
678 if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
679 return;
cristyf84a1932010-01-03 18:00:18 +0000680 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000681 if (cache_resources == (SplayTreeInfo *) NULL)
682 {
cristyf84a1932010-01-03 18:00:18 +0000683 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000684 return;
685 }
686 ResetSplayTreeIterator(cache_resources);
687 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
688 while (p != (CacheInfo *) NULL)
689 {
690 if ((p->type == DiskCache) && (p->file != -1))
cristy508d9312010-02-10 21:10:30 +0000691 break;
cristy3ed852e2009-09-05 21:47:34 +0000692 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
693 }
694 for (q=p; p != (CacheInfo *) NULL; )
695 {
696 if ((p->type == DiskCache) && (p->file != -1) &&
697 (p->timestamp < q->timestamp))
cristy508d9312010-02-10 21:10:30 +0000698 q=p;
cristy3ed852e2009-09-05 21:47:34 +0000699 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
700 }
701 if (q != (CacheInfo *) NULL)
cristy9e116922010-02-12 20:58:13 +0000702 {
703 /*
704 Close least recently used cache.
705 */
706 (void) close(q->file);
707 q->file=(-1);
708 }
cristyf84a1932010-01-03 18:00:18 +0000709 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000710}
711
712static inline MagickSizeType MagickMax(const MagickSizeType x,
713 const MagickSizeType y)
714{
715 if (x > y)
716 return(x);
717 return(y);
718}
719
720static inline MagickSizeType MagickMin(const MagickSizeType x,
721 const MagickSizeType y)
722{
723 if (x < y)
724 return(x);
725 return(y);
726}
727
728static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
729 const MapMode mode)
730{
731 int
732 file;
733
734 /*
735 Open pixel cache on disk.
736 */
cristyf84a1932010-01-03 18:00:18 +0000737 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000738 if (cache_info->file != -1)
739 {
cristyf84a1932010-01-03 18:00:18 +0000740 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000741 return(MagickTrue); /* cache already open */
742 }
743 LimitPixelCacheDescriptors();
744 if (*cache_info->cache_filename == '\0')
745 file=AcquireUniqueFileResource(cache_info->cache_filename);
746 else
747 switch (mode)
748 {
749 case ReadMode:
750 {
751 file=open(cache_info->cache_filename,O_RDONLY | O_BINARY);
752 break;
753 }
754 case WriteMode:
755 {
756 file=open(cache_info->cache_filename,O_WRONLY | O_CREAT | O_BINARY |
757 O_EXCL,S_MODE);
758 if (file == -1)
759 file=open(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
760 break;
761 }
762 case IOMode:
763 default:
764 {
765 file=open(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
766 O_EXCL,S_MODE);
767 if (file == -1)
768 file=open(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
769 break;
770 }
771 }
772 if (file == -1)
773 {
cristyf84a1932010-01-03 18:00:18 +0000774 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000775 return(MagickFalse);
776 }
777 (void) AcquireMagickResource(FileResource,1);
778 cache_info->file=file;
779 cache_info->timestamp=time(0);
cristyf84a1932010-01-03 18:00:18 +0000780 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000781 return(MagickTrue);
782}
783
784static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
785 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000786 unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000787{
788 register MagickOffsetType
789 i;
790
791 ssize_t
792 count;
793
cristy08a88202010-03-04 19:18:05 +0000794 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000795#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000796 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000797 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
798 {
cristyf84a1932010-01-03 18:00:18 +0000799 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000800 return((MagickOffsetType) -1);
801 }
802#endif
803 count=0;
804 for (i=0; i < (MagickOffsetType) length; i+=count)
805 {
806#if !defined(MAGICKCORE_HAVE_PREAD)
807 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
808 (MagickSizeType) SSIZE_MAX));
809#else
810 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
811 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
812#endif
813 if (count > 0)
814 continue;
815 count=0;
816 if (errno != EINTR)
817 {
818 i=(-1);
819 break;
820 }
821 }
822#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000823 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000824#endif
825 return(i);
826}
827
828static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
829 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000830 const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000831{
832 register MagickOffsetType
833 i;
834
835 ssize_t
836 count;
837
cristy08a88202010-03-04 19:18:05 +0000838 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000839#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000840 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000841 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
842 {
cristyf84a1932010-01-03 18:00:18 +0000843 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000844 return((MagickOffsetType) -1);
845 }
846#endif
847 count=0;
848 for (i=0; i < (MagickOffsetType) length; i+=count)
849 {
850#if !defined(MAGICKCORE_HAVE_PWRITE)
851 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
852 (MagickSizeType) SSIZE_MAX));
853#else
854 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
855 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
856#endif
857 if (count > 0)
858 continue;
859 count=0;
860 if (errno != EINTR)
861 {
862 i=(-1);
863 break;
864 }
865 }
866#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000867 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000868#endif
869 return(i);
870}
871
872static MagickBooleanType CloneDiskToDiskPixelCache(CacheInfo *clone_info,
873 CacheInfo *cache_info,ExceptionInfo *exception)
874{
875 MagickOffsetType
876 count,
877 offset,
878 source_offset;
879
880 MagickSizeType
881 length;
882
cristybb503372010-05-27 20:51:26 +0000883 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000884 y;
885
886 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000887 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +0000888
cristybb503372010-05-27 20:51:26 +0000889 size_t
cristy3ed852e2009-09-05 21:47:34 +0000890 columns,
891 rows;
892
893 if (cache_info->debug != MagickFalse)
894 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
895 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
896 {
897 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
898 clone_info->cache_filename);
899 return(MagickFalse);
900 }
901 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
902 {
903 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
904 cache_info->cache_filename);
905 return(MagickFalse);
906 }
cristybb503372010-05-27 20:51:26 +0000907 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
908 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +0000909 if ((clone_info->active_index_channel != MagickFalse) &&
910 (cache_info->active_index_channel != MagickFalse))
911 {
912 register IndexPacket
913 *indexes;
914
915 /*
916 Clone cache indexes.
917 */
918 length=MagickMax(clone_info->columns,cache_info->columns)*
919 sizeof(*indexes);
920 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
921 if (indexes == (IndexPacket *) NULL)
922 {
923 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
924 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
925 return(MagickFalse);
926 }
927 (void) ResetMagickMemory(indexes,0,(size_t) length);
928 length=columns*sizeof(*indexes);
929 source_offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
930 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
931 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
932 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +0000933 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000934 {
935 source_offset-=cache_info->columns*sizeof(*indexes);
936 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
937 length,(unsigned char *) indexes);
938 if ((MagickSizeType) count != length)
939 break;
940 offset-=clone_info->columns*sizeof(*indexes);
941 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
942 (unsigned char *) indexes);
943 if ((MagickSizeType) count != length)
944 break;
945 }
cristybb503372010-05-27 20:51:26 +0000946 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000947 {
948 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
949 ThrowFileException(exception,CacheError,"UnableToCloneCache",
950 cache_info->cache_filename);
951 return(MagickFalse);
952 }
953 if (clone_info->columns > cache_info->columns)
954 {
955 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
956 (void) ResetMagickMemory(indexes,0,(size_t) length);
957 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
958 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +0000959 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000960 {
961 offset-=clone_info->columns*sizeof(*indexes);
962 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
963 length,(unsigned char *) indexes);
964 if ((MagickSizeType) count != length)
965 break;
966 }
cristybb503372010-05-27 20:51:26 +0000967 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000968 {
969 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
970 ThrowFileException(exception,CacheError,"UnableToCloneCache",
971 cache_info->cache_filename);
972 return(MagickFalse);
973 }
974 }
975 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
976 }
977 /*
978 Clone cache pixels.
979 */
980 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
981 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
982 if (pixels == (PixelPacket *) NULL)
983 {
984 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
985 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
986 return(MagickFalse);
987 }
988 (void) ResetMagickMemory(pixels,0,(size_t) length);
989 length=columns*sizeof(*pixels);
990 source_offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
991 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +0000992 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000993 {
994 source_offset-=cache_info->columns*sizeof(*pixels);
995 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
996 length,(unsigned char *) pixels);
997 if ((MagickSizeType) count != length)
998 break;
999 offset-=clone_info->columns*sizeof(*pixels);
1000 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1001 (unsigned char *) pixels);
1002 if ((MagickSizeType) count != length)
1003 break;
1004 }
cristybb503372010-05-27 20:51:26 +00001005 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001006 {
1007 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1008 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1009 cache_info->cache_filename);
1010 return(MagickFalse);
1011 }
1012 if (clone_info->columns > cache_info->columns)
1013 {
1014 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
1015 sizeof(*pixels);
1016 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1017 (void) ResetMagickMemory(pixels,0,(size_t) length);
cristybb503372010-05-27 20:51:26 +00001018 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001019 {
1020 offset-=clone_info->columns*sizeof(*pixels);
1021 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1022 (unsigned char *) pixels);
1023 if ((MagickSizeType) count != length)
1024 break;
1025 }
cristybb503372010-05-27 20:51:26 +00001026 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001027 {
1028 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1029 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1030 cache_info->cache_filename);
1031 return(MagickFalse);
1032 }
1033 }
1034 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1035 return(MagickTrue);
1036}
1037
1038static MagickBooleanType CloneDiskToMemoryPixelCache(CacheInfo *clone_info,
1039 CacheInfo *cache_info,ExceptionInfo *exception)
1040{
1041 MagickOffsetType
1042 count,
1043 offset;
1044
1045 MagickSizeType
1046 length;
1047
cristybb503372010-05-27 20:51:26 +00001048 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001049 y;
1050
1051 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001052 *restrict pixels,
1053 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00001054
cristybb503372010-05-27 20:51:26 +00001055 size_t
cristy3ed852e2009-09-05 21:47:34 +00001056 columns,
1057 rows;
1058
1059 if (cache_info->debug != MagickFalse)
1060 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
1061 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
1062 {
1063 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1064 cache_info->cache_filename);
1065 return(MagickFalse);
1066 }
cristybb503372010-05-27 20:51:26 +00001067 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1068 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001069 if ((clone_info->active_index_channel != MagickFalse) &&
1070 (cache_info->active_index_channel != MagickFalse))
1071 {
1072 register IndexPacket
1073 *indexes,
1074 *q;
1075
1076 /*
1077 Clone cache indexes.
1078 */
1079 length=MagickMax(clone_info->columns,cache_info->columns)*
1080 sizeof(*indexes);
1081 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1082 if (indexes == (IndexPacket *) NULL)
1083 {
1084 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1085 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1086 return(MagickFalse);
1087 }
1088 (void) ResetMagickMemory(indexes,0,(size_t) length);
1089 length=columns*sizeof(IndexPacket);
1090 offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
1091 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
1092 q=clone_info->indexes+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001093 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001094 {
1095 offset-=cache_info->columns*sizeof(IndexPacket);
1096 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,
1097 length,(unsigned char *) indexes);
1098 if ((MagickSizeType) count != length)
1099 break;
1100 q-=clone_info->columns;
1101 (void) CopyMagickMemory(q,indexes,(size_t) length);
1102 if ((MagickSizeType) count != length)
1103 break;
1104 }
cristybb503372010-05-27 20:51:26 +00001105 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001106 {
1107 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1108 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1109 cache_info->cache_filename);
1110 return(MagickFalse);
1111 }
1112 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1113 }
1114 /*
1115 Clone cache pixels.
1116 */
1117 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1118 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1119 if (pixels == (PixelPacket *) NULL)
1120 {
1121 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1122 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1123 return(MagickFalse);
1124 }
1125 (void) ResetMagickMemory(pixels,0,(size_t) length);
1126 length=columns*sizeof(*pixels);
1127 offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
1128 q=clone_info->pixels+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001129 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001130 {
1131 offset-=cache_info->columns*sizeof(*pixels);
1132 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,length,
1133 (unsigned char *) pixels);
1134 if ((MagickSizeType) count != length)
1135 break;
1136 q-=clone_info->columns;
1137 (void) CopyMagickMemory(q,pixels,(size_t) length);
1138 }
cristybb503372010-05-27 20:51:26 +00001139 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001140 {
1141 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1142 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1143 cache_info->cache_filename);
1144 return(MagickFalse);
1145 }
1146 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1147 return(MagickTrue);
1148}
1149
1150static MagickBooleanType CloneMemoryToDiskPixelCache(CacheInfo *clone_info,
1151 CacheInfo *cache_info,ExceptionInfo *exception)
1152{
1153 MagickOffsetType
1154 count,
1155 offset;
1156
1157 MagickSizeType
1158 length;
1159
cristybb503372010-05-27 20:51:26 +00001160 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001161 y;
1162
1163 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001164 *restrict p,
1165 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +00001166
cristybb503372010-05-27 20:51:26 +00001167 size_t
cristy3ed852e2009-09-05 21:47:34 +00001168 columns,
1169 rows;
1170
1171 if (cache_info->debug != MagickFalse)
1172 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
1173 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
1174 {
1175 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1176 clone_info->cache_filename);
1177 return(MagickFalse);
1178 }
cristybb503372010-05-27 20:51:26 +00001179 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1180 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001181 if ((clone_info->active_index_channel != MagickFalse) &&
1182 (cache_info->active_index_channel != MagickFalse))
1183 {
1184 register IndexPacket
1185 *p,
1186 *indexes;
1187
1188 /*
1189 Clone cache indexes.
1190 */
1191 length=MagickMax(clone_info->columns,cache_info->columns)*
1192 sizeof(*indexes);
1193 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1194 if (indexes == (IndexPacket *) NULL)
1195 {
1196 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1197 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1198 return(MagickFalse);
1199 }
1200 (void) ResetMagickMemory(indexes,0,(size_t) length);
1201 length=columns*sizeof(*indexes);
1202 p=cache_info->indexes+cache_info->columns*rows;
1203 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1204 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +00001205 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001206 {
1207 p-=cache_info->columns;
1208 (void) CopyMagickMemory(indexes,p,(size_t) length);
1209 offset-=clone_info->columns*sizeof(*indexes);
1210 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1211 (unsigned char *) indexes);
1212 if ((MagickSizeType) count != length)
1213 break;
1214 }
cristybb503372010-05-27 20:51:26 +00001215 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001216 {
1217 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1218 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1219 cache_info->cache_filename);
1220 return(MagickFalse);
1221 }
1222 if (clone_info->columns > cache_info->columns)
1223 {
1224 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
1225 (void) ResetMagickMemory(indexes,0,(size_t) length);
1226 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1227 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +00001228 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001229 {
1230 offset-=clone_info->columns*sizeof(*indexes);
1231 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
1232 length,(unsigned char *) indexes);
1233 if ((MagickSizeType) count != length)
1234 break;
1235 }
cristybb503372010-05-27 20:51:26 +00001236 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001237 {
1238 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1239 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1240 cache_info->cache_filename);
1241 return(MagickFalse);
1242 }
1243 }
1244 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1245 }
1246 /*
1247 Clone cache pixels.
1248 */
1249 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1250 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1251 if (pixels == (PixelPacket *) NULL)
1252 {
1253 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1254 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1255 return(MagickFalse);
1256 }
1257 (void) ResetMagickMemory(pixels,0,(size_t) length);
1258 length=columns*sizeof(*pixels);
1259 p=cache_info->pixels+cache_info->columns*rows;
1260 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +00001261 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001262 {
1263 p-=cache_info->columns;
1264 (void) CopyMagickMemory(pixels,p,(size_t) length);
1265 offset-=clone_info->columns*sizeof(*pixels);
1266 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1267 (unsigned char *) pixels);
1268 if ((MagickSizeType) count != length)
1269 break;
1270 }
cristybb503372010-05-27 20:51:26 +00001271 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001272 {
1273 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1274 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1275 cache_info->cache_filename);
1276 return(MagickFalse);
1277 }
1278 if (clone_info->columns > cache_info->columns)
1279 {
1280 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
1281 sizeof(*pixels);
1282 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1283 (void) ResetMagickMemory(pixels,0,(size_t) length);
cristybb503372010-05-27 20:51:26 +00001284 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001285 {
1286 offset-=clone_info->columns*sizeof(*pixels);
1287 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1288 (unsigned char *) pixels);
1289 if ((MagickSizeType) count != length)
1290 break;
1291 }
cristybb503372010-05-27 20:51:26 +00001292 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001293 {
1294 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1295 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1296 cache_info->cache_filename);
1297 return(MagickFalse);
1298 }
1299 }
1300 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1301 return(MagickTrue);
1302}
1303
1304static MagickBooleanType CloneMemoryToMemoryPixelCache(CacheInfo *clone_info,
1305 CacheInfo *cache_info,ExceptionInfo *magick_unused(exception))
1306{
cristybb503372010-05-27 20:51:26 +00001307 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001308 y;
1309
1310 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001311 *restrict pixels,
1312 *restrict source_pixels;
cristy3ed852e2009-09-05 21:47:34 +00001313
1314 size_t
1315 length;
1316
cristybb503372010-05-27 20:51:26 +00001317 size_t
cristy3ed852e2009-09-05 21:47:34 +00001318 columns,
1319 rows;
1320
1321 if (cache_info->debug != MagickFalse)
1322 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
cristybb503372010-05-27 20:51:26 +00001323 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1324 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001325 if ((clone_info->active_index_channel != MagickFalse) &&
1326 (cache_info->active_index_channel != MagickFalse))
1327 {
1328 register IndexPacket
1329 *indexes,
1330 *source_indexes;
1331
1332 /*
1333 Clone cache indexes.
1334 */
1335 length=columns*sizeof(*indexes);
1336 if (clone_info->columns == cache_info->columns)
1337 (void) CopyMagickMemory(clone_info->indexes,cache_info->indexes,
1338 length*rows);
1339 else
1340 {
1341 source_indexes=cache_info->indexes+cache_info->columns*rows;
1342 indexes=clone_info->indexes+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001343 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001344 {
1345 source_indexes-=cache_info->columns;
1346 indexes-=clone_info->columns;
1347 (void) CopyMagickMemory(indexes,source_indexes,length);
1348 }
1349 if (clone_info->columns > cache_info->columns)
1350 {
1351 length=(clone_info->columns-cache_info->columns)*
1352 sizeof(*indexes);
1353 indexes=clone_info->indexes+clone_info->columns*rows+
1354 cache_info->columns;
cristybb503372010-05-27 20:51:26 +00001355 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001356 {
1357 indexes-=clone_info->columns;
1358 (void) ResetMagickMemory(indexes,0,length);
1359 }
1360 }
1361 }
1362 }
1363 /*
1364 Clone cache pixels.
1365 */
1366 length=columns*sizeof(*pixels);
1367 if (clone_info->columns == cache_info->columns)
1368 (void) CopyMagickMemory(clone_info->pixels,cache_info->pixels,length*rows);
1369 else
1370 {
1371 source_pixels=cache_info->pixels+cache_info->columns*rows;
1372 pixels=clone_info->pixels+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001373 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001374 {
1375 source_pixels-=cache_info->columns;
1376 pixels-=clone_info->columns;
1377 (void) CopyMagickMemory(pixels,source_pixels,length);
1378 }
1379 if (clone_info->columns > cache_info->columns)
1380 {
1381 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1382 pixels=clone_info->pixels+clone_info->columns*rows+
1383 cache_info->columns;
cristybb503372010-05-27 20:51:26 +00001384 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001385 {
1386 pixels-=clone_info->columns;
1387 (void) ResetMagickMemory(pixels,0,length);
1388 }
1389 }
1390 }
1391 return(MagickTrue);
1392}
1393
1394static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1395 CacheInfo *cache_info,ExceptionInfo *exception)
1396{
1397 if ((clone_info->type != DiskCache) && (cache_info->type != DiskCache))
1398 return(CloneMemoryToMemoryPixelCache(clone_info,cache_info,exception));
1399 if ((clone_info->type == DiskCache) && (cache_info->type == DiskCache))
1400 return(CloneDiskToDiskPixelCache(clone_info,cache_info,exception));
1401 if (cache_info->type == DiskCache)
1402 return(CloneDiskToMemoryPixelCache(clone_info,cache_info,exception));
1403 return(CloneMemoryToDiskPixelCache(clone_info,cache_info,exception));
1404}
1405
1406/*
1407%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1408% %
1409% %
1410% %
1411+ C l o n e P i x e l C a c h e M e t h o d s %
1412% %
1413% %
1414% %
1415%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1416%
1417% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1418% another.
1419%
1420% The format of the ClonePixelCacheMethods() method is:
1421%
1422% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1423%
1424% A description of each parameter follows:
1425%
1426% o clone: Specifies a pointer to a Cache structure.
1427%
1428% o cache: the pixel cache.
1429%
1430*/
1431MagickExport void ClonePixelCacheMethods(Cache clone,const Cache cache)
1432{
1433 CacheInfo
1434 *cache_info,
1435 *source_info;
1436
1437 assert(clone != (Cache) NULL);
1438 source_info=(CacheInfo *) clone;
1439 assert(source_info->signature == MagickSignature);
1440 if (source_info->debug != MagickFalse)
1441 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1442 source_info->filename);
1443 assert(cache != (Cache) NULL);
1444 cache_info=(CacheInfo *) cache;
1445 assert(cache_info->signature == MagickSignature);
1446 source_info->methods=cache_info->methods;
1447}
1448
1449/*
1450%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1451% %
1452% %
1453% %
1454+ D e s t r o y I m a g e P i x e l C a c h e %
1455% %
1456% %
1457% %
1458%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1459%
1460% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1461%
1462% The format of the DestroyImagePixelCache() method is:
1463%
1464% void DestroyImagePixelCache(Image *image)
1465%
1466% A description of each parameter follows:
1467%
1468% o image: the image.
1469%
1470*/
1471static void DestroyImagePixelCache(Image *image)
1472{
1473 assert(image != (Image *) NULL);
1474 assert(image->signature == MagickSignature);
1475 if (image->debug != MagickFalse)
1476 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1477 if (image->cache == (void *) NULL)
1478 return;
1479 image->cache=DestroyPixelCache(image->cache);
1480}
1481
1482/*
1483%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1484% %
1485% %
1486% %
1487+ D e s t r o y I m a g e P i x e l s %
1488% %
1489% %
1490% %
1491%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1492%
1493% DestroyImagePixels() deallocates memory associated with the pixel cache.
1494%
1495% The format of the DestroyImagePixels() method is:
1496%
1497% void DestroyImagePixels(Image *image)
1498%
1499% A description of each parameter follows:
1500%
1501% o image: the image.
1502%
1503*/
1504MagickExport void DestroyImagePixels(Image *image)
1505{
1506 CacheInfo
1507 *cache_info;
1508
1509 assert(image != (const Image *) NULL);
1510 assert(image->signature == MagickSignature);
1511 if (image->debug != MagickFalse)
1512 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1513 assert(image->cache != (Cache) NULL);
1514 cache_info=(CacheInfo *) image->cache;
1515 assert(cache_info->signature == MagickSignature);
1516 if (cache_info->methods.destroy_pixel_handler == (DestroyPixelHandler) NULL)
1517 return;
1518 cache_info->methods.destroy_pixel_handler(image);
1519}
1520
1521/*
1522%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1523% %
1524% %
1525% %
1526+ D e s t r o y P i x e l C a c h e %
1527% %
1528% %
1529% %
1530%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1531%
1532% DestroyPixelCache() deallocates memory associated with the pixel cache.
1533%
1534% The format of the DestroyPixelCache() method is:
1535%
1536% Cache DestroyPixelCache(Cache cache)
1537%
1538% A description of each parameter follows:
1539%
1540% o cache: the pixel cache.
1541%
1542*/
1543
1544static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1545{
1546 switch (cache_info->type)
1547 {
1548 case MemoryCache:
1549 {
1550 if (cache_info->mapped == MagickFalse)
1551 cache_info->pixels=(PixelPacket *) RelinquishMagickMemory(
1552 cache_info->pixels);
1553 else
1554 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,
1555 (size_t) cache_info->length);
1556 RelinquishMagickResource(MemoryResource,cache_info->length);
1557 break;
1558 }
1559 case MapCache:
1560 {
1561 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,(size_t)
1562 cache_info->length);
1563 RelinquishMagickResource(MapResource,cache_info->length);
1564 }
1565 case DiskCache:
1566 {
1567 if (cache_info->file != -1)
1568 (void) ClosePixelCacheOnDisk(cache_info);
1569 RelinquishMagickResource(DiskResource,cache_info->length);
1570 break;
1571 }
1572 default:
1573 break;
1574 }
1575 cache_info->type=UndefinedCache;
1576 cache_info->mapped=MagickFalse;
1577 cache_info->indexes=(IndexPacket *) NULL;
1578}
1579
1580MagickExport Cache DestroyPixelCache(Cache cache)
1581{
1582 CacheInfo
1583 *cache_info;
1584
cristy3ed852e2009-09-05 21:47:34 +00001585 assert(cache != (Cache) NULL);
1586 cache_info=(CacheInfo *) cache;
1587 assert(cache_info->signature == MagickSignature);
1588 if (cache_info->debug != MagickFalse)
1589 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1590 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001591 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001592 cache_info->reference_count--;
1593 if (cache_info->reference_count != 0)
1594 {
cristyf84a1932010-01-03 18:00:18 +00001595 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001596 return((Cache) NULL);
1597 }
cristyf84a1932010-01-03 18:00:18 +00001598 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001599 if (cache_resources != (SplayTreeInfo *) NULL)
1600 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
cristy5b8de732009-09-10 23:50:40 +00001601 if (cache_info->debug != MagickFalse)
1602 {
1603 char
1604 message[MaxTextExtent];
1605
1606 (void) FormatMagickString(message,MaxTextExtent,"destroy %s",
1607 cache_info->filename);
1608 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1609 }
cristyc2e1bdd2009-09-10 23:43:34 +00001610 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1611 (cache_info->type != DiskCache)))
1612 RelinquishPixelCachePixels(cache_info);
1613 else
1614 {
1615 RelinquishPixelCachePixels(cache_info);
1616 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1617 }
cristy3ed852e2009-09-05 21:47:34 +00001618 *cache_info->cache_filename='\0';
1619 if (cache_info->nexus_info != (NexusInfo **) NULL)
1620 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1621 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001622 if (cache_info->random_info != (RandomInfo *) NULL)
1623 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001624 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1625 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1626 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1627 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001628 cache_info->signature=(~MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001629 cache_info=(CacheInfo *) RelinquishAlignedMemory(cache_info);
1630 cache=(Cache) NULL;
1631 return(cache);
1632}
1633
1634/*
1635%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1636% %
1637% %
1638% %
1639+ D e s t r o y P i x e l C a c h e N e x u s %
1640% %
1641% %
1642% %
1643%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1644%
1645% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1646%
1647% The format of the DestroyPixelCacheNexus() method is:
1648%
1649% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001650% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001651%
1652% A description of each parameter follows:
1653%
1654% o nexus_info: the nexus to destroy.
1655%
1656% o number_threads: the number of nexus threads.
1657%
1658*/
1659
1660static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1661{
1662 if (nexus_info->mapped == MagickFalse)
1663 (void) RelinquishMagickMemory(nexus_info->cache);
1664 else
1665 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1666 nexus_info->cache=(PixelPacket *) NULL;
1667 nexus_info->pixels=(PixelPacket *) NULL;
1668 nexus_info->indexes=(IndexPacket *) NULL;
1669 nexus_info->length=0;
1670 nexus_info->mapped=MagickFalse;
1671}
1672
1673MagickExport NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001674 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001675{
cristybb503372010-05-27 20:51:26 +00001676 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001677 i;
1678
1679 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001680 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001681 {
1682 if (nexus_info[i]->cache != (PixelPacket *) NULL)
1683 RelinquishCacheNexusPixels(nexus_info[i]);
1684 nexus_info[i]->signature=(~MagickSignature);
1685 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
1686 }
1687 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
1688 return(nexus_info);
1689}
1690
1691/*
1692%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1693% %
1694% %
1695% %
cristy3ed852e2009-09-05 21:47:34 +00001696+ G e t A u t h e n t i c I n d e x e s F r o m C a c h e %
1697% %
1698% %
1699% %
1700%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1701%
1702% GetAuthenticIndexesFromCache() returns the indexes associated with the last
1703% call to QueueAuthenticPixelsCache() or GetAuthenticPixelsCache().
1704%
1705% The format of the GetAuthenticIndexesFromCache() method is:
1706%
1707% IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1708%
1709% A description of each parameter follows:
1710%
1711% o image: the image.
1712%
1713*/
1714static IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1715{
1716 CacheInfo
1717 *cache_info;
1718
1719 IndexPacket
1720 *indexes;
1721
cristy6ebe97c2010-07-03 01:17:28 +00001722 int
cristy3ed852e2009-09-05 21:47:34 +00001723 id;
1724
1725 if (image->debug != MagickFalse)
1726 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1727 cache_info=(CacheInfo *) image->cache;
1728 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00001729 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001730 indexes=GetPixelCacheNexusIndexes(image->cache,cache_info->nexus_info[id]);
1731 return(indexes);
1732}
1733
1734/*
1735%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1736% %
1737% %
1738% %
1739% G e t A u t h e n t i c I n d e x Q u e u e %
1740% %
1741% %
1742% %
1743%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1744%
1745% GetAuthenticIndexQueue() returns the authentic black channel or the colormap
1746% indexes associated with the last call to QueueAuthenticPixels() or
1747% GetVirtualPixels(). NULL is returned if the black channel or colormap
1748% indexes are not available.
1749%
1750% The format of the GetAuthenticIndexQueue() method is:
1751%
1752% IndexPacket *GetAuthenticIndexQueue(const Image *image)
1753%
1754% A description of each parameter follows:
1755%
1756% o image: the image.
1757%
1758*/
1759MagickExport IndexPacket *GetAuthenticIndexQueue(const Image *image)
1760{
1761 CacheInfo
1762 *cache_info;
1763
1764 assert(image != (const Image *) NULL);
1765 assert(image->signature == MagickSignature);
1766 if (image->debug != MagickFalse)
1767 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1768 assert(image->cache != (Cache) NULL);
1769 cache_info=(CacheInfo *) image->cache;
1770 assert(cache_info->signature == MagickSignature);
1771 if (cache_info->methods.get_authentic_indexes_from_handler ==
1772 (GetAuthenticIndexesFromHandler) NULL)
1773 return((IndexPacket *) NULL);
1774 return(cache_info->methods.get_authentic_indexes_from_handler(image));
1775}
1776
1777/*
1778%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1779% %
1780% %
1781% %
1782+ G e t A u t h e n t i c P i x e l C a c h e N e x u s %
1783% %
1784% %
1785% %
1786%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1787%
1788% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1789% disk pixel cache as defined by the geometry parameters. A pointer to the
1790% pixels is returned if the pixels are transferred, otherwise a NULL is
1791% returned.
1792%
1793% The format of the GetAuthenticPixelCacheNexus() method is:
1794%
cristybb503372010-05-27 20:51:26 +00001795% PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1796% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001797% NexusInfo *nexus_info,ExceptionInfo *exception)
1798%
1799% A description of each parameter follows:
1800%
1801% o image: the image.
1802%
1803% o x,y,columns,rows: These values define the perimeter of a region of
1804% pixels.
1805%
1806% o nexus_info: the cache nexus to return.
1807%
1808% o exception: return any errors or warnings in this structure.
1809%
1810*/
1811
1812static inline MagickBooleanType IsNexusInCore(const CacheInfo *cache_info,
1813 NexusInfo *nexus_info)
1814{
1815 MagickOffsetType
1816 offset;
1817
cristy73724512010-04-12 14:43:14 +00001818 if (cache_info->type == PingCache)
1819 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001820 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1821 nexus_info->region.x;
1822 if (nexus_info->pixels != (cache_info->pixels+offset))
1823 return(MagickFalse);
1824 return(MagickTrue);
1825}
1826
cristybb503372010-05-27 20:51:26 +00001827MagickExport PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1828 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001829 NexusInfo *nexus_info,ExceptionInfo *exception)
1830{
1831 CacheInfo
1832 *cache_info;
1833
1834 PixelPacket
1835 *pixels;
1836
1837 /*
1838 Transfer pixels from the cache.
1839 */
1840 assert(image != (Image *) NULL);
1841 assert(image->signature == MagickSignature);
1842 if (image->debug != MagickFalse)
1843 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1844 pixels=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
1845 if (pixels == (PixelPacket *) NULL)
1846 return((PixelPacket *) NULL);
1847 cache_info=(CacheInfo *) image->cache;
1848 assert(cache_info->signature == MagickSignature);
1849 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
1850 return(pixels);
1851 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1852 return((PixelPacket *) NULL);
1853 if (cache_info->active_index_channel != MagickFalse)
1854 if (ReadPixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse)
1855 return((PixelPacket *) NULL);
1856 return(pixels);
1857}
1858
1859/*
1860%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1861% %
1862% %
1863% %
1864+ G e t A u t h e n t i c P i x e l s F r o m C a c h e %
1865% %
1866% %
1867% %
1868%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1869%
1870% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1871% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1872%
1873% The format of the GetAuthenticPixelsFromCache() method is:
1874%
1875% PixelPacket *GetAuthenticPixelsFromCache(const Image image)
1876%
1877% A description of each parameter follows:
1878%
1879% o image: the image.
1880%
1881*/
1882static PixelPacket *GetAuthenticPixelsFromCache(const Image *image)
1883{
1884 CacheInfo
1885 *cache_info;
1886
cristy6ebe97c2010-07-03 01:17:28 +00001887 int
cristy3ed852e2009-09-05 21:47:34 +00001888 id;
1889
1890 PixelPacket
1891 *pixels;
1892
1893 if (image->debug != MagickFalse)
1894 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1895 cache_info=(CacheInfo *) image->cache;
1896 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00001897 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001898 pixels=GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]);
1899 return(pixels);
1900}
1901
1902/*
1903%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1904% %
1905% %
1906% %
1907% G e t A u t h e n t i c P i x e l Q u e u e %
1908% %
1909% %
1910% %
1911%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1912%
1913% GetAuthenticPixelQueue() returns the authentic pixels associated with the
1914% last call to QueueAuthenticPixels() or GetAuthenticPixels().
1915%
1916% The format of the GetAuthenticPixelQueue() method is:
1917%
1918% PixelPacket *GetAuthenticPixelQueue(const Image image)
1919%
1920% A description of each parameter follows:
1921%
1922% o image: the image.
1923%
1924*/
1925MagickExport PixelPacket *GetAuthenticPixelQueue(const Image *image)
1926{
1927 CacheInfo
1928 *cache_info;
1929
1930 assert(image != (const Image *) NULL);
1931 assert(image->signature == MagickSignature);
1932 if (image->debug != MagickFalse)
1933 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1934 assert(image->cache != (Cache) NULL);
1935 cache_info=(CacheInfo *) image->cache;
1936 assert(cache_info->signature == MagickSignature);
1937 if (cache_info->methods.get_authentic_pixels_from_handler ==
1938 (GetAuthenticPixelsFromHandler) NULL)
1939 return((PixelPacket *) NULL);
1940 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1941}
1942
1943/*
1944%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1945% %
1946% %
1947% %
1948% G e t A u t h e n t i c P i x e l s %
1949% %
1950% %
1951% %
1952%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1953%
1954% GetAuthenticPixels() obtains a pixel region for read/write access. If the
1955% region is successfully accessed, a pointer to a PixelPacket array
1956% representing the region is returned, otherwise NULL is returned.
1957%
1958% The returned pointer may point to a temporary working copy of the pixels
1959% or it may point to the original pixels in memory. Performance is maximized
1960% if the selected region is part of one row, or one or more full rows, since
1961% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001962% if the image is in memory, or in a memory-mapped file. The returned pointer
1963% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001964%
1965% Pixels accessed via the returned pointer represent a simple array of type
1966% PixelPacket. If the image type is CMYK or if the storage class is
1967% PseduoClass, call GetAuthenticIndexQueue() after invoking
1968% GetAuthenticPixels() to obtain the black color component or colormap indexes
1969% (of type IndexPacket) corresponding to the region. Once the PixelPacket
1970% (and/or IndexPacket) array has been updated, the changes must be saved back
1971% to the underlying image using SyncAuthenticPixels() or they may be lost.
1972%
1973% The format of the GetAuthenticPixels() method is:
1974%
cristy5f959472010-05-27 22:19:46 +00001975% PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1976% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001977% ExceptionInfo *exception)
1978%
1979% A description of each parameter follows:
1980%
1981% o image: the image.
1982%
1983% o x,y,columns,rows: These values define the perimeter of a region of
1984% pixels.
1985%
1986% o exception: return any errors or warnings in this structure.
1987%
1988*/
cristybb503372010-05-27 20:51:26 +00001989MagickExport PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1990 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001991 ExceptionInfo *exception)
1992{
1993 CacheInfo
1994 *cache_info;
1995
1996 PixelPacket
1997 *pixels;
1998
1999 assert(image != (Image *) NULL);
2000 assert(image->signature == MagickSignature);
2001 if (image->debug != MagickFalse)
2002 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2003 assert(image->cache != (Cache) NULL);
2004 cache_info=(CacheInfo *) image->cache;
2005 assert(cache_info->signature == MagickSignature);
2006 if (cache_info->methods.get_authentic_pixels_handler ==
2007 (GetAuthenticPixelsHandler) NULL)
2008 return((PixelPacket *) NULL);
2009 pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
2010 rows,exception);
2011 return(pixels);
2012}
2013
2014/*
2015%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2016% %
2017% %
2018% %
2019+ G e t A u t h e n t i c P i x e l s C a c h e %
2020% %
2021% %
2022% %
2023%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2024%
2025% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
2026% as defined by the geometry parameters. A pointer to the pixels is returned
2027% if the pixels are transferred, otherwise a NULL is returned.
2028%
2029% The format of the GetAuthenticPixelsCache() method is:
2030%
cristybb503372010-05-27 20:51:26 +00002031% PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
2032% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00002033% ExceptionInfo *exception)
2034%
2035% A description of each parameter follows:
2036%
2037% o image: the image.
2038%
2039% o x,y,columns,rows: These values define the perimeter of a region of
2040% pixels.
2041%
2042% o exception: return any errors or warnings in this structure.
2043%
2044*/
cristybb503372010-05-27 20:51:26 +00002045static PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
2046 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00002047 ExceptionInfo *exception)
2048{
2049 CacheInfo
2050 *cache_info;
2051
cristy6ebe97c2010-07-03 01:17:28 +00002052 int
cristy3ed852e2009-09-05 21:47:34 +00002053 id;
2054
2055 PixelPacket
2056 *pixels;
2057
2058 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
2059 if (cache_info == (Cache) NULL)
2060 return((PixelPacket *) NULL);
2061 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00002062 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00002063 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
2064 cache_info->nexus_info[id],exception);
2065 return(pixels);
2066}
2067
2068/*
2069%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2070% %
2071% %
2072% %
2073+ G e t I m a g e E x t e n t %
2074% %
2075% %
2076% %
2077%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2078%
2079% GetImageExtent() returns the extent of the pixels associated with the
2080% last call to QueueAuthenticPixels() or GetAuthenticPixels().
2081%
2082% The format of the GetImageExtent() method is:
2083%
2084% MagickSizeType GetImageExtent(const Image *image)
2085%
2086% A description of each parameter follows:
2087%
2088% o image: the image.
2089%
2090*/
2091MagickExport MagickSizeType GetImageExtent(const Image *image)
2092{
2093 CacheInfo
2094 *cache_info;
2095
cristy6ebe97c2010-07-03 01:17:28 +00002096 int
cristy3ed852e2009-09-05 21:47:34 +00002097 id;
2098
2099 MagickSizeType
2100 extent;
2101
2102 assert(image != (Image *) NULL);
2103 assert(image->signature == MagickSignature);
2104 if (image->debug != MagickFalse)
2105 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2106 assert(image->cache != (Cache) NULL);
2107 cache_info=(CacheInfo *) image->cache;
2108 assert(cache_info->signature == MagickSignature);
2109 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00002110 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00002111 extent=GetPixelCacheNexusExtent(image->cache,cache_info->nexus_info[id]);
2112 return(extent);
2113}
2114
2115/*
2116%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2117% %
2118% %
2119% %
2120+ G e t I m a g e P i x e l C a c h e %
2121% %
2122% %
2123% %
2124%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2125%
2126% GetImagePixelCache() ensures that there is only a single reference to the
2127% pixel cache to be modified, updating the provided cache pointer to point to
2128% a clone of the original pixel cache if necessary.
2129%
2130% The format of the GetImagePixelCache method is:
2131%
2132% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2133% ExceptionInfo *exception)
2134%
2135% A description of each parameter follows:
2136%
2137% o image: the image.
2138%
2139% o clone: any value other than MagickFalse clones the cache pixels.
2140%
2141% o exception: return any errors or warnings in this structure.
2142%
2143*/
cristy3ed852e2009-09-05 21:47:34 +00002144static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
2145{
2146 CacheInfo
2147 *cache_info;
2148
2149 /*
2150 Does the image match the pixel cache morphology?
2151 */
2152 cache_info=(CacheInfo *) image->cache;
2153 if ((image->storage_class != cache_info->storage_class) ||
2154 (image->colorspace != cache_info->colorspace) ||
2155 (image->columns != cache_info->columns) ||
2156 (image->rows != cache_info->rows) ||
2157 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2158 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2159 return(MagickFalse);
2160 return(MagickTrue);
2161}
2162
2163MagickExport Cache GetImagePixelCache(Image *image,
2164 const MagickBooleanType clone,ExceptionInfo *exception)
2165{
2166 CacheInfo
2167 *cache_info;
2168
cristy3ed852e2009-09-05 21:47:34 +00002169 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00002170 destroy,
cristy3ed852e2009-09-05 21:47:34 +00002171 status;
2172
cristy50a10922010-02-15 18:35:25 +00002173 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00002174 cpu_throttle = 0,
2175 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00002176 time_limit = 0;
2177
cristy1ea34962010-07-01 19:49:21 +00002178 static time_t
cristya21afde2010-07-02 00:45:40 +00002179 cache_genesis = 0;
cristy1ea34962010-07-01 19:49:21 +00002180
cristy3ed852e2009-09-05 21:47:34 +00002181 if (image->debug != MagickFalse)
2182 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristyc4f9f132010-03-04 18:50:01 +00002183 status=MagickTrue;
2184 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00002185 if (cpu_throttle == 0)
2186 {
2187 char
2188 *limit;
2189
2190 /*
2191 Set CPU throttle in milleseconds.
2192 */
2193 cpu_throttle=MagickResourceInfinity;
2194 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2195 if (limit == (char *) NULL)
2196 limit=GetPolicyValue("throttle");
2197 if (limit != (char *) NULL)
2198 {
2199 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2200 limit=DestroyString(limit);
2201 }
2202 }
2203 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2204 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00002205 if (time_limit == 0)
2206 {
cristy6ebe97c2010-07-03 01:17:28 +00002207 /*
2208 Set the exire time in seconds.
2209 */
cristy1ea34962010-07-01 19:49:21 +00002210 time_limit=GetMagickResourceLimit(TimeResource);
cristya21afde2010-07-02 00:45:40 +00002211 cache_genesis=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00002212 }
2213 if ((time_limit != MagickResourceInfinity) &&
cristya21afde2010-07-02 00:45:40 +00002214 ((MagickSizeType) (time((time_t *) NULL)-cache_genesis) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00002215 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00002216 assert(image->cache != (Cache) NULL);
2217 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002218 destroy=MagickFalse;
cristy01b7eb02009-09-10 23:10:14 +00002219 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002220 {
cristyaaa0cb62010-02-15 17:47:27 +00002221 LockSemaphoreInfo(cache_info->semaphore);
2222 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002223 {
cristyaaa0cb62010-02-15 17:47:27 +00002224 Image
2225 clone_image;
2226
2227 CacheInfo
2228 *clone_info;
2229
2230 /*
2231 Clone pixel cache.
2232 */
2233 clone_image=(*image);
2234 clone_image.cache=ClonePixelCache(cache_info);
2235 clone_info=(CacheInfo *) clone_image.cache;
2236 status=ClonePixelCacheNexus(cache_info,clone_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002237 if (status != MagickFalse)
2238 {
cristyaaa0cb62010-02-15 17:47:27 +00002239 status=OpenPixelCache(&clone_image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00002240 if (status != MagickFalse)
2241 {
cristyaaa0cb62010-02-15 17:47:27 +00002242 if (clone != MagickFalse)
2243 status=ClonePixelCachePixels(clone_info,cache_info,
2244 exception);
2245 if (status != MagickFalse)
2246 {
2247 destroy=MagickTrue;
2248 image->cache=clone_image.cache;
2249 }
cristy3ed852e2009-09-05 21:47:34 +00002250 }
2251 }
2252 }
cristyaaa0cb62010-02-15 17:47:27 +00002253 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002254 }
cristy4320e0e2009-09-10 15:00:08 +00002255 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002256 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002257 if (status != MagickFalse)
2258 {
2259 /*
2260 Ensure the image matches the pixel cache morphology.
2261 */
2262 image->taint=MagickTrue;
2263 image->type=UndefinedType;
cristydd438462010-05-06 13:44:04 +00002264 if (image->colorspace == GRAYColorspace)
2265 image->colorspace=RGBColorspace;
cristy3ed852e2009-09-05 21:47:34 +00002266 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2267 status=OpenPixelCache(image,IOMode,exception);
2268 }
cristyf84a1932010-01-03 18:00:18 +00002269 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002270 if (status == MagickFalse)
2271 return((Cache) NULL);
2272 return(image->cache);
2273}
2274
2275/*
2276%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2277% %
2278% %
2279% %
2280% G e t O n e A u t h e n t i c P i x e l %
2281% %
2282% %
2283% %
2284%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2285%
2286% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2287% location. The image background color is returned if an error occurs.
2288%
2289% The format of the GetOneAuthenticPixel() method is:
2290%
cristybb503372010-05-27 20:51:26 +00002291% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2292% const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002293%
2294% A description of each parameter follows:
2295%
2296% o image: the image.
2297%
2298% o x,y: These values define the location of the pixel to return.
2299%
2300% o pixel: return a pixel at the specified (x,y) location.
2301%
2302% o exception: return any errors or warnings in this structure.
2303%
2304*/
cristyacbbb7c2010-06-30 18:56:48 +00002305MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2306 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002307{
2308 CacheInfo
2309 *cache_info;
2310
2311 GetOneAuthenticPixelFromHandler
2312 get_one_authentic_pixel_from_handler;
2313
2314 MagickBooleanType
2315 status;
2316
2317 assert(image != (Image *) NULL);
2318 assert(image->signature == MagickSignature);
2319 if (image->debug != MagickFalse)
2320 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2321 assert(image->cache != (Cache) NULL);
2322 cache_info=(CacheInfo *) image->cache;
2323 assert(cache_info->signature == MagickSignature);
2324 *pixel=image->background_color;
2325 get_one_authentic_pixel_from_handler=
2326 cache_info->methods.get_one_authentic_pixel_from_handler;
2327 if (get_one_authentic_pixel_from_handler ==
2328 (GetOneAuthenticPixelFromHandler) NULL)
2329 return(MagickFalse);
2330 status=cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2331 pixel,exception);
2332 return(status);
2333}
2334
2335/*
2336%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2337% %
2338% %
2339% %
2340+ 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 %
2341% %
2342% %
2343% %
2344%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2345%
2346% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2347% location. The image background color is returned if an error occurs.
2348%
2349% The format of the GetOneAuthenticPixelFromCache() method is:
2350%
2351% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy5f959472010-05-27 22:19:46 +00002352% const ssize_t x,const ssize_t y,PixelPacket *pixel,
2353% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002354%
2355% A description of each parameter follows:
2356%
2357% o image: the image.
2358%
2359% o x,y: These values define the location of the pixel to return.
2360%
2361% o pixel: return a pixel at the specified (x,y) location.
2362%
2363% o exception: return any errors or warnings in this structure.
2364%
2365*/
2366static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristybb503372010-05-27 20:51:26 +00002367 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002368{
2369 PixelPacket
2370 *pixels;
2371
2372 if (image->debug != MagickFalse)
2373 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2374 *pixel=image->background_color;
2375 pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2376 if (pixels == (PixelPacket *) NULL)
2377 return(MagickFalse);
2378 *pixel=(*pixels);
2379 return(MagickTrue);
2380}
2381
2382/*
2383%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2384% %
2385% %
2386% %
2387% G e t O n e V i r t u a l M a g i c k P i x e l %
2388% %
2389% %
2390% %
2391%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2392%
2393% GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2394% location. The image background color is returned if an error occurs. If
2395% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2396%
2397% The format of the GetOneVirtualMagickPixel() method is:
2398%
2399% MagickBooleanType GetOneVirtualMagickPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002400% const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
cristy3ed852e2009-09-05 21:47:34 +00002401% ExceptionInfo exception)
2402%
2403% A description of each parameter follows:
2404%
2405% o image: the image.
2406%
2407% o x,y: these values define the location of the pixel to return.
2408%
2409% o pixel: return a pixel at the specified (x,y) location.
2410%
2411% o exception: return any errors or warnings in this structure.
2412%
2413*/
2414MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
cristyacbbb7c2010-06-30 18:56:48 +00002415 const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
2416 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002417{
2418 CacheInfo
2419 *cache_info;
2420
2421 register const IndexPacket
2422 *indexes;
2423
2424 register const PixelPacket
2425 *p;
2426
2427 assert(image != (const Image *) NULL);
2428 assert(image->signature == MagickSignature);
2429 assert(image->cache != (Cache) NULL);
2430 cache_info=(CacheInfo *) image->cache;
2431 assert(cache_info->signature == MagickSignature);
2432 GetMagickPixelPacket(image,pixel);
2433 p=GetVirtualPixelCache(image,GetPixelCacheVirtualMethod(image),x,y,1,1,
2434 exception);
2435 if (p == (const PixelPacket *) NULL)
2436 return(MagickFalse);
2437 indexes=GetVirtualIndexQueue(image);
2438 SetMagickPixelPacket(image,p,indexes,pixel);
2439 return(MagickTrue);
2440}
2441
2442/*
2443%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2444% %
2445% %
2446% %
2447% G e t O n e V i r t u a l M e t h o d P i x e l %
2448% %
2449% %
2450% %
2451%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2452%
2453% GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2454% location as defined by specified pixel method. The image background color
2455% is returned if an error occurs. If you plan to modify the pixel, use
2456% GetOneAuthenticPixel() instead.
2457%
2458% The format of the GetOneVirtualMethodPixel() method is:
2459%
2460% MagickBooleanType GetOneVirtualMethodPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002461% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2462% const ssize_t y,Pixelpacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002463%
2464% A description of each parameter follows:
2465%
2466% o image: the image.
2467%
2468% o virtual_pixel_method: the virtual pixel method.
2469%
2470% o x,y: These values define the location of the pixel to return.
2471%
2472% o pixel: return a pixel at the specified (x,y) location.
2473%
2474% o exception: return any errors or warnings in this structure.
2475%
2476*/
2477MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002478 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002479 PixelPacket *pixel,ExceptionInfo *exception)
2480{
2481 GetOneVirtualPixelFromHandler
2482 get_one_virtual_pixel_from_handler;
2483
2484 CacheInfo
2485 *cache_info;
2486
2487 MagickBooleanType
2488 status;
2489
2490 assert(image != (const Image *) NULL);
2491 assert(image->signature == MagickSignature);
2492 assert(image->cache != (Cache) NULL);
2493 cache_info=(CacheInfo *) image->cache;
2494 assert(cache_info->signature == MagickSignature);
2495 *pixel=image->background_color;
2496 get_one_virtual_pixel_from_handler=
2497 cache_info->methods.get_one_virtual_pixel_from_handler;
2498 if (get_one_virtual_pixel_from_handler ==
2499 (GetOneVirtualPixelFromHandler) NULL)
2500 return(MagickFalse);
2501 status=get_one_virtual_pixel_from_handler(image,virtual_pixel_method,x,y,
2502 pixel,exception);
2503 return(status);
2504}
2505
2506/*
2507%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2508% %
2509% %
2510% %
2511% G e t O n e V i r t u a l P i x e l %
2512% %
2513% %
2514% %
2515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2516%
2517% GetOneVirtualPixel() returns a single virtual pixel at the specified
2518% (x,y) location. The image background color is returned if an error occurs.
2519% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2520%
2521% The format of the GetOneVirtualPixel() method is:
2522%
cristybb503372010-05-27 20:51:26 +00002523% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2524% const ssize_t y,PixelPacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002525%
2526% A description of each parameter follows:
2527%
2528% o image: the image.
2529%
2530% o x,y: These values define the location of the pixel to return.
2531%
2532% o pixel: return a pixel at the specified (x,y) location.
2533%
2534% o exception: return any errors or warnings in this structure.
2535%
2536*/
2537MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002538 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002539{
2540 GetOneVirtualPixelFromHandler
2541 get_one_virtual_pixel_from_handler;
2542
2543 CacheInfo
2544 *cache_info;
2545
2546 MagickBooleanType
2547 status;
2548
2549 assert(image != (const Image *) NULL);
2550 assert(image->signature == MagickSignature);
2551 assert(image->cache != (Cache) NULL);
2552 cache_info=(CacheInfo *) image->cache;
2553 assert(cache_info->signature == MagickSignature);
2554 *pixel=image->background_color;
2555 get_one_virtual_pixel_from_handler=
2556 cache_info->methods.get_one_virtual_pixel_from_handler;
2557 if (get_one_virtual_pixel_from_handler ==
2558 (GetOneVirtualPixelFromHandler) NULL)
2559 return(MagickFalse);
2560 status=get_one_virtual_pixel_from_handler(image,GetPixelCacheVirtualMethod(
2561 image),x,y,pixel,exception);
2562 return(status);
2563}
2564
2565/*
2566%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2567% %
2568% %
2569% %
2570+ 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 %
2571% %
2572% %
2573% %
2574%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2575%
2576% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2577% specified (x,y) location. The image background color is returned if an
2578% error occurs.
2579%
2580% The format of the GetOneVirtualPixelFromCache() method is:
2581%
2582% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristybb503372010-05-27 20:51:26 +00002583% const VirtualPixelPacket method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002584% PixelPacket *pixel,ExceptionInfo *exception)
2585%
2586% A description of each parameter follows:
2587%
2588% o image: the image.
2589%
2590% o virtual_pixel_method: the virtual pixel method.
2591%
2592% o x,y: These values define the location of the pixel to return.
2593%
2594% o pixel: return a pixel at the specified (x,y) location.
2595%
2596% o exception: return any errors or warnings in this structure.
2597%
2598*/
2599static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002600 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002601 PixelPacket *pixel,ExceptionInfo *exception)
2602{
2603 const PixelPacket
2604 *pixels;
2605
2606 *pixel=image->background_color;
2607 pixels=GetVirtualPixelCache(image,virtual_pixel_method,x,y,1UL,1UL,exception);
2608 if (pixels == (const PixelPacket *) NULL)
2609 return(MagickFalse);
2610 *pixel=(*pixels);
2611 return(MagickTrue);
2612}
2613
2614/*
2615%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2616% %
2617% %
2618% %
2619+ G e t P i x e l C a c h e C o l o r s p a c e %
2620% %
2621% %
2622% %
2623%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2624%
2625% GetPixelCacheColorspace() returns the class type of the pixel cache.
2626%
2627% The format of the GetPixelCacheColorspace() method is:
2628%
2629% Colorspace GetPixelCacheColorspace(Cache cache)
2630%
2631% A description of each parameter follows:
2632%
2633% o cache: the pixel cache.
2634%
2635*/
2636MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
2637{
2638 CacheInfo
2639 *cache_info;
2640
2641 assert(cache != (Cache) NULL);
2642 cache_info=(CacheInfo *) cache;
2643 assert(cache_info->signature == MagickSignature);
2644 if (cache_info->debug != MagickFalse)
2645 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2646 cache_info->filename);
2647 return(cache_info->colorspace);
2648}
2649
2650/*
2651%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2652% %
2653% %
2654% %
2655+ G e t P i x e l C a c h e M e t h o d s %
2656% %
2657% %
2658% %
2659%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2660%
2661% GetPixelCacheMethods() initializes the CacheMethods structure.
2662%
2663% The format of the GetPixelCacheMethods() method is:
2664%
2665% void GetPixelCacheMethods(CacheMethods *cache_methods)
2666%
2667% A description of each parameter follows:
2668%
2669% o cache_methods: Specifies a pointer to a CacheMethods structure.
2670%
2671*/
2672MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
2673{
2674 assert(cache_methods != (CacheMethods *) NULL);
2675 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2676 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2677 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2678 cache_methods->get_virtual_indexes_from_handler=GetVirtualIndexesFromCache;
2679 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2680 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2681 cache_methods->get_authentic_indexes_from_handler=
2682 GetAuthenticIndexesFromCache;
2683 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2684 cache_methods->get_one_authentic_pixel_from_handler=
2685 GetOneAuthenticPixelFromCache;
2686 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2687 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2688 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2689}
2690
2691/*
2692%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2693% %
2694% %
2695% %
2696+ G e t P i x e l C a c h e N e x u s E x t e n t %
2697% %
2698% %
2699% %
2700%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2701%
2702% GetPixelCacheNexusExtent() returns the extent of the pixels associated with
2703% the last call to SetPixelCacheNexusPixels() or GetPixelCacheNexusPixels().
2704%
2705% The format of the GetPixelCacheNexusExtent() method is:
2706%
2707% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2708% NexusInfo *nexus_info)
2709%
2710% A description of each parameter follows:
2711%
2712% o nexus_info: the nexus info.
2713%
2714*/
2715MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2716 NexusInfo *nexus_info)
2717{
2718 CacheInfo
2719 *cache_info;
2720
2721 MagickSizeType
2722 extent;
2723
2724 if (cache == (Cache) NULL)
2725 return(0);
2726 cache_info=(CacheInfo *) cache;
2727 assert(cache_info->signature == MagickSignature);
2728 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2729 if (extent == 0)
2730 return((MagickSizeType) cache_info->columns*cache_info->rows);
2731 return(extent);
2732}
2733
2734/*
2735%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2736% %
2737% %
2738% %
2739+ 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 %
2740% %
2741% %
2742% %
2743%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2744%
2745% GetPixelCacheNexusIndexes() returns the indexes associated with the
2746% specified cache nexus.
2747%
2748% The format of the GetPixelCacheNexusIndexes() method is:
2749%
2750% IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2751% NexusInfo *nexus_info)
2752%
2753% A description of each parameter follows:
2754%
2755% o cache: the pixel cache.
2756%
2757% o nexus_info: the cache nexus to return the colormap indexes.
2758%
2759*/
2760MagickExport IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2761 NexusInfo *nexus_info)
2762{
2763 CacheInfo
2764 *cache_info;
2765
2766 if (cache == (Cache) NULL)
2767 return((IndexPacket *) NULL);
2768 cache_info=(CacheInfo *) cache;
2769 assert(cache_info->signature == MagickSignature);
2770 if (cache_info->storage_class == UndefinedClass)
2771 return((IndexPacket *) NULL);
2772 return(nexus_info->indexes);
2773}
2774
2775/*
2776%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2777% %
2778% %
2779% %
2780+ G e t P i x e l C a c h e N e x u s P i x e l s %
2781% %
2782% %
2783% %
2784%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2785%
2786% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2787% cache nexus.
2788%
2789% The format of the GetPixelCacheNexusPixels() method is:
2790%
2791% PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2792% NexusInfo *nexus_info)
2793%
2794% A description of each parameter follows:
2795%
2796% o cache: the pixel cache.
2797%
2798% o nexus_info: the cache nexus to return the pixels.
2799%
2800*/
2801MagickExport PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2802 NexusInfo *nexus_info)
2803{
2804 CacheInfo
2805 *cache_info;
2806
2807 if (cache == (Cache) NULL)
2808 return((PixelPacket *) NULL);
2809 cache_info=(CacheInfo *) cache;
2810 assert(cache_info->signature == MagickSignature);
2811 if (cache_info->debug != MagickFalse)
2812 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2813 cache_info->filename);
2814 if (cache_info->storage_class == UndefinedClass)
2815 return((PixelPacket *) NULL);
2816 return(nexus_info->pixels);
2817}
2818
2819/*
2820%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2821% %
2822% %
2823% %
cristy056ba772010-01-02 23:33:54 +00002824+ G e t P i x e l C a c h e P i x e l s %
2825% %
2826% %
2827% %
2828%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2829%
2830% GetPixelCachePixels() returns the pixels associated with the specified image.
2831%
2832% The format of the GetPixelCachePixels() method is:
2833%
cristyf84a1932010-01-03 18:00:18 +00002834% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2835% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002836%
2837% A description of each parameter follows:
2838%
2839% o image: the image.
2840%
2841% o length: the pixel cache length.
2842%
cristyf84a1932010-01-03 18:00:18 +00002843% o exception: return any errors or warnings in this structure.
2844%
cristy056ba772010-01-02 23:33:54 +00002845*/
cristyf84a1932010-01-03 18:00:18 +00002846MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2847 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002848{
2849 CacheInfo
2850 *cache_info;
2851
2852 assert(image != (const Image *) NULL);
2853 assert(image->signature == MagickSignature);
2854 if (image->debug != MagickFalse)
2855 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2856 assert(image->cache != (Cache) NULL);
cristyc4c8d132010-01-07 01:58:38 +00002857 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
cristy056ba772010-01-02 23:33:54 +00002858 assert(cache_info->signature == MagickSignature);
2859 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002860 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002861 return((void *) NULL);
2862 *length=cache_info->length;
2863 return((void *) cache_info->pixels);
2864}
2865
2866/*
2867%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2868% %
2869% %
2870% %
cristyb32b90a2009-09-07 21:45:48 +00002871+ 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 +00002872% %
2873% %
2874% %
2875%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2876%
2877% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2878%
2879% The format of the GetPixelCacheStorageClass() method is:
2880%
2881% ClassType GetPixelCacheStorageClass(Cache cache)
2882%
2883% A description of each parameter follows:
2884%
2885% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2886%
2887% o cache: the pixel cache.
2888%
2889*/
2890MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
2891{
2892 CacheInfo
2893 *cache_info;
2894
2895 assert(cache != (Cache) NULL);
2896 cache_info=(CacheInfo *) cache;
2897 assert(cache_info->signature == MagickSignature);
2898 if (cache_info->debug != MagickFalse)
2899 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2900 cache_info->filename);
2901 return(cache_info->storage_class);
2902}
2903
2904/*
2905%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2906% %
2907% %
2908% %
cristyb32b90a2009-09-07 21:45:48 +00002909+ G e t P i x e l C a c h e T i l e S i z e %
2910% %
2911% %
2912% %
2913%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2914%
2915% GetPixelCacheTileSize() returns the pixel cache tile size.
2916%
2917% The format of the GetPixelCacheTileSize() method is:
2918%
cristybb503372010-05-27 20:51:26 +00002919% void GetPixelCacheTileSize(const Image *image,size_t *width,
2920% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002921%
2922% A description of each parameter follows:
2923%
2924% o image: the image.
2925%
2926% o width: the optimize cache tile width in pixels.
2927%
2928% o height: the optimize cache tile height in pixels.
2929%
2930*/
cristybb503372010-05-27 20:51:26 +00002931MagickExport void GetPixelCacheTileSize(const Image *image,size_t *width,
2932 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002933{
2934 CacheInfo
2935 *cache_info;
2936
2937 assert(image != (Image *) NULL);
2938 assert(image->signature == MagickSignature);
2939 if (image->debug != MagickFalse)
2940 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2941 assert(image->cache != (Cache) NULL);
2942 cache_info=(CacheInfo *) image->cache;
2943 assert(cache_info->signature == MagickSignature);
2944 *width=2048UL/sizeof(PixelPacket);
2945 if (GetPixelCacheType(image) == DiskCache)
cristydaa97692009-09-13 02:10:35 +00002946 *width=8192UL/sizeof(PixelPacket);
cristyb32b90a2009-09-07 21:45:48 +00002947 *height=(*width);
2948}
2949
2950/*
2951%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2952% %
2953% %
2954% %
2955+ G e t P i x e l C a c h e T y p e %
2956% %
2957% %
2958% %
2959%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2960%
2961% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2962%
2963% The format of the GetPixelCacheType() method is:
2964%
2965% CacheType GetPixelCacheType(const Image *image)
2966%
2967% A description of each parameter follows:
2968%
2969% o image: the image.
2970%
2971*/
2972MagickExport CacheType GetPixelCacheType(const Image *image)
2973{
2974 CacheInfo
2975 *cache_info;
2976
2977 assert(image != (Image *) NULL);
2978 assert(image->signature == MagickSignature);
2979 if (image->debug != MagickFalse)
2980 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2981 assert(image->cache != (Cache) NULL);
2982 cache_info=(CacheInfo *) image->cache;
2983 assert(cache_info->signature == MagickSignature);
2984 return(cache_info->type);
2985}
2986
2987/*
2988%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2989% %
2990% %
2991% %
cristy3ed852e2009-09-05 21:47:34 +00002992+ 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 %
2993% %
2994% %
2995% %
2996%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2997%
2998% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2999% pixel cache. A virtual pixel is any pixel access that is outside the
3000% boundaries of the image cache.
3001%
3002% The format of the GetPixelCacheVirtualMethod() method is:
3003%
3004% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
3005%
3006% A description of each parameter follows:
3007%
3008% o image: the image.
3009%
3010*/
3011MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
3012{
3013 CacheInfo
3014 *cache_info;
3015
3016 assert(image != (Image *) NULL);
3017 assert(image->signature == MagickSignature);
3018 if (image->debug != MagickFalse)
3019 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3020 assert(image->cache != (Cache) NULL);
3021 cache_info=(CacheInfo *) image->cache;
3022 assert(cache_info->signature == MagickSignature);
3023 return(cache_info->virtual_pixel_method);
3024}
3025
3026/*
3027%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3028% %
3029% %
3030% %
3031+ 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 %
3032% %
3033% %
3034% %
3035%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3036%
3037% GetVirtualIndexesFromCache() returns the indexes associated with the last
3038% call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3039%
3040% The format of the GetVirtualIndexesFromCache() method is:
3041%
3042% IndexPacket *GetVirtualIndexesFromCache(const Image *image)
3043%
3044% A description of each parameter follows:
3045%
3046% o image: the image.
3047%
3048*/
3049static const IndexPacket *GetVirtualIndexesFromCache(const Image *image)
3050{
3051 CacheInfo
3052 *cache_info;
3053
3054 const IndexPacket
3055 *indexes;
3056
cristy6ebe97c2010-07-03 01:17:28 +00003057 int
cristy3ed852e2009-09-05 21:47:34 +00003058 id;
3059
3060 if (image->debug != MagickFalse)
3061 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3062 cache_info=(CacheInfo *) image->cache;
3063 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00003064 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00003065 indexes=GetVirtualIndexesFromNexus(image->cache,cache_info->nexus_info[id]);
3066 return(indexes);
3067}
3068
3069/*
3070%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3071% %
3072% %
3073% %
3074+ 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 %
3075% %
3076% %
3077% %
3078%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3079%
3080% GetVirtualIndexesFromNexus() returns the indexes associated with the
3081% specified cache nexus.
3082%
3083% The format of the GetVirtualIndexesFromNexus() method is:
3084%
3085% const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
3086% NexusInfo *nexus_info)
3087%
3088% A description of each parameter follows:
3089%
3090% o cache: the pixel cache.
3091%
3092% o nexus_info: the cache nexus to return the colormap indexes.
3093%
3094*/
3095MagickExport const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
3096 NexusInfo *nexus_info)
3097{
3098 CacheInfo
3099 *cache_info;
3100
3101 if (cache == (Cache) NULL)
3102 return((IndexPacket *) NULL);
3103 cache_info=(CacheInfo *) cache;
3104 assert(cache_info->signature == MagickSignature);
3105 if (cache_info->storage_class == UndefinedClass)
3106 return((IndexPacket *) NULL);
3107 return(nexus_info->indexes);
3108}
3109
3110/*
3111%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3112% %
3113% %
3114% %
3115% G e t V i r t u a l I n d e x Q u e u e %
3116% %
3117% %
3118% %
3119%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3120%
3121% GetVirtualIndexQueue() returns the virtual black channel or the
3122% colormap indexes associated with the last call to QueueAuthenticPixels() or
3123% GetVirtualPixels(). NULL is returned if the black channel or colormap
3124% indexes are not available.
3125%
3126% The format of the GetVirtualIndexQueue() method is:
3127%
3128% const IndexPacket *GetVirtualIndexQueue(const Image *image)
3129%
3130% A description of each parameter follows:
3131%
3132% o image: the image.
3133%
3134*/
3135MagickExport const IndexPacket *GetVirtualIndexQueue(const Image *image)
3136{
3137 CacheInfo
3138 *cache_info;
3139
3140 assert(image != (const Image *) NULL);
3141 assert(image->signature == MagickSignature);
3142 if (image->debug != MagickFalse)
3143 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3144 assert(image->cache != (Cache) NULL);
3145 cache_info=(CacheInfo *) image->cache;
3146 assert(cache_info->signature == MagickSignature);
3147 if (cache_info->methods.get_virtual_indexes_from_handler ==
3148 (GetVirtualIndexesFromHandler) NULL)
3149 return((IndexPacket *) NULL);
3150 return(cache_info->methods.get_virtual_indexes_from_handler(image));
3151}
3152
3153/*
3154%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3155% %
3156% %
3157% %
3158+ 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 %
3159% %
3160% %
3161% %
3162%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3163%
3164% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3165% pixel cache as defined by the geometry parameters. A pointer to the pixels
3166% is returned if the pixels are transferred, otherwise a NULL is returned.
3167%
3168% The format of the GetVirtualPixelsFromNexus() method is:
3169%
3170% PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003171% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00003172% const size_t columns,const size_t rows,NexusInfo *nexus_info,
3173% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003174%
3175% A description of each parameter follows:
3176%
3177% o image: the image.
3178%
3179% o virtual_pixel_method: the virtual pixel method.
3180%
3181% o x,y,columns,rows: These values define the perimeter of a region of
3182% pixels.
3183%
3184% o nexus_info: the cache nexus to acquire.
3185%
3186% o exception: return any errors or warnings in this structure.
3187%
3188*/
3189
cristybb503372010-05-27 20:51:26 +00003190static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003191 DitherMatrix[64] =
3192 {
3193 0, 48, 12, 60, 3, 51, 15, 63,
3194 32, 16, 44, 28, 35, 19, 47, 31,
3195 8, 56, 4, 52, 11, 59, 7, 55,
3196 40, 24, 36, 20, 43, 27, 39, 23,
3197 2, 50, 14, 62, 1, 49, 13, 61,
3198 34, 18, 46, 30, 33, 17, 45, 29,
3199 10, 58, 6, 54, 9, 57, 5, 53,
3200 42, 26, 38, 22, 41, 25, 37, 21
3201 };
3202
cristybb503372010-05-27 20:51:26 +00003203static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003204{
cristybb503372010-05-27 20:51:26 +00003205 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003206 index;
3207
3208 index=x+DitherMatrix[x & 0x07]-32L;
3209 if (index < 0L)
3210 return(0L);
cristybb503372010-05-27 20:51:26 +00003211 if (index >= (ssize_t) columns)
3212 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00003213 return(index);
3214}
3215
cristybb503372010-05-27 20:51:26 +00003216static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003217{
cristybb503372010-05-27 20:51:26 +00003218 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003219 index;
3220
3221 index=y+DitherMatrix[y & 0x07]-32L;
3222 if (index < 0L)
3223 return(0L);
cristybb503372010-05-27 20:51:26 +00003224 if (index >= (ssize_t) rows)
3225 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00003226 return(index);
3227}
3228
cristybb503372010-05-27 20:51:26 +00003229static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003230{
3231 if (x < 0L)
3232 return(0L);
cristybb503372010-05-27 20:51:26 +00003233 if (x >= (ssize_t) columns)
3234 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003235 return(x);
3236}
3237
cristybb503372010-05-27 20:51:26 +00003238static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003239{
3240 if (y < 0L)
3241 return(0L);
cristybb503372010-05-27 20:51:26 +00003242 if (y >= (ssize_t) rows)
3243 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003244 return(y);
3245}
3246
cristybb503372010-05-27 20:51:26 +00003247static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003248{
cristybb503372010-05-27 20:51:26 +00003249 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003250}
3251
cristybb503372010-05-27 20:51:26 +00003252static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003253{
cristybb503372010-05-27 20:51:26 +00003254 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003255}
3256
3257/*
3258 VirtualPixelModulo() computes the remainder of dividing offset by extent. It
3259 returns not only the quotient (tile the offset falls in) but also the positive
3260 remainer within that tile such that 0 <= remainder < extent. This method is
3261 essentially a ldiv() using a floored modulo division rather than the normal
3262 default truncated modulo division.
3263*/
cristybb503372010-05-27 20:51:26 +00003264static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3265 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003266{
3267 MagickModulo
3268 modulo;
3269
cristybb503372010-05-27 20:51:26 +00003270 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003271 if (offset < 0L)
3272 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003273 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003274 return(modulo);
3275}
3276
3277MagickExport const PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003278 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3279 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003280 ExceptionInfo *exception)
3281{
3282 CacheInfo
3283 *cache_info;
3284
cristyc3ec0d42010-04-07 01:18:08 +00003285 IndexPacket
3286 virtual_index;
3287
cristy3ed852e2009-09-05 21:47:34 +00003288 MagickOffsetType
3289 offset;
3290
3291 MagickSizeType
3292 length,
3293 number_pixels;
3294
3295 NexusInfo
3296 **virtual_nexus;
3297
3298 PixelPacket
3299 *pixels,
3300 virtual_pixel;
3301
3302 RectangleInfo
3303 region;
3304
3305 register const IndexPacket
cristyc3ec0d42010-04-07 01:18:08 +00003306 *restrict virtual_indexes;
cristy3ed852e2009-09-05 21:47:34 +00003307
3308 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003309 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003310
3311 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003312 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003313
cristybb503372010-05-27 20:51:26 +00003314 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003315 u,
3316 v;
3317
3318 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003319 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003320
3321 /*
3322 Acquire pixels.
3323 */
3324 if (image->debug != MagickFalse)
3325 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3326 cache_info=(CacheInfo *) image->cache;
cristy4cfbb3f2010-03-14 20:40:23 +00003327 if (cache_info->type == UndefinedCache)
cristy3ed852e2009-09-05 21:47:34 +00003328 return((const PixelPacket *) NULL);
3329 region.x=x;
3330 region.y=y;
3331 region.width=columns;
3332 region.height=rows;
3333 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
3334 if (pixels == (PixelPacket *) NULL)
3335 return((const PixelPacket *) NULL);
cristydf415c82010-03-11 16:47:50 +00003336 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3337 nexus_info->region.x;
3338 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3339 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003340 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3341 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003342 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3343 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003344 {
3345 MagickBooleanType
3346 status;
3347
3348 /*
3349 Pixel request is inside cache extents.
3350 */
3351 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
3352 return(pixels);
3353 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3354 if (status == MagickFalse)
3355 return((const PixelPacket *) NULL);
3356 if ((cache_info->storage_class == PseudoClass) ||
3357 (cache_info->colorspace == CMYKColorspace))
3358 {
3359 status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
3360 if (status == MagickFalse)
3361 return((const PixelPacket *) NULL);
3362 }
3363 return(pixels);
3364 }
3365 /*
3366 Pixel request is outside cache extents.
3367 */
3368 q=pixels;
3369 indexes=GetPixelCacheNexusIndexes(cache_info,nexus_info);
3370 virtual_nexus=AcquirePixelCacheNexus(1);
3371 if (virtual_nexus == (NexusInfo **) NULL)
3372 {
3373 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3374 "UnableToGetCacheNexus","`%s'",image->filename);
3375 return((const PixelPacket *) NULL);
3376 }
3377 switch (virtual_pixel_method)
3378 {
3379 case BlackVirtualPixelMethod:
3380 {
cristy4789f0d2010-01-10 00:01:06 +00003381 SetRedPixelComponent(&virtual_pixel,0);
3382 SetGreenPixelComponent(&virtual_pixel,0);
3383 SetBluePixelComponent(&virtual_pixel,0);
3384 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003385 break;
3386 }
3387 case GrayVirtualPixelMethod:
3388 {
cristy4789f0d2010-01-10 00:01:06 +00003389 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3390 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3391 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3392 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003393 break;
3394 }
3395 case TransparentVirtualPixelMethod:
3396 {
cristy4789f0d2010-01-10 00:01:06 +00003397 SetRedPixelComponent(&virtual_pixel,0);
3398 SetGreenPixelComponent(&virtual_pixel,0);
3399 SetBluePixelComponent(&virtual_pixel,0);
3400 SetOpacityPixelComponent(&virtual_pixel,TransparentOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003401 break;
3402 }
3403 case MaskVirtualPixelMethod:
3404 case WhiteVirtualPixelMethod:
3405 {
cristy4789f0d2010-01-10 00:01:06 +00003406 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3407 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3408 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3409 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003410 break;
3411 }
3412 default:
3413 {
3414 virtual_pixel=image->background_color;
3415 break;
3416 }
3417 }
cristyc3ec0d42010-04-07 01:18:08 +00003418 virtual_index=0;
cristybb503372010-05-27 20:51:26 +00003419 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003420 {
cristybb503372010-05-27 20:51:26 +00003421 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003422 {
3423 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003424 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003425 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3426 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003427 {
3428 MagickModulo
3429 x_modulo,
3430 y_modulo;
3431
3432 /*
3433 Transfer a single pixel.
3434 */
3435 length=(MagickSizeType) 1;
3436 switch (virtual_pixel_method)
3437 {
3438 case BackgroundVirtualPixelMethod:
3439 case ConstantVirtualPixelMethod:
3440 case BlackVirtualPixelMethod:
3441 case GrayVirtualPixelMethod:
3442 case TransparentVirtualPixelMethod:
3443 case MaskVirtualPixelMethod:
3444 case WhiteVirtualPixelMethod:
3445 {
3446 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003447 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003448 break;
3449 }
3450 case EdgeVirtualPixelMethod:
3451 default:
3452 {
3453 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003454 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003455 1UL,1UL,virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003456 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3457 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003458 break;
3459 }
3460 case RandomVirtualPixelMethod:
3461 {
3462 if (cache_info->random_info == (RandomInfo *) NULL)
3463 cache_info->random_info=AcquireRandomInfo();
3464 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003465 RandomX(cache_info->random_info,cache_info->columns),
3466 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003467 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003468 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3469 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003470 break;
3471 }
3472 case DitherVirtualPixelMethod:
3473 {
3474 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003475 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003476 1UL,1UL,virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003477 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3478 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003479 break;
3480 }
3481 case TileVirtualPixelMethod:
3482 {
3483 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3484 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3485 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3486 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3487 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003488 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3489 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003490 break;
3491 }
3492 case MirrorVirtualPixelMethod:
3493 {
3494 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3495 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003496 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003497 x_modulo.remainder-1L;
3498 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3499 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003500 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003501 y_modulo.remainder-1L;
3502 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3503 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3504 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003505 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3506 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003507 break;
3508 }
3509 case CheckerTileVirtualPixelMethod:
3510 {
3511 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3512 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3513 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3514 {
3515 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003516 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003517 break;
3518 }
3519 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3520 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3521 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003522 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3523 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003524 break;
3525 }
3526 case HorizontalTileVirtualPixelMethod:
3527 {
cristybb503372010-05-27 20:51:26 +00003528 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003529 {
3530 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003531 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003532 break;
3533 }
3534 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3535 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3536 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3537 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3538 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003539 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3540 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003541 break;
3542 }
3543 case VerticalTileVirtualPixelMethod:
3544 {
cristybb503372010-05-27 20:51:26 +00003545 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
cristy3ed852e2009-09-05 21:47:34 +00003546 {
3547 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003548 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003549 break;
3550 }
3551 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3552 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3553 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3554 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3555 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003556 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3557 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003558 break;
3559 }
3560 case HorizontalTileEdgeVirtualPixelMethod:
3561 {
3562 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3563 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003564 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003565 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003566 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3567 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003568 break;
3569 }
3570 case VerticalTileEdgeVirtualPixelMethod:
3571 {
3572 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3573 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003574 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003575 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003576 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3577 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003578 break;
3579 }
3580 }
3581 if (p == (const PixelPacket *) NULL)
3582 break;
3583 *q++=(*p);
cristyc3ec0d42010-04-07 01:18:08 +00003584 if ((indexes != (IndexPacket *) NULL) &&
3585 (virtual_indexes != (const IndexPacket *) NULL))
3586 *indexes++=(*virtual_indexes);
cristy3ed852e2009-09-05 21:47:34 +00003587 continue;
3588 }
3589 /*
3590 Transfer a run of pixels.
3591 */
3592 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,
cristybb503372010-05-27 20:51:26 +00003593 (size_t) length,1UL,virtual_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003594 if (p == (const PixelPacket *) NULL)
3595 break;
cristyc3ec0d42010-04-07 01:18:08 +00003596 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003597 (void) CopyMagickMemory(q,p,(size_t) length*sizeof(*p));
3598 q+=length;
cristyc3ec0d42010-04-07 01:18:08 +00003599 if ((indexes != (IndexPacket *) NULL) &&
3600 (virtual_indexes != (const IndexPacket *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003601 {
cristyc3ec0d42010-04-07 01:18:08 +00003602 (void) CopyMagickMemory(indexes,virtual_indexes,(size_t) length*
3603 sizeof(*virtual_indexes));
3604 indexes+=length;
cristy3ed852e2009-09-05 21:47:34 +00003605 }
3606 }
3607 }
3608 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3609 return(pixels);
3610}
3611
3612/*
3613%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3614% %
3615% %
3616% %
3617+ G e t V i r t u a l P i x e l C a c h e %
3618% %
3619% %
3620% %
3621%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3622%
3623% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3624% cache as defined by the geometry parameters. A pointer to the pixels
3625% is returned if the pixels are transferred, otherwise a NULL is returned.
3626%
3627% The format of the GetVirtualPixelCache() method is:
3628%
3629% const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003630% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3631% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003632% ExceptionInfo *exception)
3633%
3634% A description of each parameter follows:
3635%
3636% o image: the image.
3637%
3638% o virtual_pixel_method: the virtual pixel method.
3639%
3640% o x,y,columns,rows: These values define the perimeter of a region of
3641% pixels.
3642%
3643% o exception: return any errors or warnings in this structure.
3644%
3645*/
3646static const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003647 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3648 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003649{
3650 CacheInfo
3651 *cache_info;
3652
3653 const PixelPacket
3654 *pixels;
3655
cristy6ebe97c2010-07-03 01:17:28 +00003656 int
cristy3ed852e2009-09-05 21:47:34 +00003657 id;
3658
3659 if (image->debug != MagickFalse)
3660 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3661 cache_info=(CacheInfo *) image->cache;
3662 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00003663 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00003664 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3665 cache_info->nexus_info[id],exception);
3666 return(pixels);
3667}
3668
3669/*
3670%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3671% %
3672% %
3673% %
3674% G e t V i r t u a l P i x e l Q u e u e %
3675% %
3676% %
3677% %
3678%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3679%
3680% GetVirtualPixelQueue() returns the virtual pixels associated with the
3681% last call to QueueAuthenticPixels() or GetVirtualPixels().
3682%
3683% The format of the GetVirtualPixelQueue() method is:
3684%
3685% const PixelPacket *GetVirtualPixelQueue(const Image image)
3686%
3687% A description of each parameter follows:
3688%
3689% o image: the image.
3690%
3691*/
3692MagickExport const PixelPacket *GetVirtualPixelQueue(const Image *image)
3693{
3694 CacheInfo
3695 *cache_info;
3696
3697 assert(image != (const Image *) NULL);
3698 assert(image->signature == MagickSignature);
3699 if (image->debug != MagickFalse)
3700 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3701 assert(image->cache != (Cache) NULL);
3702 cache_info=(CacheInfo *) image->cache;
3703 assert(cache_info->signature == MagickSignature);
3704 if (cache_info->methods.get_virtual_pixels_handler ==
3705 (GetVirtualPixelsHandler) NULL)
3706 return((PixelPacket *) NULL);
3707 return(cache_info->methods.get_virtual_pixels_handler(image));
3708}
3709
3710/*
3711%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3712% %
3713% %
3714% %
3715% G e t V i r t u a l P i x e l s %
3716% %
3717% %
3718% %
3719%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3720%
3721% GetVirtualPixels() returns an immutable pixel region. If the
3722% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003723% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003724% copy of the pixels or it may point to the original pixels in memory.
3725% Performance is maximized if the selected region is part of one row, or one
3726% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003727% (without a copy) if the image is in memory, or in a memory-mapped file. The
3728% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003729%
3730% Pixels accessed via the returned pointer represent a simple array of type
3731% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
3732% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access
3733% the black color component or to obtain the colormap indexes (of type
3734% IndexPacket) corresponding to the region.
3735%
3736% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3737%
3738% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3739% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3740% GetCacheViewAuthenticPixels() instead.
3741%
3742% The format of the GetVirtualPixels() method is:
3743%
cristybb503372010-05-27 20:51:26 +00003744% const PixelPacket *GetVirtualPixels(const Image *image,const ssize_t x,
3745% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003746% ExceptionInfo *exception)
3747%
3748% A description of each parameter follows:
3749%
3750% o image: the image.
3751%
3752% o x,y,columns,rows: These values define the perimeter of a region of
3753% pixels.
3754%
3755% o exception: return any errors or warnings in this structure.
3756%
3757*/
3758MagickExport const PixelPacket *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003759 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3760 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003761{
3762 CacheInfo
3763 *cache_info;
3764
3765 const PixelPacket
3766 *pixels;
3767
3768 assert(image != (const Image *) NULL);
3769 assert(image->signature == MagickSignature);
3770 if (image->debug != MagickFalse)
3771 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3772 assert(image->cache != (Cache) NULL);
3773 cache_info=(CacheInfo *) image->cache;
3774 assert(cache_info->signature == MagickSignature);
3775 if (cache_info->methods.get_virtual_pixel_handler ==
3776 (GetVirtualPixelHandler) NULL)
3777 return((const PixelPacket *) NULL);
3778 pixels=cache_info->methods.get_virtual_pixel_handler(image,
3779 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception);
3780 return(pixels);
3781}
3782
3783/*
3784%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3785% %
3786% %
3787% %
3788+ 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 %
3789% %
3790% %
3791% %
3792%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3793%
3794% GetVirtualPixelsCache() returns the pixels associated with the last call
3795% to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3796%
3797% The format of the GetVirtualPixelsCache() method is:
3798%
3799% PixelPacket *GetVirtualPixelsCache(const Image *image)
3800%
3801% A description of each parameter follows:
3802%
3803% o image: the image.
3804%
3805*/
3806static const PixelPacket *GetVirtualPixelsCache(const Image *image)
3807{
3808 CacheInfo
3809 *cache_info;
3810
3811 const PixelPacket
3812 *pixels;
3813
cristy6ebe97c2010-07-03 01:17:28 +00003814 int
cristy3ed852e2009-09-05 21:47:34 +00003815 id;
3816
3817 if (image->debug != MagickFalse)
3818 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3819 cache_info=(CacheInfo *) image->cache;
3820 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00003821 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00003822 pixels=GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]);
3823 return(pixels);
3824}
3825
3826/*
3827%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3828% %
3829% %
3830% %
3831+ G e t V i r t u a l P i x e l s N e x u s %
3832% %
3833% %
3834% %
3835%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3836%
3837% GetVirtualPixelsNexus() returns the pixels associated with the specified
3838% cache nexus.
3839%
3840% The format of the GetVirtualPixelsNexus() method is:
3841%
3842% const IndexPacket *GetVirtualPixelsNexus(const Cache cache,
3843% NexusInfo *nexus_info)
3844%
3845% A description of each parameter follows:
3846%
3847% o cache: the pixel cache.
3848%
3849% o nexus_info: the cache nexus to return the colormap pixels.
3850%
3851*/
3852MagickExport const PixelPacket *GetVirtualPixelsNexus(const Cache cache,
3853 NexusInfo *nexus_info)
3854{
3855 CacheInfo
3856 *cache_info;
3857
3858 if (cache == (Cache) NULL)
3859 return((PixelPacket *) NULL);
3860 cache_info=(CacheInfo *) cache;
3861 assert(cache_info->signature == MagickSignature);
3862 if (cache_info->storage_class == UndefinedClass)
3863 return((PixelPacket *) NULL);
3864 return((const PixelPacket *) nexus_info->pixels);
3865}
3866
3867/*
3868%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3869% %
3870% %
3871% %
3872+ M a s k P i x e l C a c h e N e x u s %
3873% %
3874% %
3875% %
3876%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3877%
3878% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3879% The method returns MagickTrue if the pixel region is masked, otherwise
3880% MagickFalse.
3881%
3882% The format of the MaskPixelCacheNexus() method is:
3883%
3884% MagickBooleanType MaskPixelCacheNexus(Image *image,
3885% NexusInfo *nexus_info,ExceptionInfo *exception)
3886%
3887% A description of each parameter follows:
3888%
3889% o image: the image.
3890%
3891% o nexus_info: the cache nexus to clip.
3892%
3893% o exception: return any errors or warnings in this structure.
3894%
3895*/
3896
3897static inline void MagickPixelCompositeMask(const MagickPixelPacket *p,
3898 const MagickRealType alpha,const MagickPixelPacket *q,
3899 const MagickRealType beta,MagickPixelPacket *composite)
3900{
3901 MagickRealType
3902 gamma;
3903
3904 if (alpha == TransparentOpacity)
3905 {
3906 *composite=(*q);
3907 return;
3908 }
3909 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3910 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3911 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3912 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3913 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3914 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3915 composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
3916}
3917
3918static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3919 ExceptionInfo *exception)
3920{
3921 CacheInfo
3922 *cache_info;
3923
3924 MagickPixelPacket
3925 alpha,
3926 beta;
3927
3928 MagickSizeType
3929 number_pixels;
3930
3931 NexusInfo
3932 **clip_nexus,
3933 **image_nexus;
3934
3935 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003936 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003937
3938 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003939 *restrict nexus_indexes,
3940 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003941
cristybb503372010-05-27 20:51:26 +00003942 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003943 i;
3944
3945 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003946 *restrict p,
3947 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003948
3949 /*
3950 Apply clip mask.
3951 */
3952 if (image->debug != MagickFalse)
3953 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3954 if (image->mask == (Image *) NULL)
3955 return(MagickFalse);
3956 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
3957 if (cache_info == (Cache) NULL)
3958 return(MagickFalse);
3959 image_nexus=AcquirePixelCacheNexus(1);
3960 clip_nexus=AcquirePixelCacheNexus(1);
3961 if ((image_nexus == (NexusInfo **) NULL) ||
3962 (clip_nexus == (NexusInfo **) NULL))
3963 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy09449f72010-01-23 03:08:36 +00003964 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,
3965 nexus_info->region.y,nexus_info->region.width,nexus_info->region.height,
3966 image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003967 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
3968 q=nexus_info->pixels;
3969 nexus_indexes=nexus_info->indexes;
3970 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3971 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3972 nexus_info->region.height,clip_nexus[0],&image->exception);
3973 GetMagickPixelPacket(image,&alpha);
3974 GetMagickPixelPacket(image,&beta);
3975 number_pixels=(MagickSizeType) nexus_info->region.width*
3976 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +00003977 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +00003978 {
3979 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
3980 break;
3981 SetMagickPixelPacket(image,p,indexes+i,&alpha);
3982 SetMagickPixelPacket(image,q,nexus_indexes+i,&beta);
3983 MagickPixelCompositeMask(&beta,(MagickRealType) PixelIntensityToQuantum(r),
3984 &alpha,alpha.opacity,&beta);
cristyce70c172010-01-07 17:15:30 +00003985 q->red=ClampToQuantum(beta.red);
3986 q->green=ClampToQuantum(beta.green);
3987 q->blue=ClampToQuantum(beta.blue);
3988 q->opacity=ClampToQuantum(beta.opacity);
cristy3ed852e2009-09-05 21:47:34 +00003989 if (cache_info->active_index_channel != MagickFalse)
3990 nexus_indexes[i]=indexes[i];
3991 p++;
3992 q++;
3993 r++;
3994 }
3995 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3996 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +00003997 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003998 return(MagickFalse);
3999 return(MagickTrue);
4000}
4001
4002/*
4003%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4004% %
4005% %
4006% %
4007+ O p e n P i x e l C a c h e %
4008% %
4009% %
4010% %
4011%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4012%
4013% OpenPixelCache() allocates the pixel cache. This includes defining the cache
4014% dimensions, allocating space for the image pixels and optionally the
4015% colormap indexes, and memory mapping the cache if it is disk based. The
4016% cache nexus array is initialized as well.
4017%
4018% The format of the OpenPixelCache() method is:
4019%
4020% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
4021% ExceptionInfo *exception)
4022%
4023% A description of each parameter follows:
4024%
4025% o image: the image.
4026%
4027% o mode: ReadMode, WriteMode, or IOMode.
4028%
4029% o exception: return any errors or warnings in this structure.
4030%
4031*/
4032
cristyd43a46b2010-01-21 02:13:41 +00004033static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00004034{
4035 cache_info->mapped=MagickFalse;
4036 cache_info->pixels=(PixelPacket *) AcquireMagickMemory((size_t)
4037 cache_info->length);
4038 if (cache_info->pixels == (PixelPacket *) NULL)
4039 {
4040 cache_info->mapped=MagickTrue;
4041 cache_info->pixels=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
4042 cache_info->length);
4043 }
4044}
4045
4046static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
4047{
4048 CacheInfo
4049 *cache_info;
4050
4051 MagickOffsetType
4052 count,
4053 extent,
4054 offset;
4055
4056 cache_info=(CacheInfo *) image->cache;
4057 if (image->debug != MagickFalse)
4058 {
4059 char
4060 format[MaxTextExtent],
4061 message[MaxTextExtent];
4062
cristyb9080c92009-12-01 20:13:26 +00004063 (void) FormatMagickSize(length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00004064 (void) FormatMagickString(message,MaxTextExtent,
cristy2ce15c92010-03-12 14:03:41 +00004065 "extend %s (%s[%d], disk, %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00004066 cache_info->cache_filename,cache_info->file,format);
4067 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4068 }
4069 if (length != (MagickSizeType) ((MagickOffsetType) length))
4070 return(MagickFalse);
4071 extent=(MagickOffsetType) MagickSeek(cache_info->file,0,SEEK_END);
4072 if (extent < 0)
4073 return(MagickFalse);
4074 if ((MagickSizeType) extent >= length)
4075 return(MagickTrue);
4076 offset=(MagickOffsetType) length-1;
4077 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
4078 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
4079}
4080
4081static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
4082 ExceptionInfo *exception)
4083{
4084 char
4085 format[MaxTextExtent],
4086 message[MaxTextExtent];
4087
4088 CacheInfo
4089 *cache_info,
4090 source_info;
4091
4092 MagickSizeType
4093 length,
4094 number_pixels;
4095
4096 MagickStatusType
4097 status;
4098
4099 size_t
4100 packet_size;
4101
cristybb503372010-05-27 20:51:26 +00004102 size_t
cristy3ed852e2009-09-05 21:47:34 +00004103 columns;
4104
4105 if (image->debug != MagickFalse)
4106 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4107 if ((image->columns == 0) || (image->rows == 0))
4108 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
4109 cache_info=(CacheInfo *) image->cache;
4110 source_info=(*cache_info);
4111 source_info.file=(-1);
cristye8c25f92010-06-03 00:53:06 +00004112 (void) FormatMagickString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
4113 image->filename,(double) GetImageIndexInList(image));
cristy87528ea2009-09-10 14:53:56 +00004114 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +00004115 cache_info->rows=image->rows;
4116 cache_info->columns=image->columns;
4117 cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
4118 (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
cristy73724512010-04-12 14:43:14 +00004119 if (image->ping != MagickFalse)
4120 {
4121 cache_info->storage_class=image->storage_class;
4122 cache_info->colorspace=image->colorspace;
4123 cache_info->type=PingCache;
4124 cache_info->pixels=(PixelPacket *) NULL;
4125 cache_info->indexes=(IndexPacket *) NULL;
4126 cache_info->length=0;
4127 return(MagickTrue);
4128 }
cristy3ed852e2009-09-05 21:47:34 +00004129 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4130 packet_size=sizeof(PixelPacket);
4131 if (cache_info->active_index_channel != MagickFalse)
4132 packet_size+=sizeof(IndexPacket);
4133 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00004134 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00004135 if (cache_info->columns != columns)
4136 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4137 image->filename);
4138 cache_info->length=length;
4139 status=AcquireMagickResource(AreaResource,cache_info->length);
4140 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4141 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4142 {
4143 status=AcquireMagickResource(MemoryResource,cache_info->length);
4144 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4145 (cache_info->type == MemoryCache))
4146 {
cristyd43a46b2010-01-21 02:13:41 +00004147 AllocatePixelCachePixels(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004148 if (cache_info->pixels == (PixelPacket *) NULL)
4149 cache_info->pixels=source_info.pixels;
4150 else
4151 {
4152 /*
4153 Create memory pixel cache.
4154 */
4155 if (image->debug != MagickFalse)
4156 {
cristy97e7a572009-12-05 15:07:53 +00004157 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004158 format);
cristy3ed852e2009-09-05 21:47:34 +00004159 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004160 "open %s (%s memory, %.20gx%.20g %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00004161 cache_info->mapped != MagickFalse ? "anonymous" : "heap",
cristye8c25f92010-06-03 00:53:06 +00004162 (double) cache_info->columns,(double) cache_info->rows,
4163 format);
cristy3ed852e2009-09-05 21:47:34 +00004164 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4165 message);
4166 }
4167 cache_info->storage_class=image->storage_class;
4168 cache_info->colorspace=image->colorspace;
4169 cache_info->type=MemoryCache;
4170 cache_info->indexes=(IndexPacket *) NULL;
4171 if (cache_info->active_index_channel != MagickFalse)
4172 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4173 number_pixels);
4174 if (source_info.storage_class != UndefinedClass)
4175 {
4176 status|=ClonePixelCachePixels(cache_info,&source_info,
4177 exception);
4178 RelinquishPixelCachePixels(&source_info);
4179 }
4180 return(MagickTrue);
4181 }
4182 }
4183 RelinquishMagickResource(MemoryResource,cache_info->length);
4184 }
4185 /*
4186 Create pixel cache on disk.
4187 */
4188 status=AcquireMagickResource(DiskResource,cache_info->length);
4189 if (status == MagickFalse)
4190 {
4191 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4192 "CacheResourcesExhausted","`%s'",image->filename);
4193 return(MagickFalse);
4194 }
4195 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4196 {
4197 RelinquishMagickResource(DiskResource,cache_info->length);
4198 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4199 image->filename);
4200 return(MagickFalse);
4201 }
4202 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4203 cache_info->length);
4204 if (status == MagickFalse)
4205 {
4206 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4207 image->filename);
4208 return(MagickFalse);
4209 }
4210 cache_info->storage_class=image->storage_class;
4211 cache_info->colorspace=image->colorspace;
4212 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4213 status=AcquireMagickResource(AreaResource,cache_info->length);
4214 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4215 cache_info->type=DiskCache;
4216 else
4217 {
4218 status=AcquireMagickResource(MapResource,cache_info->length);
4219 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4220 (cache_info->type != MemoryCache))
4221 cache_info->type=DiskCache;
4222 else
4223 {
4224 cache_info->pixels=(PixelPacket *) MapBlob(cache_info->file,mode,
4225 cache_info->offset,(size_t) cache_info->length);
4226 if (cache_info->pixels == (PixelPacket *) NULL)
4227 {
4228 cache_info->pixels=source_info.pixels;
4229 cache_info->type=DiskCache;
4230 }
4231 else
4232 {
4233 /*
4234 Create file-backed memory-mapped pixel cache.
4235 */
4236 (void) ClosePixelCacheOnDisk(cache_info);
4237 cache_info->type=MapCache;
4238 cache_info->mapped=MagickTrue;
4239 cache_info->indexes=(IndexPacket *) NULL;
4240 if (cache_info->active_index_channel != MagickFalse)
4241 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4242 number_pixels);
4243 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4244 {
4245 status=ClonePixelCachePixels(cache_info,&source_info,
4246 exception);
4247 RelinquishPixelCachePixels(&source_info);
4248 }
4249 if (image->debug != MagickFalse)
4250 {
cristy97e7a572009-12-05 15:07:53 +00004251 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004252 format);
cristy3ed852e2009-09-05 21:47:34 +00004253 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004254 "open %s (%s[%d], memory-mapped, %.20gx%.20g %sB)",
cristy3ed852e2009-09-05 21:47:34 +00004255 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004256 cache_info->file,(double) cache_info->columns,(double)
4257 cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004258 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4259 message);
4260 }
4261 return(MagickTrue);
4262 }
4263 }
4264 RelinquishMagickResource(MapResource,cache_info->length);
4265 }
4266 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4267 {
4268 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4269 RelinquishPixelCachePixels(&source_info);
4270 }
4271 if (image->debug != MagickFalse)
4272 {
cristyb9080c92009-12-01 20:13:26 +00004273 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00004274 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004275 "open %s (%s[%d], disk, %.20gx%.20g %sB)",cache_info->filename,
4276 cache_info->cache_filename,cache_info->file,(double)
4277 cache_info->columns,(double) cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004278 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4279 }
4280 return(MagickTrue);
4281}
4282
4283/*
4284%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4285% %
4286% %
4287% %
4288+ P e r s i s t P i x e l C a c h e %
4289% %
4290% %
4291% %
4292%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4293%
4294% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4295% persistent pixel cache is one that resides on disk and is not destroyed
4296% when the program exits.
4297%
4298% The format of the PersistPixelCache() method is:
4299%
4300% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4301% const MagickBooleanType attach,MagickOffsetType *offset,
4302% ExceptionInfo *exception)
4303%
4304% A description of each parameter follows:
4305%
4306% o image: the image.
4307%
4308% o filename: the persistent pixel cache filename.
4309%
cristy01b7eb02009-09-10 23:10:14 +00004310% o attach: A value other than zero initializes the persistent pixel
4311% cache.
4312%
cristy3ed852e2009-09-05 21:47:34 +00004313% o initialize: A value other than zero initializes the persistent pixel
4314% cache.
4315%
4316% o offset: the offset in the persistent cache to store pixels.
4317%
4318% o exception: return any errors or warnings in this structure.
4319%
4320*/
4321MagickExport MagickBooleanType PersistPixelCache(Image *image,
4322 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4323 ExceptionInfo *exception)
4324{
4325 CacheInfo
4326 *cache_info,
4327 *clone_info;
4328
4329 Image
4330 clone_image;
4331
cristybb503372010-05-27 20:51:26 +00004332 ssize_t
cristy688f07b2009-09-27 15:19:13 +00004333 page_size;
cristy3ed852e2009-09-05 21:47:34 +00004334
4335 MagickBooleanType
4336 status;
4337
4338 assert(image != (Image *) NULL);
4339 assert(image->signature == MagickSignature);
4340 if (image->debug != MagickFalse)
4341 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4342 assert(image->cache != (void *) NULL);
4343 assert(filename != (const char *) NULL);
4344 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004345 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004346 cache_info=(CacheInfo *) image->cache;
4347 assert(cache_info->signature == MagickSignature);
4348 if (attach != MagickFalse)
4349 {
4350 /*
cristy01b7eb02009-09-10 23:10:14 +00004351 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004352 */
4353 if (image->debug != MagickFalse)
4354 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4355 "attach persistent cache");
4356 (void) CopyMagickString(cache_info->cache_filename,filename,
4357 MaxTextExtent);
4358 cache_info->type=DiskCache;
4359 cache_info->offset=(*offset);
4360 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4361 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004362 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004363 return(MagickTrue);
4364 }
cristy01b7eb02009-09-10 23:10:14 +00004365 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4366 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004367 {
cristyf84a1932010-01-03 18:00:18 +00004368 LockSemaphoreInfo(cache_info->semaphore);
cristy09449f72010-01-23 03:08:36 +00004369 if ((cache_info->mode != ReadMode) &&
4370 (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004371 (cache_info->reference_count == 1))
4372 {
4373 int
4374 status;
4375
4376 /*
cristy01b7eb02009-09-10 23:10:14 +00004377 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004378 */
4379 status=rename(cache_info->cache_filename,filename);
4380 if (status == 0)
4381 {
4382 (void) CopyMagickString(cache_info->cache_filename,filename,
4383 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004384 *offset+=cache_info->length+page_size-(cache_info->length %
4385 page_size);
cristyf84a1932010-01-03 18:00:18 +00004386 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004387 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004388 if (image->debug != MagickFalse)
4389 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4390 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004391 return(MagickTrue);
4392 }
4393 }
cristyf84a1932010-01-03 18:00:18 +00004394 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004395 }
4396 /*
cristy01b7eb02009-09-10 23:10:14 +00004397 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004398 */
4399 clone_image=(*image);
4400 clone_info=(CacheInfo *) clone_image.cache;
4401 image->cache=ClonePixelCache(cache_info);
4402 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4403 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4404 cache_info->type=DiskCache;
4405 cache_info->offset=(*offset);
4406 cache_info=(CacheInfo *) image->cache;
4407 status=ClonePixelCacheNexus(cache_info,clone_info,exception);
4408 if (status != MagickFalse)
4409 {
4410 status=OpenPixelCache(image,IOMode,exception);
4411 if (status != MagickFalse)
4412 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
4413 }
cristy688f07b2009-09-27 15:19:13 +00004414 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004415 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4416 return(status);
4417}
4418
4419/*
4420%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4421% %
4422% %
4423% %
4424+ Q u e u e A u t h e n t i c N e x u s %
4425% %
4426% %
4427% %
4428%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4429%
4430% QueueAuthenticNexus() allocates an region to store image pixels as defined
4431% by the region rectangle and returns a pointer to the region. This region is
4432% subsequently transferred from the pixel cache with
4433% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4434% pixels are transferred, otherwise a NULL is returned.
4435%
4436% The format of the QueueAuthenticNexus() method is:
4437%
cristy5f959472010-05-27 22:19:46 +00004438% PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
4439% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004440% NexusInfo *nexus_info,ExceptionInfo *exception)
4441%
4442% A description of each parameter follows:
4443%
4444% o image: the image.
4445%
4446% o x,y,columns,rows: These values define the perimeter of a region of
4447% pixels.
4448%
4449% o nexus_info: the cache nexus to set.
4450%
4451% o exception: return any errors or warnings in this structure.
4452%
4453*/
cristybb503372010-05-27 20:51:26 +00004454MagickExport PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy30097232010-07-01 02:16:30 +00004455 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
4456 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004457{
4458 CacheInfo
4459 *cache_info;
4460
4461 MagickOffsetType
4462 offset;
4463
4464 MagickSizeType
4465 number_pixels;
4466
4467 RectangleInfo
4468 region;
4469
4470 /*
4471 Validate pixel cache geometry.
4472 */
4473 cache_info=(CacheInfo *) image->cache;
4474 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4475 {
4476 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4477 "NoPixelsDefinedInCache","`%s'",image->filename);
4478 return((PixelPacket *) NULL);
4479 }
cristybb503372010-05-27 20:51:26 +00004480 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4481 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004482 {
4483 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4484 "PixelsAreNotAuthentic","`%s'",image->filename);
4485 return((PixelPacket *) NULL);
4486 }
4487 offset=(MagickOffsetType) y*cache_info->columns+x;
4488 if (offset < 0)
4489 return((PixelPacket *) NULL);
4490 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4491 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4492 if ((MagickSizeType) offset >= number_pixels)
4493 return((PixelPacket *) NULL);
4494 /*
4495 Return pixel cache.
4496 */
4497 region.x=x;
4498 region.y=y;
4499 region.width=columns;
4500 region.height=rows;
4501 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4502}
4503
4504/*
4505%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4506% %
4507% %
4508% %
4509+ 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 %
4510% %
4511% %
4512% %
4513%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4514%
4515% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4516% defined by the region rectangle and returns a pointer to the region. This
4517% region is subsequently transferred from the pixel cache with
4518% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4519% pixels are transferred, otherwise a NULL is returned.
4520%
4521% The format of the QueueAuthenticPixelsCache() method is:
4522%
cristybb503372010-05-27 20:51:26 +00004523% PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4524% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004525% ExceptionInfo *exception)
4526%
4527% A description of each parameter follows:
4528%
4529% o image: the image.
4530%
4531% o x,y,columns,rows: These values define the perimeter of a region of
4532% pixels.
4533%
4534% o exception: return any errors or warnings in this structure.
4535%
4536*/
cristybb503372010-05-27 20:51:26 +00004537static PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4538 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004539 ExceptionInfo *exception)
4540{
4541 CacheInfo
4542 *cache_info;
4543
cristy6ebe97c2010-07-03 01:17:28 +00004544 int
cristy3ed852e2009-09-05 21:47:34 +00004545 id;
4546
4547 PixelPacket
4548 *pixels;
4549
4550 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickFalse,exception);
4551 if (cache_info == (Cache) NULL)
4552 return((PixelPacket *) NULL);
4553 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00004554 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00004555 pixels=QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4556 exception);
4557 return(pixels);
4558}
4559
4560/*
4561%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4562% %
4563% %
4564% %
4565% Q u e u e A u t h e n t i c P i x e l s %
4566% %
4567% %
4568% %
4569%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4570%
4571% QueueAuthenticPixels() queues a mutable pixel region. If the region is
4572% successfully intialized a pointer to a PixelPacket array representing the
4573% region is returned, otherwise NULL is returned. The returned pointer may
4574% point to a temporary working buffer for the pixels or it may point to the
4575% final location of the pixels in memory.
4576%
4577% Write-only access means that any existing pixel values corresponding to
4578% the region are ignored. This is useful if the initial image is being
4579% created from scratch, or if the existing pixel values are to be
4580% completely replaced without need to refer to their pre-existing values.
4581% The application is free to read and write the pixel buffer returned by
4582% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4583% initialize the pixel array values. Initializing pixel array values is the
4584% application's responsibility.
4585%
4586% Performance is maximized if the selected region is part of one row, or
4587% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004588% pixels in-place (without a copy) if the image is in memory, or in a
4589% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004590% by the user.
4591%
4592% Pixels accessed via the returned pointer represent a simple array of type
4593% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
4594% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
4595% the black color component or the colormap indexes (of type IndexPacket)
4596% corresponding to the region. Once the PixelPacket (and/or IndexPacket)
4597% array has been updated, the changes must be saved back to the underlying
4598% image using SyncAuthenticPixels() or they may be lost.
4599%
4600% The format of the QueueAuthenticPixels() method is:
4601%
cristy5f959472010-05-27 22:19:46 +00004602% PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4603% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004604% ExceptionInfo *exception)
4605%
4606% A description of each parameter follows:
4607%
4608% o image: the image.
4609%
4610% o x,y,columns,rows: These values define the perimeter of a region of
4611% pixels.
4612%
4613% o exception: return any errors or warnings in this structure.
4614%
4615*/
cristybb503372010-05-27 20:51:26 +00004616MagickExport PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4617 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004618 ExceptionInfo *exception)
4619{
4620 CacheInfo
4621 *cache_info;
4622
4623 PixelPacket
4624 *pixels;
4625
4626 assert(image != (Image *) NULL);
4627 assert(image->signature == MagickSignature);
4628 if (image->debug != MagickFalse)
4629 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4630 assert(image->cache != (Cache) NULL);
4631 cache_info=(CacheInfo *) image->cache;
4632 assert(cache_info->signature == MagickSignature);
4633 if (cache_info->methods.queue_authentic_pixels_handler ==
4634 (QueueAuthenticPixelsHandler) NULL)
4635 return((PixelPacket *) NULL);
4636 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4637 rows,exception);
4638 return(pixels);
4639}
4640
4641/*
4642%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4643% %
4644% %
4645% %
4646+ R e a d P i x e l C a c h e I n d e x e s %
4647% %
4648% %
4649% %
4650%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4651%
4652% ReadPixelCacheIndexes() reads colormap indexes from the specified region of
4653% the pixel cache.
4654%
4655% The format of the ReadPixelCacheIndexes() method is:
4656%
4657% MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4658% NexusInfo *nexus_info,ExceptionInfo *exception)
4659%
4660% A description of each parameter follows:
4661%
4662% o cache_info: the pixel cache.
4663%
4664% o nexus_info: the cache nexus to read the colormap indexes.
4665%
4666% o exception: return any errors or warnings in this structure.
4667%
4668*/
4669static MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4670 NexusInfo *nexus_info,ExceptionInfo *exception)
4671{
4672 MagickOffsetType
4673 count,
4674 offset;
4675
4676 MagickSizeType
4677 length,
4678 number_pixels;
4679
4680 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004681 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004682
cristybb503372010-05-27 20:51:26 +00004683 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004684 y;
4685
cristybb503372010-05-27 20:51:26 +00004686 size_t
cristy3ed852e2009-09-05 21:47:34 +00004687 rows;
4688
4689 if (cache_info->debug != MagickFalse)
4690 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4691 cache_info->filename);
4692 if (cache_info->active_index_channel == MagickFalse)
4693 return(MagickFalse);
4694 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4695 return(MagickTrue);
4696 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4697 nexus_info->region.x;
4698 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
4699 rows=nexus_info->region.height;
4700 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004701 q=nexus_info->indexes;
4702 switch (cache_info->type)
4703 {
4704 case MemoryCache:
4705 case MapCache:
4706 {
4707 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004708 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004709
4710 /*
4711 Read indexes from memory.
4712 */
cristydd341db2010-03-04 19:06:38 +00004713 if ((cache_info->columns == nexus_info->region.width) &&
4714 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4715 {
4716 length=number_pixels;
4717 rows=1UL;
4718 }
cristy3ed852e2009-09-05 21:47:34 +00004719 p=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00004720 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004721 {
4722 (void) CopyMagickMemory(q,p,(size_t) length);
4723 p+=cache_info->columns;
4724 q+=nexus_info->region.width;
4725 }
4726 break;
4727 }
4728 case DiskCache:
4729 {
4730 /*
4731 Read indexes from disk.
4732 */
4733 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4734 {
4735 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4736 cache_info->cache_filename);
4737 return(MagickFalse);
4738 }
cristydd341db2010-03-04 19:06:38 +00004739 if ((cache_info->columns == nexus_info->region.width) &&
4740 (number_pixels < MagickMaxBufferExtent))
4741 {
4742 length=number_pixels;
4743 rows=1UL;
4744 }
cristy3ed852e2009-09-05 21:47:34 +00004745 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004746 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004747 {
4748 count=ReadPixelCacheRegion(cache_info,cache_info->offset+number_pixels*
4749 sizeof(PixelPacket)+offset*sizeof(*q),length,(unsigned char *) q);
4750 if ((MagickSizeType) count < length)
4751 break;
4752 offset+=cache_info->columns;
4753 q+=nexus_info->region.width;
4754 }
cristybb503372010-05-27 20:51:26 +00004755 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004756 {
4757 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4758 cache_info->cache_filename);
4759 return(MagickFalse);
4760 }
4761 break;
4762 }
4763 default:
4764 break;
4765 }
4766 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004767 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004768 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004769 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004770 nexus_info->region.width,(double) nexus_info->region.height,(double)
4771 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004772 return(MagickTrue);
4773}
4774
4775/*
4776%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4777% %
4778% %
4779% %
4780+ R e a d P i x e l C a c h e P i x e l s %
4781% %
4782% %
4783% %
4784%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4785%
4786% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4787% cache.
4788%
4789% The format of the ReadPixelCachePixels() method is:
4790%
4791% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4792% NexusInfo *nexus_info,ExceptionInfo *exception)
4793%
4794% A description of each parameter follows:
4795%
4796% o cache_info: the pixel cache.
4797%
4798% o nexus_info: the cache nexus to read the pixels.
4799%
4800% o exception: return any errors or warnings in this structure.
4801%
4802*/
4803static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4804 NexusInfo *nexus_info,ExceptionInfo *exception)
4805{
4806 MagickOffsetType
4807 count,
4808 offset;
4809
4810 MagickSizeType
4811 length,
4812 number_pixels;
4813
cristybb503372010-05-27 20:51:26 +00004814 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004815 y;
4816
4817 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004818 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004819
cristybb503372010-05-27 20:51:26 +00004820 size_t
cristy3ed852e2009-09-05 21:47:34 +00004821 rows;
4822
4823 if (cache_info->debug != MagickFalse)
4824 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4825 cache_info->filename);
4826 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4827 return(MagickTrue);
4828 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4829 nexus_info->region.x;
4830 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
4831 rows=nexus_info->region.height;
4832 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004833 q=nexus_info->pixels;
4834 switch (cache_info->type)
4835 {
4836 case MemoryCache:
4837 case MapCache:
4838 {
4839 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004840 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004841
4842 /*
4843 Read pixels from memory.
4844 */
cristydd341db2010-03-04 19:06:38 +00004845 if ((cache_info->columns == nexus_info->region.width) &&
4846 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4847 {
4848 length=number_pixels;
4849 rows=1UL;
4850 }
cristy3ed852e2009-09-05 21:47:34 +00004851 p=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00004852 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004853 {
4854 (void) CopyMagickMemory(q,p,(size_t) length);
4855 p+=cache_info->columns;
4856 q+=nexus_info->region.width;
4857 }
4858 break;
4859 }
4860 case DiskCache:
4861 {
4862 /*
4863 Read pixels from disk.
4864 */
4865 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4866 {
4867 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4868 cache_info->cache_filename);
4869 return(MagickFalse);
4870 }
cristydd341db2010-03-04 19:06:38 +00004871 if ((cache_info->columns == nexus_info->region.width) &&
4872 (number_pixels < MagickMaxBufferExtent))
4873 {
4874 length=number_pixels;
4875 rows=1UL;
4876 }
cristybb503372010-05-27 20:51:26 +00004877 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004878 {
4879 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4880 sizeof(*q),length,(unsigned char *) q);
4881 if ((MagickSizeType) count < length)
4882 break;
4883 offset+=cache_info->columns;
4884 q+=nexus_info->region.width;
4885 }
cristybb503372010-05-27 20:51:26 +00004886 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004887 {
4888 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4889 cache_info->cache_filename);
4890 return(MagickFalse);
4891 }
4892 break;
4893 }
4894 default:
4895 break;
4896 }
4897 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004898 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004899 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004900 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004901 nexus_info->region.width,(double) nexus_info->region.height,(double)
4902 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004903 return(MagickTrue);
4904}
4905
4906/*
4907%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4908% %
4909% %
4910% %
4911+ R e f e r e n c e P i x e l C a c h e %
4912% %
4913% %
4914% %
4915%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4916%
4917% ReferencePixelCache() increments the reference count associated with the
4918% pixel cache returning a pointer to the cache.
4919%
4920% The format of the ReferencePixelCache method is:
4921%
4922% Cache ReferencePixelCache(Cache cache_info)
4923%
4924% A description of each parameter follows:
4925%
4926% o cache_info: the pixel cache.
4927%
4928*/
4929MagickExport Cache ReferencePixelCache(Cache cache)
4930{
4931 CacheInfo
4932 *cache_info;
4933
4934 assert(cache != (Cache *) NULL);
4935 cache_info=(CacheInfo *) cache;
4936 assert(cache_info->signature == MagickSignature);
4937 if (cache_info->debug != MagickFalse)
4938 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4939 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00004940 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004941 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004942 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004943 return(cache_info);
4944}
4945
4946/*
4947%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4948% %
4949% %
4950% %
4951+ S e t P i x e l C a c h e M e t h o d s %
4952% %
4953% %
4954% %
4955%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4956%
4957% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4958%
4959% The format of the SetPixelCacheMethods() method is:
4960%
4961% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4962%
4963% A description of each parameter follows:
4964%
4965% o cache: the pixel cache.
4966%
4967% o cache_methods: Specifies a pointer to a CacheMethods structure.
4968%
4969*/
4970MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4971{
4972 CacheInfo
4973 *cache_info;
4974
4975 GetOneAuthenticPixelFromHandler
4976 get_one_authentic_pixel_from_handler;
4977
4978 GetOneVirtualPixelFromHandler
4979 get_one_virtual_pixel_from_handler;
4980
4981 /*
4982 Set cache pixel methods.
4983 */
4984 assert(cache != (Cache) NULL);
4985 assert(cache_methods != (CacheMethods *) NULL);
4986 cache_info=(CacheInfo *) cache;
4987 assert(cache_info->signature == MagickSignature);
4988 if (cache_info->debug != MagickFalse)
4989 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4990 cache_info->filename);
4991 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4992 cache_info->methods.get_virtual_pixel_handler=
4993 cache_methods->get_virtual_pixel_handler;
4994 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4995 cache_info->methods.destroy_pixel_handler=
4996 cache_methods->destroy_pixel_handler;
4997 if (cache_methods->get_virtual_indexes_from_handler !=
4998 (GetVirtualIndexesFromHandler) NULL)
4999 cache_info->methods.get_virtual_indexes_from_handler=
5000 cache_methods->get_virtual_indexes_from_handler;
5001 if (cache_methods->get_authentic_pixels_handler !=
5002 (GetAuthenticPixelsHandler) NULL)
5003 cache_info->methods.get_authentic_pixels_handler=
5004 cache_methods->get_authentic_pixels_handler;
5005 if (cache_methods->queue_authentic_pixels_handler !=
5006 (QueueAuthenticPixelsHandler) NULL)
5007 cache_info->methods.queue_authentic_pixels_handler=
5008 cache_methods->queue_authentic_pixels_handler;
5009 if (cache_methods->sync_authentic_pixels_handler !=
5010 (SyncAuthenticPixelsHandler) NULL)
5011 cache_info->methods.sync_authentic_pixels_handler=
5012 cache_methods->sync_authentic_pixels_handler;
5013 if (cache_methods->get_authentic_pixels_from_handler !=
5014 (GetAuthenticPixelsFromHandler) NULL)
5015 cache_info->methods.get_authentic_pixels_from_handler=
5016 cache_methods->get_authentic_pixels_from_handler;
5017 if (cache_methods->get_authentic_indexes_from_handler !=
5018 (GetAuthenticIndexesFromHandler) NULL)
5019 cache_info->methods.get_authentic_indexes_from_handler=
5020 cache_methods->get_authentic_indexes_from_handler;
5021 get_one_virtual_pixel_from_handler=
5022 cache_info->methods.get_one_virtual_pixel_from_handler;
5023 if (get_one_virtual_pixel_from_handler !=
5024 (GetOneVirtualPixelFromHandler) NULL)
5025 cache_info->methods.get_one_virtual_pixel_from_handler=
5026 cache_methods->get_one_virtual_pixel_from_handler;
5027 get_one_authentic_pixel_from_handler=
5028 cache_methods->get_one_authentic_pixel_from_handler;
5029 if (get_one_authentic_pixel_from_handler !=
5030 (GetOneAuthenticPixelFromHandler) NULL)
5031 cache_info->methods.get_one_authentic_pixel_from_handler=
5032 cache_methods->get_one_authentic_pixel_from_handler;
5033}
5034
5035/*
5036%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5037% %
5038% %
5039% %
5040+ S e t P i x e l C a c h e N e x u s P i x e l s %
5041% %
5042% %
5043% %
5044%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5045%
5046% SetPixelCacheNexusPixels() defines the region of the cache for the
5047% specified cache nexus.
5048%
5049% The format of the SetPixelCacheNexusPixels() method is:
5050%
5051% PixelPacket SetPixelCacheNexusPixels(const Image *image,
5052% const RectangleInfo *region,NexusInfo *nexus_info,
5053% ExceptionInfo *exception)
5054%
5055% A description of each parameter follows:
5056%
5057% o image: the image.
5058%
5059% o region: A pointer to the RectangleInfo structure that defines the
5060% region of this particular cache nexus.
5061%
5062% o nexus_info: the cache nexus to set.
5063%
5064% o exception: return any errors or warnings in this structure.
5065%
5066*/
5067static PixelPacket *SetPixelCacheNexusPixels(const Image *image,
5068 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
5069{
5070 CacheInfo
5071 *cache_info;
5072
5073 MagickBooleanType
5074 status;
5075
cristy3ed852e2009-09-05 21:47:34 +00005076 MagickSizeType
5077 length,
5078 number_pixels;
5079
5080 if (image->debug != MagickFalse)
5081 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5082 cache_info=(CacheInfo *) image->cache;
5083 assert(cache_info->signature == MagickSignature);
5084 if (cache_info->type == UndefinedCache)
5085 return((PixelPacket *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00005086 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00005087 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
5088 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00005089 {
cristybb503372010-05-27 20:51:26 +00005090 ssize_t
cristybad067a2010-02-15 17:20:55 +00005091 x,
5092 y;
cristy3ed852e2009-09-05 21:47:34 +00005093
cristyeaedf062010-05-29 22:36:02 +00005094 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
5095 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00005096 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5097 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristy731c3532010-02-15 15:40:03 +00005098 ((nexus_info->region.height == 1UL) ||
5099 ((nexus_info->region.x == 0) &&
5100 ((nexus_info->region.width == cache_info->columns) ||
5101 ((nexus_info->region.width % cache_info->columns) == 0)))))
5102 {
5103 MagickOffsetType
5104 offset;
5105
5106 /*
5107 Pixels are accessed directly from memory.
5108 */
5109 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5110 nexus_info->region.x;
5111 nexus_info->pixels=cache_info->pixels+offset;
5112 nexus_info->indexes=(IndexPacket *) NULL;
5113 if (cache_info->active_index_channel != MagickFalse)
5114 nexus_info->indexes=cache_info->indexes+offset;
5115 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00005116 }
5117 }
5118 /*
5119 Pixels are stored in a cache region until they are synced to the cache.
5120 */
5121 number_pixels=(MagickSizeType) nexus_info->region.width*
5122 nexus_info->region.height;
5123 length=number_pixels*sizeof(PixelPacket);
5124 if (cache_info->active_index_channel != MagickFalse)
5125 length+=number_pixels*sizeof(IndexPacket);
5126 if (nexus_info->cache == (PixelPacket *) NULL)
5127 {
5128 nexus_info->length=length;
5129 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5130 if (status == MagickFalse)
5131 return((PixelPacket *) NULL);
5132 }
5133 else
5134 if (nexus_info->length != length)
5135 {
5136 RelinquishCacheNexusPixels(nexus_info);
5137 nexus_info->length=length;
5138 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5139 if (status == MagickFalse)
5140 return((PixelPacket *) NULL);
5141 }
5142 nexus_info->pixels=nexus_info->cache;
5143 nexus_info->indexes=(IndexPacket *) NULL;
5144 if (cache_info->active_index_channel != MagickFalse)
5145 nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
5146 return(nexus_info->pixels);
5147}
5148
5149/*
5150%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5151% %
5152% %
5153% %
5154% 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 %
5155% %
5156% %
5157% %
5158%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5159%
5160% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5161% pixel cache and returns the previous setting. A virtual pixel is any pixel
5162% access that is outside the boundaries of the image cache.
5163%
5164% The format of the SetPixelCacheVirtualMethod() method is:
5165%
5166% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5167% const VirtualPixelMethod virtual_pixel_method)
5168%
5169% A description of each parameter follows:
5170%
5171% o image: the image.
5172%
5173% o virtual_pixel_method: choose the type of virtual pixel.
5174%
5175*/
5176MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5177 const VirtualPixelMethod virtual_pixel_method)
5178{
5179 CacheInfo
5180 *cache_info;
5181
5182 VirtualPixelMethod
5183 method;
5184
5185 assert(image != (Image *) NULL);
5186 assert(image->signature == MagickSignature);
5187 if (image->debug != MagickFalse)
5188 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5189 assert(image->cache != (Cache) NULL);
5190 cache_info=(CacheInfo *) image->cache;
5191 assert(cache_info->signature == MagickSignature);
5192 method=cache_info->virtual_pixel_method;
5193 cache_info->virtual_pixel_method=virtual_pixel_method;
5194 return(method);
5195}
5196
5197/*
5198%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5199% %
5200% %
5201% %
5202+ 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 %
5203% %
5204% %
5205% %
5206%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5207%
5208% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5209% in-memory or disk cache. The method returns MagickTrue if the pixel region
5210% is synced, otherwise MagickFalse.
5211%
5212% The format of the SyncAuthenticPixelCacheNexus() method is:
5213%
5214% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5215% NexusInfo *nexus_info,ExceptionInfo *exception)
5216%
5217% A description of each parameter follows:
5218%
5219% o image: the image.
5220%
5221% o nexus_info: the cache nexus to sync.
5222%
5223% o exception: return any errors or warnings in this structure.
5224%
5225*/
5226MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5227 NexusInfo *nexus_info,ExceptionInfo *exception)
5228{
5229 CacheInfo
5230 *cache_info;
5231
5232 MagickBooleanType
5233 status;
5234
5235 /*
5236 Transfer pixels to the cache.
5237 */
5238 assert(image != (Image *) NULL);
5239 assert(image->signature == MagickSignature);
5240 if (image->debug != MagickFalse)
5241 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5242 if (image->cache == (Cache) NULL)
5243 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5244 cache_info=(CacheInfo *) image->cache;
5245 if (cache_info->type == UndefinedCache)
5246 return(MagickFalse);
5247 if ((image->clip_mask != (Image *) NULL) &&
5248 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5249 return(MagickFalse);
5250 if ((image->mask != (Image *) NULL) &&
5251 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5252 return(MagickFalse);
5253 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5254 return(MagickTrue);
5255 assert(cache_info->signature == MagickSignature);
5256 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5257 if ((cache_info->active_index_channel != MagickFalse) &&
5258 (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
5259 return(MagickFalse);
5260 return(status);
5261}
5262
5263/*
5264%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5265% %
5266% %
5267% %
5268+ S y n c A u t h e n t i c P i x e l C a c h e %
5269% %
5270% %
5271% %
5272%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5273%
5274% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5275% or disk cache. The method returns MagickTrue if the pixel region is synced,
5276% otherwise MagickFalse.
5277%
5278% The format of the SyncAuthenticPixelsCache() method is:
5279%
5280% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5281% ExceptionInfo *exception)
5282%
5283% A description of each parameter follows:
5284%
5285% o image: the image.
5286%
5287% o exception: return any errors or warnings in this structure.
5288%
5289*/
5290static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5291 ExceptionInfo *exception)
5292{
5293 CacheInfo
5294 *cache_info;
5295
cristy6ebe97c2010-07-03 01:17:28 +00005296 int
cristy3ed852e2009-09-05 21:47:34 +00005297 id;
5298
5299 MagickBooleanType
5300 status;
5301
5302 cache_info=(CacheInfo *) image->cache;
5303 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00005304 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00005305 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5306 exception);
5307 return(status);
5308}
5309
5310/*
5311%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5312% %
5313% %
5314% %
5315% S y n c A u t h e n t i c P i x e l s %
5316% %
5317% %
5318% %
5319%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5320%
5321% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5322% The method returns MagickTrue if the pixel region is flushed, otherwise
5323% MagickFalse.
5324%
5325% The format of the SyncAuthenticPixels() method is:
5326%
5327% MagickBooleanType SyncAuthenticPixels(Image *image,
5328% ExceptionInfo *exception)
5329%
5330% A description of each parameter follows:
5331%
5332% o image: the image.
5333%
5334% o exception: return any errors or warnings in this structure.
5335%
5336*/
5337MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5338 ExceptionInfo *exception)
5339{
5340 CacheInfo
5341 *cache_info;
5342
5343 assert(image != (Image *) NULL);
5344 assert(image->signature == MagickSignature);
5345 if (image->debug != MagickFalse)
5346 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5347 assert(image->cache != (Cache) NULL);
5348 cache_info=(CacheInfo *) image->cache;
5349 assert(cache_info->signature == MagickSignature);
5350 if (cache_info->methods.sync_authentic_pixels_handler ==
5351 (SyncAuthenticPixelsHandler) NULL)
5352 return(MagickFalse);
5353 return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
5354}
5355
5356/*
5357%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5358% %
5359% %
5360% %
5361+ W r i t e P i x e l C a c h e I n d e x e s %
5362% %
5363% %
5364% %
5365%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5366%
5367% WritePixelCacheIndexes() writes the colormap indexes to the specified
5368% region of the pixel cache.
5369%
5370% The format of the WritePixelCacheIndexes() method is:
5371%
5372% MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5373% NexusInfo *nexus_info,ExceptionInfo *exception)
5374%
5375% A description of each parameter follows:
5376%
5377% o cache_info: the pixel cache.
5378%
5379% o nexus_info: the cache nexus to write the colormap indexes.
5380%
5381% o exception: return any errors or warnings in this structure.
5382%
5383*/
5384static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5385 NexusInfo *nexus_info,ExceptionInfo *exception)
5386{
5387 MagickOffsetType
5388 count,
5389 offset;
5390
5391 MagickSizeType
5392 length,
5393 number_pixels;
5394
5395 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005396 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005397
cristybb503372010-05-27 20:51:26 +00005398 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005399 y;
5400
cristybb503372010-05-27 20:51:26 +00005401 size_t
cristy3ed852e2009-09-05 21:47:34 +00005402 rows;
5403
5404 if (cache_info->debug != MagickFalse)
5405 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
5406 cache_info->filename);
5407 if (cache_info->active_index_channel == MagickFalse)
5408 return(MagickFalse);
5409 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5410 return(MagickTrue);
5411 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5412 nexus_info->region.x;
5413 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
5414 rows=nexus_info->region.height;
5415 number_pixels=(MagickSizeType) length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005416 p=nexus_info->indexes;
5417 switch (cache_info->type)
5418 {
5419 case MemoryCache:
5420 case MapCache:
5421 {
5422 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005423 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005424
5425 /*
5426 Write indexes to memory.
5427 */
cristydd341db2010-03-04 19:06:38 +00005428 if ((cache_info->columns == nexus_info->region.width) &&
5429 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5430 {
5431 length=number_pixels;
5432 rows=1UL;
5433 }
cristy3ed852e2009-09-05 21:47:34 +00005434 q=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00005435 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005436 {
5437 (void) CopyMagickMemory(q,p,(size_t) length);
5438 p+=nexus_info->region.width;
5439 q+=cache_info->columns;
5440 }
5441 break;
5442 }
5443 case DiskCache:
5444 {
5445 /*
5446 Write indexes to disk.
5447 */
5448 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5449 {
5450 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5451 cache_info->cache_filename);
5452 return(MagickFalse);
5453 }
cristydd341db2010-03-04 19:06:38 +00005454 if ((cache_info->columns == nexus_info->region.width) &&
5455 (number_pixels < MagickMaxBufferExtent))
5456 {
5457 length=number_pixels;
5458 rows=1UL;
5459 }
cristy3ed852e2009-09-05 21:47:34 +00005460 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005461 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005462 {
5463 count=WritePixelCacheRegion(cache_info,cache_info->offset+number_pixels*
5464 sizeof(PixelPacket)+offset*sizeof(*p),length,
5465 (const unsigned char *) p);
5466 if ((MagickSizeType) count < length)
5467 break;
5468 p+=nexus_info->region.width;
5469 offset+=cache_info->columns;
5470 }
cristybb503372010-05-27 20:51:26 +00005471 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005472 {
5473 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5474 cache_info->cache_filename);
5475 return(MagickFalse);
5476 }
5477 break;
5478 }
5479 default:
5480 break;
5481 }
5482 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005483 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005484 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005485 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005486 nexus_info->region.width,(double) nexus_info->region.height,(double)
5487 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005488 return(MagickTrue);
5489}
5490
5491/*
5492%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5493% %
5494% %
5495% %
5496+ W r i t e C a c h e P i x e l s %
5497% %
5498% %
5499% %
5500%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5501%
5502% WritePixelCachePixels() writes image pixels to the specified region of the
5503% pixel cache.
5504%
5505% The format of the WritePixelCachePixels() method is:
5506%
5507% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5508% NexusInfo *nexus_info,ExceptionInfo *exception)
5509%
5510% A description of each parameter follows:
5511%
5512% o cache_info: the pixel cache.
5513%
5514% o nexus_info: the cache nexus to write the pixels.
5515%
5516% o exception: return any errors or warnings in this structure.
5517%
5518*/
5519static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5520 NexusInfo *nexus_info,ExceptionInfo *exception)
5521{
5522 MagickOffsetType
5523 count,
5524 offset;
5525
5526 MagickSizeType
5527 length,
5528 number_pixels;
5529
cristy3ed852e2009-09-05 21:47:34 +00005530 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005531 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005532
cristybb503372010-05-27 20:51:26 +00005533 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005534 y;
5535
cristybb503372010-05-27 20:51:26 +00005536 size_t
cristy3ed852e2009-09-05 21:47:34 +00005537 rows;
5538
5539 if (cache_info->debug != MagickFalse)
5540 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
5541 cache_info->filename);
5542 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5543 return(MagickTrue);
5544 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5545 nexus_info->region.x;
5546 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
5547 rows=nexus_info->region.height;
5548 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005549 p=nexus_info->pixels;
5550 switch (cache_info->type)
5551 {
5552 case MemoryCache:
5553 case MapCache:
5554 {
5555 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005556 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005557
5558 /*
5559 Write pixels to memory.
5560 */
cristydd341db2010-03-04 19:06:38 +00005561 if ((cache_info->columns == nexus_info->region.width) &&
5562 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5563 {
5564 length=number_pixels;
5565 rows=1UL;
5566 }
cristy3ed852e2009-09-05 21:47:34 +00005567 q=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00005568 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005569 {
5570 (void) CopyMagickMemory(q,p,(size_t) length);
5571 p+=nexus_info->region.width;
5572 q+=cache_info->columns;
5573 }
5574 break;
5575 }
5576 case DiskCache:
5577 {
5578 /*
5579 Write pixels to disk.
5580 */
5581 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5582 {
5583 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5584 cache_info->cache_filename);
5585 return(MagickFalse);
5586 }
cristydd341db2010-03-04 19:06:38 +00005587 if ((cache_info->columns == nexus_info->region.width) &&
5588 (number_pixels < MagickMaxBufferExtent))
5589 {
5590 length=number_pixels;
5591 rows=1UL;
5592 }
cristybb503372010-05-27 20:51:26 +00005593 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005594 {
5595 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5596 sizeof(*p),length,(const unsigned char *) p);
5597 if ((MagickSizeType) count < length)
5598 break;
5599 p+=nexus_info->region.width;
5600 offset+=cache_info->columns;
5601 }
cristybb503372010-05-27 20:51:26 +00005602 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005603 {
5604 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5605 cache_info->cache_filename);
5606 return(MagickFalse);
5607 }
5608 break;
5609 }
5610 default:
5611 break;
5612 }
5613 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005614 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005615 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005616 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005617 nexus_info->region.width,(double) nexus_info->region.height,(double)
5618 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005619 return(MagickTrue);
5620}