blob: 1337847fdcd4f906a2bfb843832f677762f5c565 [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);
cristy3ed852e2009-09-05 21:47:34 +0000204 cache_info->semaphore=AllocateSemaphoreInfo();
cristy93505cf2010-08-10 21:37:49 +0000205 cache_info->reference_count=1;
cristy3ed852e2009-09-05 21:47:34 +0000206 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*/
cristy2cd7a752010-08-23 00:48:54 +0000250MagickExport NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000251{
cristy3ed852e2009-09-05 21:47:34 +0000252 NexusInfo
253 **nexus_info;
254
cristye076a6e2010-08-15 19:59:43 +0000255 register ssize_t
256 i;
257
cristy3ed852e2009-09-05 21:47:34 +0000258 nexus_info=(NexusInfo **) AcquireAlignedMemory(number_threads,
259 sizeof(*nexus_info));
260 if (nexus_info == (NexusInfo **) NULL)
261 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristybb503372010-05-27 20:51:26 +0000262 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000263 {
264 nexus_info[i]=(NexusInfo *) AcquireAlignedMemory(1,sizeof(**nexus_info));
265 if (nexus_info[i] == (NexusInfo *) NULL)
266 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
267 (void) ResetMagickMemory(nexus_info[i],0,sizeof(*nexus_info[i]));
268 nexus_info[i]->signature=MagickSignature;
269 }
270 return(nexus_info);
271}
272
273/*
274%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
275% %
276% %
277% %
cristyd43a46b2010-01-21 02:13:41 +0000278+ A c q u i r e P i x e l C a c h e P i x e l s %
279% %
280% %
281% %
282%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
283%
284% AcquirePixelCachePixels() returns the pixels associated with the specified
285% image.
286%
287% The format of the AcquirePixelCachePixels() method is:
288%
289% const void *AcquirePixelCachePixels(const Image *image,
290% MagickSizeType *length,ExceptionInfo *exception)
291%
292% A description of each parameter follows:
293%
294% o image: the image.
295%
296% o length: the pixel cache length.
297%
298% o exception: return any errors or warnings in this structure.
299%
300*/
301MagickExport const void *AcquirePixelCachePixels(const Image *image,
302 MagickSizeType *length,ExceptionInfo *exception)
303{
304 CacheInfo
305 *cache_info;
306
307 assert(image != (const Image *) NULL);
308 assert(image->signature == MagickSignature);
cristyd43a46b2010-01-21 02:13:41 +0000309 assert(exception != (ExceptionInfo *) NULL);
310 assert(exception->signature == MagickSignature);
311 assert(image->cache != (Cache) NULL);
312 cache_info=(CacheInfo *) image->cache;
313 assert(cache_info->signature == MagickSignature);
314 *length=0;
315 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
316 return((const void *) NULL);
317 *length=cache_info->length;
318 return((const void *) cache_info->pixels);
319}
320
321/*
322%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
323% %
324% %
325% %
cristyf34a1452009-10-24 22:29:27 +0000326+ C a c h e C o m p o n e n t G e n e s i s %
327% %
328% %
329% %
330%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
331%
332% CacheComponentGenesis() instantiates the cache component.
333%
334% The format of the CacheComponentGenesis method is:
335%
336% MagickBooleanType CacheComponentGenesis(void)
337%
338*/
339MagickExport MagickBooleanType CacheComponentGenesis(void)
340{
cristy165b6092009-10-26 13:52:10 +0000341 AcquireSemaphoreInfo(&cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000342 return(MagickTrue);
343}
344
345/*
346%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
347% %
348% %
349% %
350+ C a c h e C o m p o n e n t T e r m i n u s %
351% %
352% %
353% %
354%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
355%
356% CacheComponentTerminus() destroys the cache component.
357%
358% The format of the CacheComponentTerminus() method is:
359%
360% CacheComponentTerminus(void)
361%
362*/
363MagickExport void CacheComponentTerminus(void)
364{
cristy18b17442009-10-25 18:36:48 +0000365 if (cache_semaphore == (SemaphoreInfo *) NULL)
366 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000367 LockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000368 if (cache_resources != (SplayTreeInfo *) NULL)
369 cache_resources=DestroySplayTree(cache_resources);
370 instantiate_cache=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +0000371 UnlockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000372 DestroySemaphoreInfo(&cache_semaphore);
373}
374
375/*
376%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
377% %
378% %
379% %
cristy3ed852e2009-09-05 21:47:34 +0000380+ C l i p P i x e l C a c h e N e x u s %
381% %
382% %
383% %
384%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
385%
386% ClipPixelCacheNexus() clips the cache nexus as defined by the image clip
387% mask. The method returns MagickTrue if the pixel region is clipped,
388% otherwise MagickFalse.
389%
390% The format of the ClipPixelCacheNexus() method is:
391%
392% MagickBooleanType ClipPixelCacheNexus(Image *image,NexusInfo *nexus_info,
393% ExceptionInfo *exception)
394%
395% A description of each parameter follows:
396%
397% o image: the image.
398%
399% o nexus_info: the cache nexus to clip.
400%
401% o exception: return any errors or warnings in this structure.
402%
403*/
404static MagickBooleanType ClipPixelCacheNexus(Image *image,
405 NexusInfo *nexus_info,ExceptionInfo *exception)
406{
407 CacheInfo
408 *cache_info;
409
410 MagickSizeType
411 number_pixels;
412
413 NexusInfo
414 **clip_nexus,
415 **image_nexus;
416
417 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000418 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +0000419
420 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +0000421 *restrict nexus_indexes,
422 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +0000423
cristy3ed852e2009-09-05 21:47:34 +0000424 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000425 *restrict p,
426 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000427
cristye076a6e2010-08-15 19:59:43 +0000428 register ssize_t
429 i;
430
cristy3ed852e2009-09-05 21:47:34 +0000431 /*
432 Apply clip mask.
433 */
434 if (image->debug != MagickFalse)
435 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
436 if (image->clip_mask == (Image *) NULL)
437 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +0000438 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +0000439 if (cache_info == (Cache) NULL)
440 return(MagickFalse);
441 image_nexus=AcquirePixelCacheNexus(1);
442 clip_nexus=AcquirePixelCacheNexus(1);
443 if ((image_nexus == (NexusInfo **) NULL) ||
444 (clip_nexus == (NexusInfo **) NULL))
445 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
446 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,nexus_info->region.y,
447 nexus_info->region.width,nexus_info->region.height,image_nexus[0],
448 exception);
449 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
450 q=nexus_info->pixels;
451 nexus_indexes=nexus_info->indexes;
452 r=GetVirtualPixelsFromNexus(image->clip_mask,MaskVirtualPixelMethod,
453 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
454 nexus_info->region.height,clip_nexus[0],exception);
455 number_pixels=(MagickSizeType) nexus_info->region.width*
456 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +0000457 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000458 {
459 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
460 break;
461 if (PixelIntensityToQuantum(r) > ((Quantum) QuantumRange/2))
462 {
cristyce70c172010-01-07 17:15:30 +0000463 SetRedPixelComponent(q,GetRedPixelComponent(p));
464 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
465 SetBluePixelComponent(q,GetBluePixelComponent(p));
466 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
cristy3ed852e2009-09-05 21:47:34 +0000467 if (cache_info->active_index_channel != MagickFalse)
468 nexus_indexes[i]=indexes[i];
469 }
470 p++;
471 q++;
472 r++;
473 }
474 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
475 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +0000476 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +0000477 return(MagickFalse);
478 return(MagickTrue);
479}
480
481/*
482%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
483% %
484% %
485% %
486+ C l o n e P i x e l C a c h e %
487% %
488% %
489% %
490%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
491%
492% ClonePixelCache() clones a pixel cache.
493%
494% The format of the ClonePixelCache() method is:
495%
496% Cache ClonePixelCache(const Cache cache)
497%
498% A description of each parameter follows:
499%
500% o cache: the pixel cache.
501%
502*/
503MagickExport Cache ClonePixelCache(const Cache cache)
504{
505 CacheInfo
506 *clone_info;
507
508 const CacheInfo
509 *cache_info;
510
511 assert(cache != (const Cache) NULL);
512 cache_info=(const CacheInfo *) cache;
513 assert(cache_info->signature == MagickSignature);
514 if (cache_info->debug != MagickFalse)
515 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
516 cache_info->filename);
517 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
518 if (clone_info == (Cache) NULL)
519 return((Cache) NULL);
520 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
521 return((Cache ) clone_info);
522}
523
524/*
525%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
526% %
527% %
528% %
529+ C l o n e P i x e l C a c h e N e x u s %
530% %
531% %
532% %
533%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
534%
535% ClonePixelCacheNexus() clones the source cache nexus to the destination
536% nexus.
537%
538% The format of the ClonePixelCacheNexus() method is:
539%
540% MagickBooleanType ClonePixelCacheNexus(CacheInfo *destination,
541% CacheInfo *source,ExceptionInfo *exception)
542%
543% A description of each parameter follows:
544%
545% o destination: the destination cache nexus.
546%
547% o source: the source cache nexus.
548%
549% o exception: return any errors or warnings in this structure.
550%
551*/
552
553static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
554 NexusInfo *nexus_info,ExceptionInfo *exception)
555{
556 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
557 return(MagickFalse);
558 nexus_info->mapped=MagickFalse;
559 nexus_info->cache=(PixelPacket *) AcquireMagickMemory((size_t)
560 nexus_info->length);
561 if (nexus_info->cache == (PixelPacket *) NULL)
562 {
563 nexus_info->mapped=MagickTrue;
564 nexus_info->cache=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
565 nexus_info->length);
566 }
567 if (nexus_info->cache == (PixelPacket *) NULL)
568 {
569 (void) ThrowMagickException(exception,GetMagickModule(),
570 ResourceLimitError,"MemoryAllocationFailed","`%s'",
571 cache_info->filename);
572 return(MagickFalse);
573 }
574 return(MagickTrue);
575}
576
577static MagickBooleanType ClonePixelCacheNexus(CacheInfo *destination,
578 CacheInfo *source,ExceptionInfo *exception)
579{
580 MagickBooleanType
581 status;
582
cristye076a6e2010-08-15 19:59:43 +0000583 register ssize_t
584 i;
585
cristy3ed852e2009-09-05 21:47:34 +0000586 status=MagickTrue;
cristybb503372010-05-27 20:51:26 +0000587 for (i=0; i < (ssize_t) source->number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000588 {
cristy4b7818d2010-08-29 00:47:57 +0000589 register const NexusInfo
590 *p;
591
592 register NexusInfo
593 *q;
594
cristy3ed852e2009-09-05 21:47:34 +0000595 p=source->nexus_info[i];
596 q=destination->nexus_info[i];
cristy3ed852e2009-09-05 21:47:34 +0000597 q->region=p->region;
cristy5485e372010-09-15 19:02:29 +0000598 q->mapped=MagickFalse;
599 q->cache=(PixelPacket *) NULL;
600 q->pixels=(PixelPacket *) NULL;
601 q->indexes=(IndexPacket *) NULL;
602 q->length=0;
cristy3ed852e2009-09-05 21:47:34 +0000603 if (p->cache != (PixelPacket *) NULL)
604 {
605 status=AcquireCacheNexusPixels(source,q,exception);
606 if (status != MagickFalse)
607 {
cristy4b7818d2010-08-29 00:47:57 +0000608 MagickSizeType
609 number_pixels;
610
cristy3ed852e2009-09-05 21:47:34 +0000611 (void) CopyMagickMemory(q->cache,p->cache,(size_t) p->length);
612 q->pixels=q->cache;
613 q->indexes=(IndexPacket *) NULL;
614 number_pixels=(MagickSizeType) q->region.width*q->region.height;
615 if (p->indexes != (IndexPacket *) NULL)
616 q->indexes=(IndexPacket *) (q->pixels+number_pixels);
cristy5485e372010-09-15 19:02:29 +0000617 q->length=p->length;
cristy3ed852e2009-09-05 21:47:34 +0000618 }
619 }
620 }
621 return(status);
622}
623
624/*
625%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
626% %
627% %
628% %
cristy60c44a82009-10-07 00:58:49 +0000629+ 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 +0000630% %
631% %
632% %
633%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
634% ClonePixelCachePixels() clones the source pixel cache to the destination
635% cache.
636%
637% The format of the ClonePixelCachePixels() method is:
638%
639% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
640% CacheInfo *source_info,ExceptionInfo *exception)
641%
642% A description of each parameter follows:
643%
644% o cache_info: the pixel cache.
645%
646% o source_info: the source pixel cache.
647%
648% o exception: return any errors or warnings in this structure.
649%
650*/
651
652static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
653{
654 int
655 status;
656
cristy5ee247a2010-02-12 15:42:34 +0000657 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000658 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000659 if (cache_info->file != -1)
660 status=close(cache_info->file);
cristy3ed852e2009-09-05 21:47:34 +0000661 cache_info->file=(-1);
662 RelinquishMagickResource(FileResource,1);
cristyf84a1932010-01-03 18:00:18 +0000663 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000664 return(status == -1 ? MagickFalse : MagickTrue);
665}
666
667static void LimitPixelCacheDescriptors(void)
668{
669 register CacheInfo
670 *p,
671 *q;
672
673 /*
674 Limit # of open file descriptors.
675 */
676 if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
677 return;
cristyf84a1932010-01-03 18:00:18 +0000678 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000679 if (cache_resources == (SplayTreeInfo *) NULL)
680 {
cristyf84a1932010-01-03 18:00:18 +0000681 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000682 return;
683 }
684 ResetSplayTreeIterator(cache_resources);
685 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
686 while (p != (CacheInfo *) NULL)
687 {
688 if ((p->type == DiskCache) && (p->file != -1))
cristy508d9312010-02-10 21:10:30 +0000689 break;
cristy3ed852e2009-09-05 21:47:34 +0000690 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
691 }
692 for (q=p; p != (CacheInfo *) NULL; )
693 {
694 if ((p->type == DiskCache) && (p->file != -1) &&
695 (p->timestamp < q->timestamp))
cristy508d9312010-02-10 21:10:30 +0000696 q=p;
cristy3ed852e2009-09-05 21:47:34 +0000697 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
698 }
699 if (q != (CacheInfo *) NULL)
cristy9e116922010-02-12 20:58:13 +0000700 {
701 /*
702 Close least recently used cache.
703 */
704 (void) close(q->file);
705 q->file=(-1);
706 }
cristyf84a1932010-01-03 18:00:18 +0000707 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000708}
709
710static inline MagickSizeType MagickMax(const MagickSizeType x,
711 const MagickSizeType y)
712{
713 if (x > y)
714 return(x);
715 return(y);
716}
717
718static inline MagickSizeType MagickMin(const MagickSizeType x,
719 const MagickSizeType y)
720{
721 if (x < y)
722 return(x);
723 return(y);
724}
725
726static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
727 const MapMode mode)
728{
729 int
730 file;
731
732 /*
733 Open pixel cache on disk.
734 */
cristyf84a1932010-01-03 18:00:18 +0000735 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000736 if (cache_info->file != -1)
737 {
cristyf84a1932010-01-03 18:00:18 +0000738 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000739 return(MagickTrue); /* cache already open */
740 }
741 LimitPixelCacheDescriptors();
742 if (*cache_info->cache_filename == '\0')
743 file=AcquireUniqueFileResource(cache_info->cache_filename);
744 else
745 switch (mode)
746 {
747 case ReadMode:
748 {
749 file=open(cache_info->cache_filename,O_RDONLY | O_BINARY);
750 break;
751 }
752 case WriteMode:
753 {
754 file=open(cache_info->cache_filename,O_WRONLY | O_CREAT | O_BINARY |
755 O_EXCL,S_MODE);
756 if (file == -1)
757 file=open(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
758 break;
759 }
760 case IOMode:
761 default:
762 {
763 file=open(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
764 O_EXCL,S_MODE);
765 if (file == -1)
766 file=open(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
767 break;
768 }
769 }
770 if (file == -1)
771 {
cristyf84a1932010-01-03 18:00:18 +0000772 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000773 return(MagickFalse);
774 }
775 (void) AcquireMagickResource(FileResource,1);
776 cache_info->file=file;
777 cache_info->timestamp=time(0);
cristyf84a1932010-01-03 18:00:18 +0000778 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000779 return(MagickTrue);
780}
781
782static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
783 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000784 unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000785{
786 register MagickOffsetType
787 i;
788
789 ssize_t
790 count;
791
cristy08a88202010-03-04 19:18:05 +0000792 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000793#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000794 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000795 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
796 {
cristyf84a1932010-01-03 18:00:18 +0000797 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000798 return((MagickOffsetType) -1);
799 }
800#endif
801 count=0;
802 for (i=0; i < (MagickOffsetType) length; i+=count)
803 {
804#if !defined(MAGICKCORE_HAVE_PREAD)
805 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
806 (MagickSizeType) SSIZE_MAX));
807#else
808 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
809 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
810#endif
811 if (count > 0)
812 continue;
813 count=0;
814 if (errno != EINTR)
815 {
816 i=(-1);
817 break;
818 }
819 }
820#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000821 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000822#endif
823 return(i);
824}
825
826static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
827 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000828 const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000829{
830 register MagickOffsetType
831 i;
832
833 ssize_t
834 count;
835
cristy08a88202010-03-04 19:18:05 +0000836 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000837#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000838 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000839 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
840 {
cristyf84a1932010-01-03 18:00:18 +0000841 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000842 return((MagickOffsetType) -1);
843 }
844#endif
845 count=0;
846 for (i=0; i < (MagickOffsetType) length; i+=count)
847 {
848#if !defined(MAGICKCORE_HAVE_PWRITE)
849 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
850 (MagickSizeType) SSIZE_MAX));
851#else
852 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
853 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
854#endif
855 if (count > 0)
856 continue;
857 count=0;
858 if (errno != EINTR)
859 {
860 i=(-1);
861 break;
862 }
863 }
864#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000865 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000866#endif
867 return(i);
868}
869
870static MagickBooleanType CloneDiskToDiskPixelCache(CacheInfo *clone_info,
871 CacheInfo *cache_info,ExceptionInfo *exception)
872{
873 MagickOffsetType
874 count,
875 offset,
876 source_offset;
877
878 MagickSizeType
879 length;
880
cristy3ed852e2009-09-05 21:47:34 +0000881 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000882 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +0000883
cristye076a6e2010-08-15 19:59:43 +0000884 register ssize_t
885 y;
886
cristybb503372010-05-27 20:51:26 +0000887 size_t
cristy3ed852e2009-09-05 21:47:34 +0000888 columns,
889 rows;
890
891 if (cache_info->debug != MagickFalse)
892 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
893 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
894 {
895 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
896 clone_info->cache_filename);
897 return(MagickFalse);
898 }
899 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
900 {
901 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
902 cache_info->cache_filename);
903 return(MagickFalse);
904 }
cristybb503372010-05-27 20:51:26 +0000905 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
906 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +0000907 if ((clone_info->active_index_channel != MagickFalse) &&
908 (cache_info->active_index_channel != MagickFalse))
909 {
910 register IndexPacket
911 *indexes;
912
913 /*
914 Clone cache indexes.
915 */
916 length=MagickMax(clone_info->columns,cache_info->columns)*
917 sizeof(*indexes);
918 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
919 if (indexes == (IndexPacket *) NULL)
920 {
921 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
922 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
923 return(MagickFalse);
924 }
925 (void) ResetMagickMemory(indexes,0,(size_t) length);
926 length=columns*sizeof(*indexes);
927 source_offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
928 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
929 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
930 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +0000931 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000932 {
933 source_offset-=cache_info->columns*sizeof(*indexes);
934 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
935 length,(unsigned char *) indexes);
936 if ((MagickSizeType) count != length)
937 break;
938 offset-=clone_info->columns*sizeof(*indexes);
939 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
940 (unsigned char *) indexes);
941 if ((MagickSizeType) count != length)
942 break;
943 }
cristybb503372010-05-27 20:51:26 +0000944 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000945 {
946 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
947 ThrowFileException(exception,CacheError,"UnableToCloneCache",
948 cache_info->cache_filename);
949 return(MagickFalse);
950 }
951 if (clone_info->columns > cache_info->columns)
952 {
953 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
954 (void) ResetMagickMemory(indexes,0,(size_t) length);
955 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
956 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +0000957 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000958 {
959 offset-=clone_info->columns*sizeof(*indexes);
960 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
961 length,(unsigned char *) indexes);
962 if ((MagickSizeType) count != length)
963 break;
964 }
cristybb503372010-05-27 20:51:26 +0000965 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000966 {
967 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
968 ThrowFileException(exception,CacheError,"UnableToCloneCache",
969 cache_info->cache_filename);
970 return(MagickFalse);
971 }
972 }
973 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
974 }
975 /*
976 Clone cache pixels.
977 */
978 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
979 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
980 if (pixels == (PixelPacket *) NULL)
981 {
982 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
983 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
984 return(MagickFalse);
985 }
986 (void) ResetMagickMemory(pixels,0,(size_t) length);
987 length=columns*sizeof(*pixels);
988 source_offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
989 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +0000990 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000991 {
992 source_offset-=cache_info->columns*sizeof(*pixels);
993 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
994 length,(unsigned char *) pixels);
995 if ((MagickSizeType) count != length)
996 break;
997 offset-=clone_info->columns*sizeof(*pixels);
998 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
999 (unsigned char *) pixels);
1000 if ((MagickSizeType) count != length)
1001 break;
1002 }
cristybb503372010-05-27 20:51:26 +00001003 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001004 {
1005 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1006 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1007 cache_info->cache_filename);
1008 return(MagickFalse);
1009 }
1010 if (clone_info->columns > cache_info->columns)
1011 {
1012 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
1013 sizeof(*pixels);
1014 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1015 (void) ResetMagickMemory(pixels,0,(size_t) length);
cristybb503372010-05-27 20:51:26 +00001016 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001017 {
1018 offset-=clone_info->columns*sizeof(*pixels);
1019 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1020 (unsigned char *) pixels);
1021 if ((MagickSizeType) count != length)
1022 break;
1023 }
cristybb503372010-05-27 20:51:26 +00001024 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001025 {
1026 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1027 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1028 cache_info->cache_filename);
1029 return(MagickFalse);
1030 }
1031 }
1032 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1033 return(MagickTrue);
1034}
1035
1036static MagickBooleanType CloneDiskToMemoryPixelCache(CacheInfo *clone_info,
1037 CacheInfo *cache_info,ExceptionInfo *exception)
1038{
1039 MagickOffsetType
1040 count,
1041 offset;
1042
1043 MagickSizeType
1044 length;
1045
cristy3ed852e2009-09-05 21:47:34 +00001046 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001047 *restrict pixels,
1048 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00001049
cristye076a6e2010-08-15 19:59:43 +00001050 register ssize_t
1051 y;
1052
cristybb503372010-05-27 20:51:26 +00001053 size_t
cristy3ed852e2009-09-05 21:47:34 +00001054 columns,
1055 rows;
1056
1057 if (cache_info->debug != MagickFalse)
1058 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
1059 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
1060 {
1061 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1062 cache_info->cache_filename);
1063 return(MagickFalse);
1064 }
cristybb503372010-05-27 20:51:26 +00001065 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1066 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001067 if ((clone_info->active_index_channel != MagickFalse) &&
1068 (cache_info->active_index_channel != MagickFalse))
1069 {
1070 register IndexPacket
1071 *indexes,
1072 *q;
1073
1074 /*
1075 Clone cache indexes.
1076 */
1077 length=MagickMax(clone_info->columns,cache_info->columns)*
1078 sizeof(*indexes);
1079 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1080 if (indexes == (IndexPacket *) NULL)
1081 {
1082 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1083 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1084 return(MagickFalse);
1085 }
1086 (void) ResetMagickMemory(indexes,0,(size_t) length);
1087 length=columns*sizeof(IndexPacket);
1088 offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
1089 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
1090 q=clone_info->indexes+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001091 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001092 {
1093 offset-=cache_info->columns*sizeof(IndexPacket);
1094 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,
1095 length,(unsigned char *) indexes);
1096 if ((MagickSizeType) count != length)
1097 break;
1098 q-=clone_info->columns;
1099 (void) CopyMagickMemory(q,indexes,(size_t) length);
1100 if ((MagickSizeType) count != length)
1101 break;
1102 }
cristybb503372010-05-27 20:51:26 +00001103 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001104 {
1105 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1106 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1107 cache_info->cache_filename);
1108 return(MagickFalse);
1109 }
1110 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1111 }
1112 /*
1113 Clone cache pixels.
1114 */
1115 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1116 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1117 if (pixels == (PixelPacket *) NULL)
1118 {
1119 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1120 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1121 return(MagickFalse);
1122 }
1123 (void) ResetMagickMemory(pixels,0,(size_t) length);
1124 length=columns*sizeof(*pixels);
1125 offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
1126 q=clone_info->pixels+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001127 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001128 {
1129 offset-=cache_info->columns*sizeof(*pixels);
1130 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,length,
1131 (unsigned char *) pixels);
1132 if ((MagickSizeType) count != length)
1133 break;
1134 q-=clone_info->columns;
1135 (void) CopyMagickMemory(q,pixels,(size_t) length);
1136 }
cristybb503372010-05-27 20:51:26 +00001137 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001138 {
1139 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1140 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1141 cache_info->cache_filename);
1142 return(MagickFalse);
1143 }
1144 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1145 return(MagickTrue);
1146}
1147
1148static MagickBooleanType CloneMemoryToDiskPixelCache(CacheInfo *clone_info,
1149 CacheInfo *cache_info,ExceptionInfo *exception)
1150{
1151 MagickOffsetType
1152 count,
1153 offset;
1154
1155 MagickSizeType
1156 length;
1157
cristy3ed852e2009-09-05 21:47:34 +00001158 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001159 *restrict p,
1160 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +00001161
cristye076a6e2010-08-15 19:59:43 +00001162 register ssize_t
1163 y;
1164
cristybb503372010-05-27 20:51:26 +00001165 size_t
cristy3ed852e2009-09-05 21:47:34 +00001166 columns,
1167 rows;
1168
1169 if (cache_info->debug != MagickFalse)
1170 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
1171 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
1172 {
1173 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1174 clone_info->cache_filename);
1175 return(MagickFalse);
1176 }
cristybb503372010-05-27 20:51:26 +00001177 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1178 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001179 if ((clone_info->active_index_channel != MagickFalse) &&
1180 (cache_info->active_index_channel != MagickFalse))
1181 {
1182 register IndexPacket
1183 *p,
1184 *indexes;
1185
1186 /*
1187 Clone cache indexes.
1188 */
1189 length=MagickMax(clone_info->columns,cache_info->columns)*
1190 sizeof(*indexes);
1191 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1192 if (indexes == (IndexPacket *) NULL)
1193 {
1194 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1195 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1196 return(MagickFalse);
1197 }
1198 (void) ResetMagickMemory(indexes,0,(size_t) length);
1199 length=columns*sizeof(*indexes);
1200 p=cache_info->indexes+cache_info->columns*rows;
1201 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1202 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +00001203 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001204 {
1205 p-=cache_info->columns;
1206 (void) CopyMagickMemory(indexes,p,(size_t) length);
1207 offset-=clone_info->columns*sizeof(*indexes);
1208 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1209 (unsigned char *) indexes);
1210 if ((MagickSizeType) count != length)
1211 break;
1212 }
cristybb503372010-05-27 20:51:26 +00001213 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001214 {
1215 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1216 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1217 cache_info->cache_filename);
1218 return(MagickFalse);
1219 }
1220 if (clone_info->columns > cache_info->columns)
1221 {
1222 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
1223 (void) ResetMagickMemory(indexes,0,(size_t) length);
1224 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1225 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +00001226 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001227 {
1228 offset-=clone_info->columns*sizeof(*indexes);
1229 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
1230 length,(unsigned char *) indexes);
1231 if ((MagickSizeType) count != length)
1232 break;
1233 }
cristybb503372010-05-27 20:51:26 +00001234 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001235 {
1236 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1237 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1238 cache_info->cache_filename);
1239 return(MagickFalse);
1240 }
1241 }
1242 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1243 }
1244 /*
1245 Clone cache pixels.
1246 */
1247 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1248 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1249 if (pixels == (PixelPacket *) NULL)
1250 {
1251 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1252 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1253 return(MagickFalse);
1254 }
1255 (void) ResetMagickMemory(pixels,0,(size_t) length);
1256 length=columns*sizeof(*pixels);
1257 p=cache_info->pixels+cache_info->columns*rows;
1258 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +00001259 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001260 {
1261 p-=cache_info->columns;
1262 (void) CopyMagickMemory(pixels,p,(size_t) length);
1263 offset-=clone_info->columns*sizeof(*pixels);
1264 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1265 (unsigned char *) pixels);
1266 if ((MagickSizeType) count != length)
1267 break;
1268 }
cristybb503372010-05-27 20:51:26 +00001269 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001270 {
1271 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1272 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1273 cache_info->cache_filename);
1274 return(MagickFalse);
1275 }
1276 if (clone_info->columns > cache_info->columns)
1277 {
1278 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
1279 sizeof(*pixels);
1280 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1281 (void) ResetMagickMemory(pixels,0,(size_t) length);
cristybb503372010-05-27 20:51:26 +00001282 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001283 {
1284 offset-=clone_info->columns*sizeof(*pixels);
1285 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1286 (unsigned char *) pixels);
1287 if ((MagickSizeType) count != length)
1288 break;
1289 }
cristybb503372010-05-27 20:51:26 +00001290 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001291 {
1292 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1293 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1294 cache_info->cache_filename);
1295 return(MagickFalse);
1296 }
1297 }
1298 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1299 return(MagickTrue);
1300}
1301
1302static MagickBooleanType CloneMemoryToMemoryPixelCache(CacheInfo *clone_info,
1303 CacheInfo *cache_info,ExceptionInfo *magick_unused(exception))
1304{
cristy3ed852e2009-09-05 21:47:34 +00001305 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001306 *restrict pixels,
1307 *restrict source_pixels;
cristy3ed852e2009-09-05 21:47:34 +00001308
cristye076a6e2010-08-15 19:59:43 +00001309 register ssize_t
1310 y;
cristy3ed852e2009-09-05 21:47:34 +00001311
cristybb503372010-05-27 20:51:26 +00001312 size_t
cristy3ed852e2009-09-05 21:47:34 +00001313 columns,
cristye076a6e2010-08-15 19:59:43 +00001314 length,
cristy3ed852e2009-09-05 21:47:34 +00001315 rows;
1316
1317 if (cache_info->debug != MagickFalse)
1318 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
cristybb503372010-05-27 20:51:26 +00001319 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1320 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001321 if ((clone_info->active_index_channel != MagickFalse) &&
1322 (cache_info->active_index_channel != MagickFalse))
1323 {
1324 register IndexPacket
1325 *indexes,
1326 *source_indexes;
1327
1328 /*
1329 Clone cache indexes.
1330 */
1331 length=columns*sizeof(*indexes);
1332 if (clone_info->columns == cache_info->columns)
1333 (void) CopyMagickMemory(clone_info->indexes,cache_info->indexes,
1334 length*rows);
1335 else
1336 {
1337 source_indexes=cache_info->indexes+cache_info->columns*rows;
1338 indexes=clone_info->indexes+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001339 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001340 {
1341 source_indexes-=cache_info->columns;
1342 indexes-=clone_info->columns;
1343 (void) CopyMagickMemory(indexes,source_indexes,length);
1344 }
1345 if (clone_info->columns > cache_info->columns)
1346 {
1347 length=(clone_info->columns-cache_info->columns)*
1348 sizeof(*indexes);
1349 indexes=clone_info->indexes+clone_info->columns*rows+
1350 cache_info->columns;
cristybb503372010-05-27 20:51:26 +00001351 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001352 {
1353 indexes-=clone_info->columns;
1354 (void) ResetMagickMemory(indexes,0,length);
1355 }
1356 }
1357 }
1358 }
1359 /*
1360 Clone cache pixels.
1361 */
1362 length=columns*sizeof(*pixels);
1363 if (clone_info->columns == cache_info->columns)
1364 (void) CopyMagickMemory(clone_info->pixels,cache_info->pixels,length*rows);
1365 else
1366 {
1367 source_pixels=cache_info->pixels+cache_info->columns*rows;
1368 pixels=clone_info->pixels+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001369 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001370 {
1371 source_pixels-=cache_info->columns;
1372 pixels-=clone_info->columns;
1373 (void) CopyMagickMemory(pixels,source_pixels,length);
1374 }
1375 if (clone_info->columns > cache_info->columns)
1376 {
1377 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1378 pixels=clone_info->pixels+clone_info->columns*rows+
1379 cache_info->columns;
cristybb503372010-05-27 20:51:26 +00001380 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001381 {
1382 pixels-=clone_info->columns;
1383 (void) ResetMagickMemory(pixels,0,length);
1384 }
1385 }
1386 }
1387 return(MagickTrue);
1388}
1389
1390static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1391 CacheInfo *cache_info,ExceptionInfo *exception)
1392{
1393 if ((clone_info->type != DiskCache) && (cache_info->type != DiskCache))
1394 return(CloneMemoryToMemoryPixelCache(clone_info,cache_info,exception));
1395 if ((clone_info->type == DiskCache) && (cache_info->type == DiskCache))
1396 return(CloneDiskToDiskPixelCache(clone_info,cache_info,exception));
1397 if (cache_info->type == DiskCache)
1398 return(CloneDiskToMemoryPixelCache(clone_info,cache_info,exception));
1399 return(CloneMemoryToDiskPixelCache(clone_info,cache_info,exception));
1400}
1401
1402/*
1403%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1404% %
1405% %
1406% %
1407+ C l o n e P i x e l C a c h e M e t h o d s %
1408% %
1409% %
1410% %
1411%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1412%
1413% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1414% another.
1415%
1416% The format of the ClonePixelCacheMethods() method is:
1417%
1418% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1419%
1420% A description of each parameter follows:
1421%
1422% o clone: Specifies a pointer to a Cache structure.
1423%
1424% o cache: the pixel cache.
1425%
1426*/
1427MagickExport void ClonePixelCacheMethods(Cache clone,const Cache cache)
1428{
1429 CacheInfo
1430 *cache_info,
1431 *source_info;
1432
1433 assert(clone != (Cache) NULL);
1434 source_info=(CacheInfo *) clone;
1435 assert(source_info->signature == MagickSignature);
1436 if (source_info->debug != MagickFalse)
1437 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1438 source_info->filename);
1439 assert(cache != (Cache) NULL);
1440 cache_info=(CacheInfo *) cache;
1441 assert(cache_info->signature == MagickSignature);
1442 source_info->methods=cache_info->methods;
1443}
1444
1445/*
1446%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1447% %
1448% %
1449% %
1450+ D e s t r o y I m a g e P i x e l C a c h e %
1451% %
1452% %
1453% %
1454%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1455%
1456% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1457%
1458% The format of the DestroyImagePixelCache() method is:
1459%
1460% void DestroyImagePixelCache(Image *image)
1461%
1462% A description of each parameter follows:
1463%
1464% o image: the image.
1465%
1466*/
1467static void DestroyImagePixelCache(Image *image)
1468{
1469 assert(image != (Image *) NULL);
1470 assert(image->signature == MagickSignature);
1471 if (image->debug != MagickFalse)
1472 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1473 if (image->cache == (void *) NULL)
1474 return;
1475 image->cache=DestroyPixelCache(image->cache);
1476}
1477
1478/*
1479%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1480% %
1481% %
1482% %
1483+ D e s t r o y I m a g e P i x e l s %
1484% %
1485% %
1486% %
1487%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1488%
1489% DestroyImagePixels() deallocates memory associated with the pixel cache.
1490%
1491% The format of the DestroyImagePixels() method is:
1492%
1493% void DestroyImagePixels(Image *image)
1494%
1495% A description of each parameter follows:
1496%
1497% o image: the image.
1498%
1499*/
1500MagickExport void DestroyImagePixels(Image *image)
1501{
1502 CacheInfo
1503 *cache_info;
1504
1505 assert(image != (const Image *) NULL);
1506 assert(image->signature == MagickSignature);
1507 if (image->debug != MagickFalse)
1508 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1509 assert(image->cache != (Cache) NULL);
1510 cache_info=(CacheInfo *) image->cache;
1511 assert(cache_info->signature == MagickSignature);
1512 if (cache_info->methods.destroy_pixel_handler == (DestroyPixelHandler) NULL)
1513 return;
1514 cache_info->methods.destroy_pixel_handler(image);
1515}
1516
1517/*
1518%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1519% %
1520% %
1521% %
1522+ D e s t r o y P i x e l C a c h e %
1523% %
1524% %
1525% %
1526%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1527%
1528% DestroyPixelCache() deallocates memory associated with the pixel cache.
1529%
1530% The format of the DestroyPixelCache() method is:
1531%
1532% Cache DestroyPixelCache(Cache cache)
1533%
1534% A description of each parameter follows:
1535%
1536% o cache: the pixel cache.
1537%
1538*/
1539
1540static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1541{
1542 switch (cache_info->type)
1543 {
1544 case MemoryCache:
1545 {
1546 if (cache_info->mapped == MagickFalse)
1547 cache_info->pixels=(PixelPacket *) RelinquishMagickMemory(
1548 cache_info->pixels);
1549 else
1550 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,
1551 (size_t) cache_info->length);
1552 RelinquishMagickResource(MemoryResource,cache_info->length);
1553 break;
1554 }
1555 case MapCache:
1556 {
1557 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,(size_t)
1558 cache_info->length);
1559 RelinquishMagickResource(MapResource,cache_info->length);
1560 }
1561 case DiskCache:
1562 {
1563 if (cache_info->file != -1)
1564 (void) ClosePixelCacheOnDisk(cache_info);
1565 RelinquishMagickResource(DiskResource,cache_info->length);
1566 break;
1567 }
1568 default:
1569 break;
1570 }
1571 cache_info->type=UndefinedCache;
1572 cache_info->mapped=MagickFalse;
1573 cache_info->indexes=(IndexPacket *) NULL;
1574}
1575
1576MagickExport Cache DestroyPixelCache(Cache cache)
1577{
1578 CacheInfo
1579 *cache_info;
1580
cristy3ed852e2009-09-05 21:47:34 +00001581 assert(cache != (Cache) NULL);
1582 cache_info=(CacheInfo *) cache;
1583 assert(cache_info->signature == MagickSignature);
1584 if (cache_info->debug != MagickFalse)
1585 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1586 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001587 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001588 cache_info->reference_count--;
1589 if (cache_info->reference_count != 0)
1590 {
cristyf84a1932010-01-03 18:00:18 +00001591 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001592 return((Cache) NULL);
1593 }
cristyf84a1932010-01-03 18:00:18 +00001594 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001595 if (cache_resources != (SplayTreeInfo *) NULL)
1596 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
cristy5b8de732009-09-10 23:50:40 +00001597 if (cache_info->debug != MagickFalse)
1598 {
1599 char
1600 message[MaxTextExtent];
1601
1602 (void) FormatMagickString(message,MaxTextExtent,"destroy %s",
1603 cache_info->filename);
1604 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1605 }
cristyc2e1bdd2009-09-10 23:43:34 +00001606 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1607 (cache_info->type != DiskCache)))
1608 RelinquishPixelCachePixels(cache_info);
1609 else
1610 {
1611 RelinquishPixelCachePixels(cache_info);
1612 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1613 }
cristy3ed852e2009-09-05 21:47:34 +00001614 *cache_info->cache_filename='\0';
1615 if (cache_info->nexus_info != (NexusInfo **) NULL)
1616 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1617 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001618 if (cache_info->random_info != (RandomInfo *) NULL)
1619 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001620 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1621 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1622 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1623 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001624 cache_info->signature=(~MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001625 cache_info=(CacheInfo *) RelinquishAlignedMemory(cache_info);
1626 cache=(Cache) NULL;
1627 return(cache);
1628}
1629
1630/*
1631%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1632% %
1633% %
1634% %
1635+ D e s t r o y P i x e l C a c h e N e x u s %
1636% %
1637% %
1638% %
1639%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1640%
1641% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1642%
1643% The format of the DestroyPixelCacheNexus() method is:
1644%
1645% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001646% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001647%
1648% A description of each parameter follows:
1649%
1650% o nexus_info: the nexus to destroy.
1651%
1652% o number_threads: the number of nexus threads.
1653%
1654*/
1655
1656static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1657{
1658 if (nexus_info->mapped == MagickFalse)
1659 (void) RelinquishMagickMemory(nexus_info->cache);
1660 else
1661 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1662 nexus_info->cache=(PixelPacket *) NULL;
1663 nexus_info->pixels=(PixelPacket *) NULL;
1664 nexus_info->indexes=(IndexPacket *) NULL;
1665 nexus_info->length=0;
1666 nexus_info->mapped=MagickFalse;
1667}
1668
1669MagickExport NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001670 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001671{
cristybb503372010-05-27 20:51:26 +00001672 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001673 i;
1674
1675 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001676 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001677 {
1678 if (nexus_info[i]->cache != (PixelPacket *) NULL)
1679 RelinquishCacheNexusPixels(nexus_info[i]);
1680 nexus_info[i]->signature=(~MagickSignature);
1681 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
1682 }
1683 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
1684 return(nexus_info);
1685}
1686
1687/*
1688%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1689% %
1690% %
1691% %
cristy3ed852e2009-09-05 21:47:34 +00001692+ 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 %
1693% %
1694% %
1695% %
1696%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1697%
1698% GetAuthenticIndexesFromCache() returns the indexes associated with the last
1699% call to QueueAuthenticPixelsCache() or GetAuthenticPixelsCache().
1700%
1701% The format of the GetAuthenticIndexesFromCache() method is:
1702%
1703% IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1704%
1705% A description of each parameter follows:
1706%
1707% o image: the image.
1708%
1709*/
1710static IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1711{
1712 CacheInfo
1713 *cache_info;
1714
1715 IndexPacket
1716 *indexes;
1717
cristy6ebe97c2010-07-03 01:17:28 +00001718 int
cristy3ed852e2009-09-05 21:47:34 +00001719 id;
1720
cristy3ed852e2009-09-05 21:47:34 +00001721 cache_info=(CacheInfo *) image->cache;
1722 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00001723 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001724 indexes=GetPixelCacheNexusIndexes(image->cache,cache_info->nexus_info[id]);
1725 return(indexes);
1726}
1727
1728/*
1729%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1730% %
1731% %
1732% %
1733% G e t A u t h e n t i c I n d e x Q u e u e %
1734% %
1735% %
1736% %
1737%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1738%
1739% GetAuthenticIndexQueue() returns the authentic black channel or the colormap
1740% indexes associated with the last call to QueueAuthenticPixels() or
1741% GetVirtualPixels(). NULL is returned if the black channel or colormap
1742% indexes are not available.
1743%
1744% The format of the GetAuthenticIndexQueue() method is:
1745%
1746% IndexPacket *GetAuthenticIndexQueue(const Image *image)
1747%
1748% A description of each parameter follows:
1749%
1750% o image: the image.
1751%
1752*/
1753MagickExport IndexPacket *GetAuthenticIndexQueue(const Image *image)
1754{
1755 CacheInfo
1756 *cache_info;
1757
1758 assert(image != (const Image *) NULL);
1759 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001760 assert(image->cache != (Cache) NULL);
1761 cache_info=(CacheInfo *) image->cache;
1762 assert(cache_info->signature == MagickSignature);
1763 if (cache_info->methods.get_authentic_indexes_from_handler ==
1764 (GetAuthenticIndexesFromHandler) NULL)
1765 return((IndexPacket *) NULL);
1766 return(cache_info->methods.get_authentic_indexes_from_handler(image));
1767}
1768
1769/*
1770%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1771% %
1772% %
1773% %
1774+ 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 %
1775% %
1776% %
1777% %
1778%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1779%
1780% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1781% disk pixel cache as defined by the geometry parameters. A pointer to the
1782% pixels is returned if the pixels are transferred, otherwise a NULL is
1783% returned.
1784%
1785% The format of the GetAuthenticPixelCacheNexus() method is:
1786%
cristybb503372010-05-27 20:51:26 +00001787% PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1788% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001789% NexusInfo *nexus_info,ExceptionInfo *exception)
1790%
1791% A description of each parameter follows:
1792%
1793% o image: the image.
1794%
1795% o x,y,columns,rows: These values define the perimeter of a region of
1796% pixels.
1797%
1798% o nexus_info: the cache nexus to return.
1799%
1800% o exception: return any errors or warnings in this structure.
1801%
1802*/
1803
1804static inline MagickBooleanType IsNexusInCore(const CacheInfo *cache_info,
1805 NexusInfo *nexus_info)
1806{
1807 MagickOffsetType
1808 offset;
1809
cristy73724512010-04-12 14:43:14 +00001810 if (cache_info->type == PingCache)
1811 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001812 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1813 nexus_info->region.x;
1814 if (nexus_info->pixels != (cache_info->pixels+offset))
1815 return(MagickFalse);
1816 return(MagickTrue);
1817}
1818
cristye076a6e2010-08-15 19:59:43 +00001819MagickExport PixelPacket *GetAuthenticPixelCacheNexus(Image *image,
1820 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001821 NexusInfo *nexus_info,ExceptionInfo *exception)
1822{
1823 CacheInfo
1824 *cache_info;
1825
1826 PixelPacket
1827 *pixels;
1828
1829 /*
1830 Transfer pixels from the cache.
1831 */
1832 assert(image != (Image *) NULL);
1833 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001834 pixels=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
1835 if (pixels == (PixelPacket *) NULL)
1836 return((PixelPacket *) NULL);
1837 cache_info=(CacheInfo *) image->cache;
1838 assert(cache_info->signature == MagickSignature);
1839 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
1840 return(pixels);
1841 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1842 return((PixelPacket *) NULL);
1843 if (cache_info->active_index_channel != MagickFalse)
1844 if (ReadPixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse)
1845 return((PixelPacket *) NULL);
1846 return(pixels);
1847}
1848
1849/*
1850%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1851% %
1852% %
1853% %
1854+ 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 %
1855% %
1856% %
1857% %
1858%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1859%
1860% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1861% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1862%
1863% The format of the GetAuthenticPixelsFromCache() method is:
1864%
1865% PixelPacket *GetAuthenticPixelsFromCache(const Image image)
1866%
1867% A description of each parameter follows:
1868%
1869% o image: the image.
1870%
1871*/
1872static PixelPacket *GetAuthenticPixelsFromCache(const Image *image)
1873{
1874 CacheInfo
1875 *cache_info;
1876
cristy6ebe97c2010-07-03 01:17:28 +00001877 int
cristy3ed852e2009-09-05 21:47:34 +00001878 id;
1879
1880 PixelPacket
1881 *pixels;
1882
cristy3ed852e2009-09-05 21:47:34 +00001883 cache_info=(CacheInfo *) image->cache;
1884 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00001885 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001886 pixels=GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]);
1887 return(pixels);
1888}
1889
1890/*
1891%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1892% %
1893% %
1894% %
1895% G e t A u t h e n t i c P i x e l Q u e u e %
1896% %
1897% %
1898% %
1899%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1900%
1901% GetAuthenticPixelQueue() returns the authentic pixels associated with the
1902% last call to QueueAuthenticPixels() or GetAuthenticPixels().
1903%
1904% The format of the GetAuthenticPixelQueue() method is:
1905%
1906% PixelPacket *GetAuthenticPixelQueue(const Image image)
1907%
1908% A description of each parameter follows:
1909%
1910% o image: the image.
1911%
1912*/
1913MagickExport PixelPacket *GetAuthenticPixelQueue(const Image *image)
1914{
1915 CacheInfo
1916 *cache_info;
1917
1918 assert(image != (const Image *) NULL);
1919 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001920 assert(image->cache != (Cache) NULL);
1921 cache_info=(CacheInfo *) image->cache;
1922 assert(cache_info->signature == MagickSignature);
1923 if (cache_info->methods.get_authentic_pixels_from_handler ==
1924 (GetAuthenticPixelsFromHandler) NULL)
1925 return((PixelPacket *) NULL);
1926 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1927}
1928
1929/*
1930%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1931% %
1932% %
1933% %
1934% G e t A u t h e n t i c P i x e l s %
1935% %
1936% %
1937% %
1938%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1939%
1940% GetAuthenticPixels() obtains a pixel region for read/write access. If the
1941% region is successfully accessed, a pointer to a PixelPacket array
1942% representing the region is returned, otherwise NULL is returned.
1943%
1944% The returned pointer may point to a temporary working copy of the pixels
1945% or it may point to the original pixels in memory. Performance is maximized
1946% if the selected region is part of one row, or one or more full rows, since
1947% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001948% if the image is in memory, or in a memory-mapped file. The returned pointer
1949% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001950%
1951% Pixels accessed via the returned pointer represent a simple array of type
1952% PixelPacket. If the image type is CMYK or if the storage class is
1953% PseduoClass, call GetAuthenticIndexQueue() after invoking
1954% GetAuthenticPixels() to obtain the black color component or colormap indexes
1955% (of type IndexPacket) corresponding to the region. Once the PixelPacket
1956% (and/or IndexPacket) array has been updated, the changes must be saved back
1957% to the underlying image using SyncAuthenticPixels() or they may be lost.
1958%
1959% The format of the GetAuthenticPixels() method is:
1960%
cristy5f959472010-05-27 22:19:46 +00001961% PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1962% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001963% ExceptionInfo *exception)
1964%
1965% A description of each parameter follows:
1966%
1967% o image: the image.
1968%
1969% o x,y,columns,rows: These values define the perimeter of a region of
1970% pixels.
1971%
1972% o exception: return any errors or warnings in this structure.
1973%
1974*/
cristybb503372010-05-27 20:51:26 +00001975MagickExport 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 CacheInfo
1980 *cache_info;
1981
1982 PixelPacket
1983 *pixels;
1984
1985 assert(image != (Image *) NULL);
1986 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001987 assert(image->cache != (Cache) NULL);
1988 cache_info=(CacheInfo *) image->cache;
1989 assert(cache_info->signature == MagickSignature);
1990 if (cache_info->methods.get_authentic_pixels_handler ==
1991 (GetAuthenticPixelsHandler) NULL)
1992 return((PixelPacket *) NULL);
1993 pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1994 rows,exception);
1995 return(pixels);
1996}
1997
1998/*
1999%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2000% %
2001% %
2002% %
2003+ G e t A u t h e n t i c P i x e l s C a c h e %
2004% %
2005% %
2006% %
2007%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2008%
2009% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
2010% as defined by the geometry parameters. A pointer to the pixels is returned
2011% if the pixels are transferred, otherwise a NULL is returned.
2012%
2013% The format of the GetAuthenticPixelsCache() method is:
2014%
cristybb503372010-05-27 20:51:26 +00002015% PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
2016% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00002017% ExceptionInfo *exception)
2018%
2019% A description of each parameter follows:
2020%
2021% o image: the image.
2022%
2023% o x,y,columns,rows: These values define the perimeter of a region of
2024% pixels.
2025%
2026% o exception: return any errors or warnings in this structure.
2027%
2028*/
cristybb503372010-05-27 20:51:26 +00002029static PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
2030 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00002031 ExceptionInfo *exception)
2032{
2033 CacheInfo
2034 *cache_info;
2035
cristy6ebe97c2010-07-03 01:17:28 +00002036 int
cristy3ed852e2009-09-05 21:47:34 +00002037 id;
2038
2039 PixelPacket
2040 *pixels;
2041
cristy77ff0282010-09-13 00:51:10 +00002042 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00002043 if (cache_info == (Cache) NULL)
2044 return((PixelPacket *) NULL);
2045 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00002046 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00002047 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
2048 cache_info->nexus_info[id],exception);
2049 return(pixels);
2050}
2051
2052/*
2053%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2054% %
2055% %
2056% %
2057+ G e t I m a g e E x t e n t %
2058% %
2059% %
2060% %
2061%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2062%
2063% GetImageExtent() returns the extent of the pixels associated with the
2064% last call to QueueAuthenticPixels() or GetAuthenticPixels().
2065%
2066% The format of the GetImageExtent() method is:
2067%
2068% MagickSizeType GetImageExtent(const Image *image)
2069%
2070% A description of each parameter follows:
2071%
2072% o image: the image.
2073%
2074*/
2075MagickExport MagickSizeType GetImageExtent(const Image *image)
2076{
2077 CacheInfo
2078 *cache_info;
2079
cristy6ebe97c2010-07-03 01:17:28 +00002080 int
cristy3ed852e2009-09-05 21:47:34 +00002081 id;
2082
2083 MagickSizeType
2084 extent;
2085
2086 assert(image != (Image *) NULL);
2087 assert(image->signature == MagickSignature);
2088 if (image->debug != MagickFalse)
2089 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2090 assert(image->cache != (Cache) NULL);
2091 cache_info=(CacheInfo *) image->cache;
2092 assert(cache_info->signature == MagickSignature);
2093 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00002094 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00002095 extent=GetPixelCacheNexusExtent(image->cache,cache_info->nexus_info[id]);
2096 return(extent);
2097}
2098
2099/*
2100%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2101% %
2102% %
2103% %
2104+ G e t I m a g e P i x e l C a c h e %
2105% %
2106% %
2107% %
2108%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2109%
2110% GetImagePixelCache() ensures that there is only a single reference to the
2111% pixel cache to be modified, updating the provided cache pointer to point to
2112% a clone of the original pixel cache if necessary.
2113%
2114% The format of the GetImagePixelCache method is:
2115%
2116% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2117% ExceptionInfo *exception)
2118%
2119% A description of each parameter follows:
2120%
2121% o image: the image.
2122%
2123% o clone: any value other than MagickFalse clones the cache pixels.
2124%
2125% o exception: return any errors or warnings in this structure.
2126%
2127*/
cristy3ed852e2009-09-05 21:47:34 +00002128static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
2129{
2130 CacheInfo
2131 *cache_info;
2132
2133 /*
2134 Does the image match the pixel cache morphology?
2135 */
2136 cache_info=(CacheInfo *) image->cache;
2137 if ((image->storage_class != cache_info->storage_class) ||
2138 (image->colorspace != cache_info->colorspace) ||
2139 (image->columns != cache_info->columns) ||
2140 (image->rows != cache_info->rows) ||
2141 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2142 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2143 return(MagickFalse);
2144 return(MagickTrue);
2145}
2146
cristy77ff0282010-09-13 00:51:10 +00002147static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2148 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002149{
2150 CacheInfo
2151 *cache_info;
2152
cristy3ed852e2009-09-05 21:47:34 +00002153 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00002154 destroy,
cristy3ed852e2009-09-05 21:47:34 +00002155 status;
2156
cristy50a10922010-02-15 18:35:25 +00002157 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00002158 cpu_throttle = 0,
2159 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00002160 time_limit = 0;
2161
cristy1ea34962010-07-01 19:49:21 +00002162 static time_t
cristya21afde2010-07-02 00:45:40 +00002163 cache_genesis = 0;
cristy1ea34962010-07-01 19:49:21 +00002164
cristyc4f9f132010-03-04 18:50:01 +00002165 status=MagickTrue;
2166 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00002167 if (cpu_throttle == 0)
2168 {
2169 char
2170 *limit;
2171
2172 /*
2173 Set CPU throttle in milleseconds.
2174 */
2175 cpu_throttle=MagickResourceInfinity;
2176 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2177 if (limit == (char *) NULL)
2178 limit=GetPolicyValue("throttle");
2179 if (limit != (char *) NULL)
2180 {
2181 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2182 limit=DestroyString(limit);
2183 }
2184 }
2185 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2186 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00002187 if (time_limit == 0)
2188 {
cristy6ebe97c2010-07-03 01:17:28 +00002189 /*
2190 Set the exire time in seconds.
2191 */
cristy1ea34962010-07-01 19:49:21 +00002192 time_limit=GetMagickResourceLimit(TimeResource);
cristya21afde2010-07-02 00:45:40 +00002193 cache_genesis=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00002194 }
2195 if ((time_limit != MagickResourceInfinity) &&
cristya21afde2010-07-02 00:45:40 +00002196 ((MagickSizeType) (time((time_t *) NULL)-cache_genesis) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00002197 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00002198 assert(image->cache != (Cache) NULL);
2199 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002200 destroy=MagickFalse;
cristy01b7eb02009-09-10 23:10:14 +00002201 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002202 {
cristyaaa0cb62010-02-15 17:47:27 +00002203 LockSemaphoreInfo(cache_info->semaphore);
2204 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002205 {
cristyaaa0cb62010-02-15 17:47:27 +00002206 Image
2207 clone_image;
2208
2209 CacheInfo
2210 *clone_info;
2211
2212 /*
2213 Clone pixel cache.
2214 */
2215 clone_image=(*image);
cristy93505cf2010-08-10 21:37:49 +00002216 clone_image.semaphore=AllocateSemaphoreInfo();
2217 clone_image.reference_count=1;
cristyaaa0cb62010-02-15 17:47:27 +00002218 clone_image.cache=ClonePixelCache(cache_info);
2219 clone_info=(CacheInfo *) clone_image.cache;
2220 status=ClonePixelCacheNexus(cache_info,clone_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002221 if (status != MagickFalse)
2222 {
cristyaaa0cb62010-02-15 17:47:27 +00002223 status=OpenPixelCache(&clone_image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00002224 if (status != MagickFalse)
2225 {
cristyaaa0cb62010-02-15 17:47:27 +00002226 if (clone != MagickFalse)
2227 status=ClonePixelCachePixels(clone_info,cache_info,
2228 exception);
2229 if (status != MagickFalse)
2230 {
2231 destroy=MagickTrue;
2232 image->cache=clone_image.cache;
2233 }
cristy3ed852e2009-09-05 21:47:34 +00002234 }
2235 }
cristy93505cf2010-08-10 21:37:49 +00002236 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002237 }
cristyaaa0cb62010-02-15 17:47:27 +00002238 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002239 }
cristy4320e0e2009-09-10 15:00:08 +00002240 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002241 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002242 if (status != MagickFalse)
2243 {
2244 /*
2245 Ensure the image matches the pixel cache morphology.
2246 */
2247 image->taint=MagickTrue;
2248 image->type=UndefinedType;
cristydd438462010-05-06 13:44:04 +00002249 if (image->colorspace == GRAYColorspace)
2250 image->colorspace=RGBColorspace;
cristy3ed852e2009-09-05 21:47:34 +00002251 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2252 status=OpenPixelCache(image,IOMode,exception);
2253 }
cristyf84a1932010-01-03 18:00:18 +00002254 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002255 if (status == MagickFalse)
2256 return((Cache) NULL);
2257 return(image->cache);
2258}
2259
2260/*
2261%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2262% %
2263% %
2264% %
2265% G e t O n e A u t h e n t i c P i x e l %
2266% %
2267% %
2268% %
2269%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2270%
2271% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2272% location. The image background color is returned if an error occurs.
2273%
2274% The format of the GetOneAuthenticPixel() method is:
2275%
cristybb503372010-05-27 20:51:26 +00002276% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2277% const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002278%
2279% A description of each parameter follows:
2280%
2281% o image: the image.
2282%
2283% o x,y: These values define the location of the pixel to return.
2284%
2285% o pixel: return a pixel at the specified (x,y) location.
2286%
2287% o exception: return any errors or warnings in this structure.
2288%
2289*/
cristyacbbb7c2010-06-30 18:56:48 +00002290MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2291 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002292{
2293 CacheInfo
2294 *cache_info;
2295
2296 GetOneAuthenticPixelFromHandler
2297 get_one_authentic_pixel_from_handler;
2298
2299 MagickBooleanType
2300 status;
2301
2302 assert(image != (Image *) NULL);
2303 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002304 assert(image->cache != (Cache) NULL);
2305 cache_info=(CacheInfo *) image->cache;
2306 assert(cache_info->signature == MagickSignature);
2307 *pixel=image->background_color;
2308 get_one_authentic_pixel_from_handler=
2309 cache_info->methods.get_one_authentic_pixel_from_handler;
2310 if (get_one_authentic_pixel_from_handler ==
2311 (GetOneAuthenticPixelFromHandler) NULL)
2312 return(MagickFalse);
2313 status=cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2314 pixel,exception);
2315 return(status);
2316}
2317
2318/*
2319%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2320% %
2321% %
2322% %
2323+ 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 %
2324% %
2325% %
2326% %
2327%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2328%
2329% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2330% location. The image background color is returned if an error occurs.
2331%
2332% The format of the GetOneAuthenticPixelFromCache() method is:
2333%
2334% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy5f959472010-05-27 22:19:46 +00002335% const ssize_t x,const ssize_t y,PixelPacket *pixel,
2336% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002337%
2338% A description of each parameter follows:
2339%
2340% o image: the image.
2341%
2342% o x,y: These values define the location of the pixel to return.
2343%
2344% o pixel: return a pixel at the specified (x,y) location.
2345%
2346% o exception: return any errors or warnings in this structure.
2347%
2348*/
2349static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristybb503372010-05-27 20:51:26 +00002350 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002351{
2352 PixelPacket
2353 *pixels;
2354
cristy3ed852e2009-09-05 21:47:34 +00002355 *pixel=image->background_color;
2356 pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2357 if (pixels == (PixelPacket *) NULL)
2358 return(MagickFalse);
2359 *pixel=(*pixels);
2360 return(MagickTrue);
2361}
2362
2363/*
2364%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2365% %
2366% %
2367% %
2368% G e t O n e V i r t u a l M a g i c k P i x e l %
2369% %
2370% %
2371% %
2372%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2373%
2374% GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2375% location. The image background color is returned if an error occurs. If
2376% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2377%
2378% The format of the GetOneVirtualMagickPixel() method is:
2379%
2380% MagickBooleanType GetOneVirtualMagickPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002381% const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
cristy3ed852e2009-09-05 21:47:34 +00002382% ExceptionInfo exception)
2383%
2384% A description of each parameter follows:
2385%
2386% o image: the image.
2387%
2388% o x,y: these values define the location of the pixel to return.
2389%
2390% o pixel: return a pixel at the specified (x,y) location.
2391%
2392% o exception: return any errors or warnings in this structure.
2393%
2394*/
2395MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
cristyacbbb7c2010-06-30 18:56:48 +00002396 const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
2397 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002398{
2399 CacheInfo
2400 *cache_info;
2401
2402 register const IndexPacket
2403 *indexes;
2404
2405 register const PixelPacket
2406 *p;
2407
2408 assert(image != (const Image *) NULL);
2409 assert(image->signature == MagickSignature);
2410 assert(image->cache != (Cache) NULL);
2411 cache_info=(CacheInfo *) image->cache;
2412 assert(cache_info->signature == MagickSignature);
2413 GetMagickPixelPacket(image,pixel);
2414 p=GetVirtualPixelCache(image,GetPixelCacheVirtualMethod(image),x,y,1,1,
2415 exception);
2416 if (p == (const PixelPacket *) NULL)
2417 return(MagickFalse);
2418 indexes=GetVirtualIndexQueue(image);
2419 SetMagickPixelPacket(image,p,indexes,pixel);
2420 return(MagickTrue);
2421}
2422
2423/*
2424%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2425% %
2426% %
2427% %
2428% G e t O n e V i r t u a l M e t h o d P i x e l %
2429% %
2430% %
2431% %
2432%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2433%
2434% GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2435% location as defined by specified pixel method. The image background color
2436% is returned if an error occurs. If you plan to modify the pixel, use
2437% GetOneAuthenticPixel() instead.
2438%
2439% The format of the GetOneVirtualMethodPixel() method is:
2440%
2441% MagickBooleanType GetOneVirtualMethodPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002442% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2443% const ssize_t y,Pixelpacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002444%
2445% A description of each parameter follows:
2446%
2447% o image: the image.
2448%
2449% o virtual_pixel_method: the virtual pixel method.
2450%
2451% o x,y: These values define the location of the pixel to return.
2452%
2453% o pixel: return a pixel at the specified (x,y) location.
2454%
2455% o exception: return any errors or warnings in this structure.
2456%
2457*/
2458MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002459 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002460 PixelPacket *pixel,ExceptionInfo *exception)
2461{
2462 GetOneVirtualPixelFromHandler
2463 get_one_virtual_pixel_from_handler;
2464
2465 CacheInfo
2466 *cache_info;
2467
2468 MagickBooleanType
2469 status;
2470
2471 assert(image != (const Image *) NULL);
2472 assert(image->signature == MagickSignature);
2473 assert(image->cache != (Cache) NULL);
2474 cache_info=(CacheInfo *) image->cache;
2475 assert(cache_info->signature == MagickSignature);
2476 *pixel=image->background_color;
2477 get_one_virtual_pixel_from_handler=
2478 cache_info->methods.get_one_virtual_pixel_from_handler;
2479 if (get_one_virtual_pixel_from_handler ==
2480 (GetOneVirtualPixelFromHandler) NULL)
2481 return(MagickFalse);
2482 status=get_one_virtual_pixel_from_handler(image,virtual_pixel_method,x,y,
2483 pixel,exception);
2484 return(status);
2485}
2486
2487/*
2488%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2489% %
2490% %
2491% %
2492% G e t O n e V i r t u a l P i x e l %
2493% %
2494% %
2495% %
2496%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2497%
2498% GetOneVirtualPixel() returns a single virtual pixel at the specified
2499% (x,y) location. The image background color is returned if an error occurs.
2500% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2501%
2502% The format of the GetOneVirtualPixel() method is:
2503%
cristybb503372010-05-27 20:51:26 +00002504% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2505% const ssize_t y,PixelPacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002506%
2507% A description of each parameter follows:
2508%
2509% o image: the image.
2510%
2511% o x,y: These values define the location of the pixel to return.
2512%
2513% o pixel: return a pixel at the specified (x,y) location.
2514%
2515% o exception: return any errors or warnings in this structure.
2516%
2517*/
2518MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002519 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002520{
2521 GetOneVirtualPixelFromHandler
2522 get_one_virtual_pixel_from_handler;
2523
2524 CacheInfo
2525 *cache_info;
2526
2527 MagickBooleanType
2528 status;
2529
2530 assert(image != (const Image *) NULL);
2531 assert(image->signature == MagickSignature);
2532 assert(image->cache != (Cache) NULL);
2533 cache_info=(CacheInfo *) image->cache;
2534 assert(cache_info->signature == MagickSignature);
2535 *pixel=image->background_color;
2536 get_one_virtual_pixel_from_handler=
2537 cache_info->methods.get_one_virtual_pixel_from_handler;
2538 if (get_one_virtual_pixel_from_handler ==
2539 (GetOneVirtualPixelFromHandler) NULL)
2540 return(MagickFalse);
2541 status=get_one_virtual_pixel_from_handler(image,GetPixelCacheVirtualMethod(
2542 image),x,y,pixel,exception);
2543 return(status);
2544}
2545
2546/*
2547%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2548% %
2549% %
2550% %
2551+ 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 %
2552% %
2553% %
2554% %
2555%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2556%
2557% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2558% specified (x,y) location. The image background color is returned if an
2559% error occurs.
2560%
2561% The format of the GetOneVirtualPixelFromCache() method is:
2562%
2563% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristybb503372010-05-27 20:51:26 +00002564% const VirtualPixelPacket method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002565% PixelPacket *pixel,ExceptionInfo *exception)
2566%
2567% A description of each parameter follows:
2568%
2569% o image: the image.
2570%
2571% o virtual_pixel_method: the virtual pixel method.
2572%
2573% o x,y: These values define the location of the pixel to return.
2574%
2575% o pixel: return a pixel at the specified (x,y) location.
2576%
2577% o exception: return any errors or warnings in this structure.
2578%
2579*/
2580static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002581 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002582 PixelPacket *pixel,ExceptionInfo *exception)
2583{
2584 const PixelPacket
2585 *pixels;
2586
2587 *pixel=image->background_color;
2588 pixels=GetVirtualPixelCache(image,virtual_pixel_method,x,y,1UL,1UL,exception);
2589 if (pixels == (const PixelPacket *) NULL)
2590 return(MagickFalse);
2591 *pixel=(*pixels);
2592 return(MagickTrue);
2593}
2594
2595/*
2596%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2597% %
2598% %
2599% %
2600+ G e t P i x e l C a c h e C o l o r s p a c e %
2601% %
2602% %
2603% %
2604%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2605%
2606% GetPixelCacheColorspace() returns the class type of the pixel cache.
2607%
2608% The format of the GetPixelCacheColorspace() method is:
2609%
2610% Colorspace GetPixelCacheColorspace(Cache cache)
2611%
2612% A description of each parameter follows:
2613%
2614% o cache: the pixel cache.
2615%
2616*/
2617MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
2618{
2619 CacheInfo
2620 *cache_info;
2621
2622 assert(cache != (Cache) NULL);
2623 cache_info=(CacheInfo *) cache;
2624 assert(cache_info->signature == MagickSignature);
2625 if (cache_info->debug != MagickFalse)
2626 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2627 cache_info->filename);
2628 return(cache_info->colorspace);
2629}
2630
2631/*
2632%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2633% %
2634% %
2635% %
2636+ G e t P i x e l C a c h e M e t h o d s %
2637% %
2638% %
2639% %
2640%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2641%
2642% GetPixelCacheMethods() initializes the CacheMethods structure.
2643%
2644% The format of the GetPixelCacheMethods() method is:
2645%
2646% void GetPixelCacheMethods(CacheMethods *cache_methods)
2647%
2648% A description of each parameter follows:
2649%
2650% o cache_methods: Specifies a pointer to a CacheMethods structure.
2651%
2652*/
2653MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
2654{
2655 assert(cache_methods != (CacheMethods *) NULL);
2656 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2657 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2658 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2659 cache_methods->get_virtual_indexes_from_handler=GetVirtualIndexesFromCache;
2660 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2661 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2662 cache_methods->get_authentic_indexes_from_handler=
2663 GetAuthenticIndexesFromCache;
2664 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2665 cache_methods->get_one_authentic_pixel_from_handler=
2666 GetOneAuthenticPixelFromCache;
2667 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2668 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2669 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2670}
2671
2672/*
2673%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2674% %
2675% %
2676% %
2677+ G e t P i x e l C a c h e N e x u s E x t e n t %
2678% %
2679% %
2680% %
2681%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2682%
2683% GetPixelCacheNexusExtent() returns the extent of the pixels associated with
2684% the last call to SetPixelCacheNexusPixels() or GetPixelCacheNexusPixels().
2685%
2686% The format of the GetPixelCacheNexusExtent() method is:
2687%
2688% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2689% NexusInfo *nexus_info)
2690%
2691% A description of each parameter follows:
2692%
2693% o nexus_info: the nexus info.
2694%
2695*/
2696MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2697 NexusInfo *nexus_info)
2698{
2699 CacheInfo
2700 *cache_info;
2701
2702 MagickSizeType
2703 extent;
2704
2705 if (cache == (Cache) NULL)
2706 return(0);
2707 cache_info=(CacheInfo *) cache;
2708 assert(cache_info->signature == MagickSignature);
2709 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2710 if (extent == 0)
2711 return((MagickSizeType) cache_info->columns*cache_info->rows);
2712 return(extent);
2713}
2714
2715/*
2716%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2717% %
2718% %
2719% %
2720+ 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 %
2721% %
2722% %
2723% %
2724%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2725%
2726% GetPixelCacheNexusIndexes() returns the indexes associated with the
2727% specified cache nexus.
2728%
2729% The format of the GetPixelCacheNexusIndexes() method is:
2730%
2731% IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2732% NexusInfo *nexus_info)
2733%
2734% A description of each parameter follows:
2735%
2736% o cache: the pixel cache.
2737%
2738% o nexus_info: the cache nexus to return the colormap indexes.
2739%
2740*/
2741MagickExport IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2742 NexusInfo *nexus_info)
2743{
2744 CacheInfo
2745 *cache_info;
2746
2747 if (cache == (Cache) NULL)
2748 return((IndexPacket *) NULL);
2749 cache_info=(CacheInfo *) cache;
2750 assert(cache_info->signature == MagickSignature);
2751 if (cache_info->storage_class == UndefinedClass)
2752 return((IndexPacket *) NULL);
2753 return(nexus_info->indexes);
2754}
2755
2756/*
2757%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2758% %
2759% %
2760% %
2761+ G e t P i x e l C a c h e N e x u s P i x e l s %
2762% %
2763% %
2764% %
2765%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2766%
2767% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2768% cache nexus.
2769%
2770% The format of the GetPixelCacheNexusPixels() method is:
2771%
2772% PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2773% NexusInfo *nexus_info)
2774%
2775% A description of each parameter follows:
2776%
2777% o cache: the pixel cache.
2778%
2779% o nexus_info: the cache nexus to return the pixels.
2780%
2781*/
2782MagickExport PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2783 NexusInfo *nexus_info)
2784{
2785 CacheInfo
2786 *cache_info;
2787
2788 if (cache == (Cache) NULL)
2789 return((PixelPacket *) NULL);
2790 cache_info=(CacheInfo *) cache;
2791 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002792 if (cache_info->storage_class == UndefinedClass)
2793 return((PixelPacket *) NULL);
2794 return(nexus_info->pixels);
2795}
2796
2797/*
2798%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2799% %
2800% %
2801% %
cristy056ba772010-01-02 23:33:54 +00002802+ G e t P i x e l C a c h e P i x e l s %
2803% %
2804% %
2805% %
2806%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2807%
2808% GetPixelCachePixels() returns the pixels associated with the specified image.
2809%
2810% The format of the GetPixelCachePixels() method is:
2811%
cristyf84a1932010-01-03 18:00:18 +00002812% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2813% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002814%
2815% A description of each parameter follows:
2816%
2817% o image: the image.
2818%
2819% o length: the pixel cache length.
2820%
cristyf84a1932010-01-03 18:00:18 +00002821% o exception: return any errors or warnings in this structure.
2822%
cristy056ba772010-01-02 23:33:54 +00002823*/
cristyf84a1932010-01-03 18:00:18 +00002824MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2825 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002826{
2827 CacheInfo
2828 *cache_info;
2829
2830 assert(image != (const Image *) NULL);
2831 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002832 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00002833 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002834 assert(cache_info->signature == MagickSignature);
2835 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002836 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002837 return((void *) NULL);
2838 *length=cache_info->length;
2839 return((void *) cache_info->pixels);
2840}
2841
2842/*
2843%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2844% %
2845% %
2846% %
cristyb32b90a2009-09-07 21:45:48 +00002847+ 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 +00002848% %
2849% %
2850% %
2851%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2852%
2853% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2854%
2855% The format of the GetPixelCacheStorageClass() method is:
2856%
2857% ClassType GetPixelCacheStorageClass(Cache cache)
2858%
2859% A description of each parameter follows:
2860%
2861% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2862%
2863% o cache: the pixel cache.
2864%
2865*/
2866MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
2867{
2868 CacheInfo
2869 *cache_info;
2870
2871 assert(cache != (Cache) NULL);
2872 cache_info=(CacheInfo *) cache;
2873 assert(cache_info->signature == MagickSignature);
2874 if (cache_info->debug != MagickFalse)
2875 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2876 cache_info->filename);
2877 return(cache_info->storage_class);
2878}
2879
2880/*
2881%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2882% %
2883% %
2884% %
cristyb32b90a2009-09-07 21:45:48 +00002885+ G e t P i x e l C a c h e T i l e S i z e %
2886% %
2887% %
2888% %
2889%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2890%
2891% GetPixelCacheTileSize() returns the pixel cache tile size.
2892%
2893% The format of the GetPixelCacheTileSize() method is:
2894%
cristybb503372010-05-27 20:51:26 +00002895% void GetPixelCacheTileSize(const Image *image,size_t *width,
2896% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002897%
2898% A description of each parameter follows:
2899%
2900% o image: the image.
2901%
2902% o width: the optimize cache tile width in pixels.
2903%
2904% o height: the optimize cache tile height in pixels.
2905%
2906*/
cristybb503372010-05-27 20:51:26 +00002907MagickExport void GetPixelCacheTileSize(const Image *image,size_t *width,
2908 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002909{
2910 CacheInfo
2911 *cache_info;
2912
2913 assert(image != (Image *) NULL);
2914 assert(image->signature == MagickSignature);
2915 if (image->debug != MagickFalse)
2916 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2917 assert(image->cache != (Cache) NULL);
2918 cache_info=(CacheInfo *) image->cache;
2919 assert(cache_info->signature == MagickSignature);
2920 *width=2048UL/sizeof(PixelPacket);
2921 if (GetPixelCacheType(image) == DiskCache)
cristydaa97692009-09-13 02:10:35 +00002922 *width=8192UL/sizeof(PixelPacket);
cristyb32b90a2009-09-07 21:45:48 +00002923 *height=(*width);
2924}
2925
2926/*
2927%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2928% %
2929% %
2930% %
2931+ G e t P i x e l C a c h e T y p e %
2932% %
2933% %
2934% %
2935%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2936%
2937% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2938%
2939% The format of the GetPixelCacheType() method is:
2940%
2941% CacheType GetPixelCacheType(const Image *image)
2942%
2943% A description of each parameter follows:
2944%
2945% o image: the image.
2946%
2947*/
2948MagickExport CacheType GetPixelCacheType(const Image *image)
2949{
2950 CacheInfo
2951 *cache_info;
2952
2953 assert(image != (Image *) NULL);
2954 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002955 assert(image->cache != (Cache) NULL);
2956 cache_info=(CacheInfo *) image->cache;
2957 assert(cache_info->signature == MagickSignature);
2958 return(cache_info->type);
2959}
2960
2961/*
2962%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2963% %
2964% %
2965% %
cristy3ed852e2009-09-05 21:47:34 +00002966+ 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 %
2967% %
2968% %
2969% %
2970%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2971%
2972% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2973% pixel cache. A virtual pixel is any pixel access that is outside the
2974% boundaries of the image cache.
2975%
2976% The format of the GetPixelCacheVirtualMethod() method is:
2977%
2978% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2979%
2980% A description of each parameter follows:
2981%
2982% o image: the image.
2983%
2984*/
2985MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2986{
2987 CacheInfo
2988 *cache_info;
2989
2990 assert(image != (Image *) NULL);
2991 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002992 assert(image->cache != (Cache) NULL);
2993 cache_info=(CacheInfo *) image->cache;
2994 assert(cache_info->signature == MagickSignature);
2995 return(cache_info->virtual_pixel_method);
2996}
2997
2998/*
2999%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3000% %
3001% %
3002% %
3003+ 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 %
3004% %
3005% %
3006% %
3007%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3008%
3009% GetVirtualIndexesFromCache() returns the indexes associated with the last
3010% call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3011%
3012% The format of the GetVirtualIndexesFromCache() method is:
3013%
3014% IndexPacket *GetVirtualIndexesFromCache(const Image *image)
3015%
3016% A description of each parameter follows:
3017%
3018% o image: the image.
3019%
3020*/
3021static const IndexPacket *GetVirtualIndexesFromCache(const Image *image)
3022{
3023 CacheInfo
3024 *cache_info;
3025
3026 const IndexPacket
3027 *indexes;
3028
cristy6ebe97c2010-07-03 01:17:28 +00003029 int
cristy3ed852e2009-09-05 21:47:34 +00003030 id;
3031
cristy3ed852e2009-09-05 21:47:34 +00003032 cache_info=(CacheInfo *) image->cache;
3033 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00003034 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00003035 indexes=GetVirtualIndexesFromNexus(image->cache,cache_info->nexus_info[id]);
3036 return(indexes);
3037}
3038
3039/*
3040%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3041% %
3042% %
3043% %
3044+ 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 %
3045% %
3046% %
3047% %
3048%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3049%
3050% GetVirtualIndexesFromNexus() returns the indexes associated with the
3051% specified cache nexus.
3052%
3053% The format of the GetVirtualIndexesFromNexus() method is:
3054%
3055% const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
3056% NexusInfo *nexus_info)
3057%
3058% A description of each parameter follows:
3059%
3060% o cache: the pixel cache.
3061%
3062% o nexus_info: the cache nexus to return the colormap indexes.
3063%
3064*/
3065MagickExport const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
3066 NexusInfo *nexus_info)
3067{
3068 CacheInfo
3069 *cache_info;
3070
3071 if (cache == (Cache) NULL)
3072 return((IndexPacket *) NULL);
3073 cache_info=(CacheInfo *) cache;
3074 assert(cache_info->signature == MagickSignature);
3075 if (cache_info->storage_class == UndefinedClass)
3076 return((IndexPacket *) NULL);
3077 return(nexus_info->indexes);
3078}
3079
3080/*
3081%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3082% %
3083% %
3084% %
3085% G e t V i r t u a l I n d e x Q u e u e %
3086% %
3087% %
3088% %
3089%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3090%
3091% GetVirtualIndexQueue() returns the virtual black channel or the
3092% colormap indexes associated with the last call to QueueAuthenticPixels() or
3093% GetVirtualPixels(). NULL is returned if the black channel or colormap
3094% indexes are not available.
3095%
3096% The format of the GetVirtualIndexQueue() method is:
3097%
3098% const IndexPacket *GetVirtualIndexQueue(const Image *image)
3099%
3100% A description of each parameter follows:
3101%
3102% o image: the image.
3103%
3104*/
3105MagickExport const IndexPacket *GetVirtualIndexQueue(const Image *image)
3106{
3107 CacheInfo
3108 *cache_info;
3109
3110 assert(image != (const Image *) NULL);
3111 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003112 assert(image->cache != (Cache) NULL);
3113 cache_info=(CacheInfo *) image->cache;
3114 assert(cache_info->signature == MagickSignature);
3115 if (cache_info->methods.get_virtual_indexes_from_handler ==
3116 (GetVirtualIndexesFromHandler) NULL)
3117 return((IndexPacket *) NULL);
3118 return(cache_info->methods.get_virtual_indexes_from_handler(image));
3119}
3120
3121/*
3122%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3123% %
3124% %
3125% %
3126+ 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 %
3127% %
3128% %
3129% %
3130%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3131%
3132% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3133% pixel cache as defined by the geometry parameters. A pointer to the pixels
3134% is returned if the pixels are transferred, otherwise a NULL is returned.
3135%
3136% The format of the GetVirtualPixelsFromNexus() method is:
3137%
3138% PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003139% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00003140% const size_t columns,const size_t rows,NexusInfo *nexus_info,
3141% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003142%
3143% A description of each parameter follows:
3144%
3145% o image: the image.
3146%
3147% o virtual_pixel_method: the virtual pixel method.
3148%
3149% o x,y,columns,rows: These values define the perimeter of a region of
3150% pixels.
3151%
3152% o nexus_info: the cache nexus to acquire.
3153%
3154% o exception: return any errors or warnings in this structure.
3155%
3156*/
3157
cristybb503372010-05-27 20:51:26 +00003158static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003159 DitherMatrix[64] =
3160 {
3161 0, 48, 12, 60, 3, 51, 15, 63,
3162 32, 16, 44, 28, 35, 19, 47, 31,
3163 8, 56, 4, 52, 11, 59, 7, 55,
3164 40, 24, 36, 20, 43, 27, 39, 23,
3165 2, 50, 14, 62, 1, 49, 13, 61,
3166 34, 18, 46, 30, 33, 17, 45, 29,
3167 10, 58, 6, 54, 9, 57, 5, 53,
3168 42, 26, 38, 22, 41, 25, 37, 21
3169 };
3170
cristybb503372010-05-27 20:51:26 +00003171static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003172{
cristybb503372010-05-27 20:51:26 +00003173 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003174 index;
3175
3176 index=x+DitherMatrix[x & 0x07]-32L;
3177 if (index < 0L)
3178 return(0L);
cristybb503372010-05-27 20:51:26 +00003179 if (index >= (ssize_t) columns)
3180 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00003181 return(index);
3182}
3183
cristybb503372010-05-27 20:51:26 +00003184static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003185{
cristybb503372010-05-27 20:51:26 +00003186 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003187 index;
3188
3189 index=y+DitherMatrix[y & 0x07]-32L;
3190 if (index < 0L)
3191 return(0L);
cristybb503372010-05-27 20:51:26 +00003192 if (index >= (ssize_t) rows)
3193 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00003194 return(index);
3195}
3196
cristybb503372010-05-27 20:51:26 +00003197static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003198{
3199 if (x < 0L)
3200 return(0L);
cristybb503372010-05-27 20:51:26 +00003201 if (x >= (ssize_t) columns)
3202 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003203 return(x);
3204}
3205
cristybb503372010-05-27 20:51:26 +00003206static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003207{
3208 if (y < 0L)
3209 return(0L);
cristybb503372010-05-27 20:51:26 +00003210 if (y >= (ssize_t) rows)
3211 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003212 return(y);
3213}
3214
cristybb503372010-05-27 20:51:26 +00003215static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003216{
cristybb503372010-05-27 20:51:26 +00003217 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003218}
3219
cristybb503372010-05-27 20:51:26 +00003220static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003221{
cristybb503372010-05-27 20:51:26 +00003222 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003223}
3224
3225/*
3226 VirtualPixelModulo() computes the remainder of dividing offset by extent. It
3227 returns not only the quotient (tile the offset falls in) but also the positive
3228 remainer within that tile such that 0 <= remainder < extent. This method is
3229 essentially a ldiv() using a floored modulo division rather than the normal
3230 default truncated modulo division.
3231*/
cristybb503372010-05-27 20:51:26 +00003232static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3233 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003234{
3235 MagickModulo
3236 modulo;
3237
cristybb503372010-05-27 20:51:26 +00003238 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003239 if (offset < 0L)
3240 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003241 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003242 return(modulo);
3243}
3244
3245MagickExport const PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003246 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3247 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003248 ExceptionInfo *exception)
3249{
3250 CacheInfo
3251 *cache_info;
3252
cristyc3ec0d42010-04-07 01:18:08 +00003253 IndexPacket
3254 virtual_index;
3255
cristy3ed852e2009-09-05 21:47:34 +00003256 MagickOffsetType
3257 offset;
3258
3259 MagickSizeType
3260 length,
3261 number_pixels;
3262
3263 NexusInfo
3264 **virtual_nexus;
3265
3266 PixelPacket
3267 *pixels,
3268 virtual_pixel;
3269
3270 RectangleInfo
3271 region;
3272
3273 register const IndexPacket
cristyc3ec0d42010-04-07 01:18:08 +00003274 *restrict virtual_indexes;
cristy3ed852e2009-09-05 21:47:34 +00003275
3276 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003277 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003278
3279 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003280 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003281
cristye076a6e2010-08-15 19:59:43 +00003282 register PixelPacket
3283 *restrict q;
3284
cristybb503372010-05-27 20:51:26 +00003285 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003286 u,
3287 v;
3288
cristy3ed852e2009-09-05 21:47:34 +00003289 /*
3290 Acquire pixels.
3291 */
cristy3ed852e2009-09-05 21:47:34 +00003292 cache_info=(CacheInfo *) image->cache;
cristy4cfbb3f2010-03-14 20:40:23 +00003293 if (cache_info->type == UndefinedCache)
cristy3ed852e2009-09-05 21:47:34 +00003294 return((const PixelPacket *) NULL);
3295 region.x=x;
3296 region.y=y;
3297 region.width=columns;
3298 region.height=rows;
3299 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
3300 if (pixels == (PixelPacket *) NULL)
3301 return((const PixelPacket *) NULL);
cristydf415c82010-03-11 16:47:50 +00003302 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3303 nexus_info->region.x;
3304 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3305 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003306 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3307 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003308 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3309 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003310 {
3311 MagickBooleanType
3312 status;
3313
3314 /*
3315 Pixel request is inside cache extents.
3316 */
3317 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
3318 return(pixels);
3319 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3320 if (status == MagickFalse)
3321 return((const PixelPacket *) NULL);
3322 if ((cache_info->storage_class == PseudoClass) ||
3323 (cache_info->colorspace == CMYKColorspace))
3324 {
3325 status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
3326 if (status == MagickFalse)
3327 return((const PixelPacket *) NULL);
3328 }
3329 return(pixels);
3330 }
3331 /*
3332 Pixel request is outside cache extents.
3333 */
3334 q=pixels;
3335 indexes=GetPixelCacheNexusIndexes(cache_info,nexus_info);
3336 virtual_nexus=AcquirePixelCacheNexus(1);
3337 if (virtual_nexus == (NexusInfo **) NULL)
3338 {
3339 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3340 "UnableToGetCacheNexus","`%s'",image->filename);
3341 return((const PixelPacket *) NULL);
3342 }
3343 switch (virtual_pixel_method)
3344 {
3345 case BlackVirtualPixelMethod:
3346 {
cristy4789f0d2010-01-10 00:01:06 +00003347 SetRedPixelComponent(&virtual_pixel,0);
3348 SetGreenPixelComponent(&virtual_pixel,0);
3349 SetBluePixelComponent(&virtual_pixel,0);
3350 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003351 break;
3352 }
3353 case GrayVirtualPixelMethod:
3354 {
cristy4789f0d2010-01-10 00:01:06 +00003355 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3356 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3357 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3358 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003359 break;
3360 }
3361 case TransparentVirtualPixelMethod:
3362 {
cristy4789f0d2010-01-10 00:01:06 +00003363 SetRedPixelComponent(&virtual_pixel,0);
3364 SetGreenPixelComponent(&virtual_pixel,0);
3365 SetBluePixelComponent(&virtual_pixel,0);
3366 SetOpacityPixelComponent(&virtual_pixel,TransparentOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003367 break;
3368 }
3369 case MaskVirtualPixelMethod:
3370 case WhiteVirtualPixelMethod:
3371 {
cristy4789f0d2010-01-10 00:01:06 +00003372 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3373 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3374 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3375 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003376 break;
3377 }
3378 default:
3379 {
3380 virtual_pixel=image->background_color;
3381 break;
3382 }
3383 }
cristyc3ec0d42010-04-07 01:18:08 +00003384 virtual_index=0;
cristybb503372010-05-27 20:51:26 +00003385 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003386 {
cristybb503372010-05-27 20:51:26 +00003387 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003388 {
3389 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003390 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003391 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3392 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003393 {
3394 MagickModulo
3395 x_modulo,
3396 y_modulo;
3397
3398 /*
3399 Transfer a single pixel.
3400 */
3401 length=(MagickSizeType) 1;
3402 switch (virtual_pixel_method)
3403 {
3404 case BackgroundVirtualPixelMethod:
3405 case ConstantVirtualPixelMethod:
3406 case BlackVirtualPixelMethod:
3407 case GrayVirtualPixelMethod:
3408 case TransparentVirtualPixelMethod:
3409 case MaskVirtualPixelMethod:
3410 case WhiteVirtualPixelMethod:
3411 {
3412 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003413 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003414 break;
3415 }
3416 case EdgeVirtualPixelMethod:
3417 default:
3418 {
3419 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003420 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003421 1UL,1UL,virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003422 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3423 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003424 break;
3425 }
3426 case RandomVirtualPixelMethod:
3427 {
3428 if (cache_info->random_info == (RandomInfo *) NULL)
3429 cache_info->random_info=AcquireRandomInfo();
3430 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003431 RandomX(cache_info->random_info,cache_info->columns),
3432 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003433 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003434 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3435 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003436 break;
3437 }
3438 case DitherVirtualPixelMethod:
3439 {
3440 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003441 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003442 1UL,1UL,virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003443 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3444 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003445 break;
3446 }
3447 case TileVirtualPixelMethod:
3448 {
3449 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3450 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3451 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3452 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3453 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003454 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3455 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003456 break;
3457 }
3458 case MirrorVirtualPixelMethod:
3459 {
3460 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3461 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003462 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003463 x_modulo.remainder-1L;
3464 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3465 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003466 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003467 y_modulo.remainder-1L;
3468 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3469 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3470 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003471 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3472 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003473 break;
3474 }
3475 case CheckerTileVirtualPixelMethod:
3476 {
3477 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3478 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3479 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3480 {
3481 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003482 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003483 break;
3484 }
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 HorizontalTileVirtualPixelMethod:
3493 {
cristybb503372010-05-27 20:51:26 +00003494 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003495 {
3496 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003497 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003498 break;
3499 }
3500 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3501 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
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 VerticalTileVirtualPixelMethod:
3510 {
cristybb503372010-05-27 20:51:26 +00003511 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
cristy3ed852e2009-09-05 21:47:34 +00003512 {
3513 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003514 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003515 break;
3516 }
3517 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3518 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
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 HorizontalTileEdgeVirtualPixelMethod:
3527 {
3528 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3529 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003530 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003531 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003532 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3533 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003534 break;
3535 }
3536 case VerticalTileEdgeVirtualPixelMethod:
3537 {
3538 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3539 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003540 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003541 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003542 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3543 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003544 break;
3545 }
3546 }
3547 if (p == (const PixelPacket *) NULL)
3548 break;
3549 *q++=(*p);
cristyc3ec0d42010-04-07 01:18:08 +00003550 if ((indexes != (IndexPacket *) NULL) &&
3551 (virtual_indexes != (const IndexPacket *) NULL))
3552 *indexes++=(*virtual_indexes);
cristy3ed852e2009-09-05 21:47:34 +00003553 continue;
3554 }
3555 /*
3556 Transfer a run of pixels.
3557 */
3558 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,
cristybb503372010-05-27 20:51:26 +00003559 (size_t) length,1UL,virtual_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003560 if (p == (const PixelPacket *) NULL)
3561 break;
cristyc3ec0d42010-04-07 01:18:08 +00003562 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003563 (void) CopyMagickMemory(q,p,(size_t) length*sizeof(*p));
3564 q+=length;
cristyc3ec0d42010-04-07 01:18:08 +00003565 if ((indexes != (IndexPacket *) NULL) &&
3566 (virtual_indexes != (const IndexPacket *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003567 {
cristyc3ec0d42010-04-07 01:18:08 +00003568 (void) CopyMagickMemory(indexes,virtual_indexes,(size_t) length*
3569 sizeof(*virtual_indexes));
3570 indexes+=length;
cristy3ed852e2009-09-05 21:47:34 +00003571 }
3572 }
3573 }
3574 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3575 return(pixels);
3576}
3577
3578/*
3579%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3580% %
3581% %
3582% %
3583+ G e t V i r t u a l P i x e l C a c h e %
3584% %
3585% %
3586% %
3587%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3588%
3589% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3590% cache as defined by the geometry parameters. A pointer to the pixels
3591% is returned if the pixels are transferred, otherwise a NULL is returned.
3592%
3593% The format of the GetVirtualPixelCache() method is:
3594%
3595% const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003596% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3597% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003598% ExceptionInfo *exception)
3599%
3600% A description of each parameter follows:
3601%
3602% o image: the image.
3603%
3604% o virtual_pixel_method: the virtual pixel method.
3605%
3606% o x,y,columns,rows: These values define the perimeter of a region of
3607% pixels.
3608%
3609% o exception: return any errors or warnings in this structure.
3610%
3611*/
3612static const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003613 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3614 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003615{
3616 CacheInfo
3617 *cache_info;
3618
3619 const PixelPacket
3620 *pixels;
3621
cristy6ebe97c2010-07-03 01:17:28 +00003622 int
cristy3ed852e2009-09-05 21:47:34 +00003623 id;
3624
cristy3ed852e2009-09-05 21:47:34 +00003625 cache_info=(CacheInfo *) image->cache;
3626 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00003627 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00003628 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3629 cache_info->nexus_info[id],exception);
3630 return(pixels);
3631}
3632
3633/*
3634%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3635% %
3636% %
3637% %
3638% G e t V i r t u a l P i x e l Q u e u e %
3639% %
3640% %
3641% %
3642%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3643%
3644% GetVirtualPixelQueue() returns the virtual pixels associated with the
3645% last call to QueueAuthenticPixels() or GetVirtualPixels().
3646%
3647% The format of the GetVirtualPixelQueue() method is:
3648%
3649% const PixelPacket *GetVirtualPixelQueue(const Image image)
3650%
3651% A description of each parameter follows:
3652%
3653% o image: the image.
3654%
3655*/
3656MagickExport const PixelPacket *GetVirtualPixelQueue(const Image *image)
3657{
3658 CacheInfo
3659 *cache_info;
3660
3661 assert(image != (const Image *) NULL);
3662 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003663 assert(image->cache != (Cache) NULL);
3664 cache_info=(CacheInfo *) image->cache;
3665 assert(cache_info->signature == MagickSignature);
3666 if (cache_info->methods.get_virtual_pixels_handler ==
3667 (GetVirtualPixelsHandler) NULL)
3668 return((PixelPacket *) NULL);
3669 return(cache_info->methods.get_virtual_pixels_handler(image));
3670}
3671
3672/*
3673%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3674% %
3675% %
3676% %
3677% G e t V i r t u a l P i x e l s %
3678% %
3679% %
3680% %
3681%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3682%
3683% GetVirtualPixels() returns an immutable pixel region. If the
3684% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003685% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003686% copy of the pixels or it may point to the original pixels in memory.
3687% Performance is maximized if the selected region is part of one row, or one
3688% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003689% (without a copy) if the image is in memory, or in a memory-mapped file. The
3690% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003691%
3692% Pixels accessed via the returned pointer represent a simple array of type
3693% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
3694% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access
3695% the black color component or to obtain the colormap indexes (of type
3696% IndexPacket) corresponding to the region.
3697%
3698% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3699%
3700% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3701% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3702% GetCacheViewAuthenticPixels() instead.
3703%
3704% The format of the GetVirtualPixels() method is:
3705%
cristybb503372010-05-27 20:51:26 +00003706% const PixelPacket *GetVirtualPixels(const Image *image,const ssize_t x,
3707% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003708% ExceptionInfo *exception)
3709%
3710% A description of each parameter follows:
3711%
3712% o image: the image.
3713%
3714% o x,y,columns,rows: These values define the perimeter of a region of
3715% pixels.
3716%
3717% o exception: return any errors or warnings in this structure.
3718%
3719*/
3720MagickExport const PixelPacket *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003721 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3722 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003723{
3724 CacheInfo
3725 *cache_info;
3726
3727 const PixelPacket
3728 *pixels;
3729
3730 assert(image != (const Image *) NULL);
3731 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003732 assert(image->cache != (Cache) NULL);
3733 cache_info=(CacheInfo *) image->cache;
3734 assert(cache_info->signature == MagickSignature);
3735 if (cache_info->methods.get_virtual_pixel_handler ==
3736 (GetVirtualPixelHandler) NULL)
3737 return((const PixelPacket *) NULL);
3738 pixels=cache_info->methods.get_virtual_pixel_handler(image,
3739 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception);
3740 return(pixels);
3741}
3742
3743/*
3744%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3745% %
3746% %
3747% %
3748+ 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 %
3749% %
3750% %
3751% %
3752%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3753%
3754% GetVirtualPixelsCache() returns the pixels associated with the last call
3755% to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3756%
3757% The format of the GetVirtualPixelsCache() method is:
3758%
3759% PixelPacket *GetVirtualPixelsCache(const Image *image)
3760%
3761% A description of each parameter follows:
3762%
3763% o image: the image.
3764%
3765*/
3766static const PixelPacket *GetVirtualPixelsCache(const Image *image)
3767{
3768 CacheInfo
3769 *cache_info;
3770
3771 const PixelPacket
3772 *pixels;
3773
cristy6ebe97c2010-07-03 01:17:28 +00003774 int
cristy3ed852e2009-09-05 21:47:34 +00003775 id;
3776
cristy3ed852e2009-09-05 21:47:34 +00003777 cache_info=(CacheInfo *) image->cache;
3778 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00003779 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00003780 pixels=GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]);
3781 return(pixels);
3782}
3783
3784/*
3785%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3786% %
3787% %
3788% %
3789+ G e t V i r t u a l P i x e l s N e x u s %
3790% %
3791% %
3792% %
3793%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3794%
3795% GetVirtualPixelsNexus() returns the pixels associated with the specified
3796% cache nexus.
3797%
3798% The format of the GetVirtualPixelsNexus() method is:
3799%
3800% const IndexPacket *GetVirtualPixelsNexus(const Cache cache,
3801% NexusInfo *nexus_info)
3802%
3803% A description of each parameter follows:
3804%
3805% o cache: the pixel cache.
3806%
3807% o nexus_info: the cache nexus to return the colormap pixels.
3808%
3809*/
3810MagickExport const PixelPacket *GetVirtualPixelsNexus(const Cache cache,
3811 NexusInfo *nexus_info)
3812{
3813 CacheInfo
3814 *cache_info;
3815
3816 if (cache == (Cache) NULL)
3817 return((PixelPacket *) NULL);
3818 cache_info=(CacheInfo *) cache;
3819 assert(cache_info->signature == MagickSignature);
3820 if (cache_info->storage_class == UndefinedClass)
3821 return((PixelPacket *) NULL);
3822 return((const PixelPacket *) nexus_info->pixels);
3823}
3824
3825/*
3826%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3827% %
3828% %
3829% %
3830+ M a s k P i x e l C a c h e N e x u s %
3831% %
3832% %
3833% %
3834%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3835%
3836% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3837% The method returns MagickTrue if the pixel region is masked, otherwise
3838% MagickFalse.
3839%
3840% The format of the MaskPixelCacheNexus() method is:
3841%
3842% MagickBooleanType MaskPixelCacheNexus(Image *image,
3843% NexusInfo *nexus_info,ExceptionInfo *exception)
3844%
3845% A description of each parameter follows:
3846%
3847% o image: the image.
3848%
3849% o nexus_info: the cache nexus to clip.
3850%
3851% o exception: return any errors or warnings in this structure.
3852%
3853*/
3854
3855static inline void MagickPixelCompositeMask(const MagickPixelPacket *p,
3856 const MagickRealType alpha,const MagickPixelPacket *q,
3857 const MagickRealType beta,MagickPixelPacket *composite)
3858{
3859 MagickRealType
3860 gamma;
3861
3862 if (alpha == TransparentOpacity)
3863 {
3864 *composite=(*q);
3865 return;
3866 }
3867 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3868 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3869 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3870 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3871 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3872 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3873 composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
3874}
3875
3876static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3877 ExceptionInfo *exception)
3878{
3879 CacheInfo
3880 *cache_info;
3881
3882 MagickPixelPacket
3883 alpha,
3884 beta;
3885
3886 MagickSizeType
3887 number_pixels;
3888
3889 NexusInfo
3890 **clip_nexus,
3891 **image_nexus;
3892
3893 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003894 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003895
3896 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003897 *restrict nexus_indexes,
3898 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003899
cristy3ed852e2009-09-05 21:47:34 +00003900 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003901 *restrict p,
3902 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003903
cristye076a6e2010-08-15 19:59:43 +00003904 register ssize_t
3905 i;
3906
cristy3ed852e2009-09-05 21:47:34 +00003907 /*
3908 Apply clip mask.
3909 */
3910 if (image->debug != MagickFalse)
3911 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3912 if (image->mask == (Image *) NULL)
3913 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +00003914 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00003915 if (cache_info == (Cache) NULL)
3916 return(MagickFalse);
3917 image_nexus=AcquirePixelCacheNexus(1);
3918 clip_nexus=AcquirePixelCacheNexus(1);
3919 if ((image_nexus == (NexusInfo **) NULL) ||
3920 (clip_nexus == (NexusInfo **) NULL))
3921 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy09449f72010-01-23 03:08:36 +00003922 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,
3923 nexus_info->region.y,nexus_info->region.width,nexus_info->region.height,
3924 image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003925 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
3926 q=nexus_info->pixels;
3927 nexus_indexes=nexus_info->indexes;
3928 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3929 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3930 nexus_info->region.height,clip_nexus[0],&image->exception);
3931 GetMagickPixelPacket(image,&alpha);
3932 GetMagickPixelPacket(image,&beta);
3933 number_pixels=(MagickSizeType) nexus_info->region.width*
3934 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +00003935 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +00003936 {
3937 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
3938 break;
3939 SetMagickPixelPacket(image,p,indexes+i,&alpha);
3940 SetMagickPixelPacket(image,q,nexus_indexes+i,&beta);
3941 MagickPixelCompositeMask(&beta,(MagickRealType) PixelIntensityToQuantum(r),
3942 &alpha,alpha.opacity,&beta);
cristyce70c172010-01-07 17:15:30 +00003943 q->red=ClampToQuantum(beta.red);
3944 q->green=ClampToQuantum(beta.green);
3945 q->blue=ClampToQuantum(beta.blue);
3946 q->opacity=ClampToQuantum(beta.opacity);
cristy3ed852e2009-09-05 21:47:34 +00003947 if (cache_info->active_index_channel != MagickFalse)
3948 nexus_indexes[i]=indexes[i];
3949 p++;
3950 q++;
3951 r++;
3952 }
3953 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3954 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +00003955 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003956 return(MagickFalse);
3957 return(MagickTrue);
3958}
3959
3960/*
3961%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3962% %
3963% %
3964% %
3965+ O p e n P i x e l C a c h e %
3966% %
3967% %
3968% %
3969%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3970%
3971% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3972% dimensions, allocating space for the image pixels and optionally the
3973% colormap indexes, and memory mapping the cache if it is disk based. The
3974% cache nexus array is initialized as well.
3975%
3976% The format of the OpenPixelCache() method is:
3977%
3978% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3979% ExceptionInfo *exception)
3980%
3981% A description of each parameter follows:
3982%
3983% o image: the image.
3984%
3985% o mode: ReadMode, WriteMode, or IOMode.
3986%
3987% o exception: return any errors or warnings in this structure.
3988%
3989*/
3990
cristyd43a46b2010-01-21 02:13:41 +00003991static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003992{
3993 cache_info->mapped=MagickFalse;
3994 cache_info->pixels=(PixelPacket *) AcquireMagickMemory((size_t)
3995 cache_info->length);
3996 if (cache_info->pixels == (PixelPacket *) NULL)
3997 {
3998 cache_info->mapped=MagickTrue;
3999 cache_info->pixels=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
4000 cache_info->length);
4001 }
4002}
4003
4004static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
4005{
4006 CacheInfo
4007 *cache_info;
4008
4009 MagickOffsetType
4010 count,
4011 extent,
4012 offset;
4013
4014 cache_info=(CacheInfo *) image->cache;
4015 if (image->debug != MagickFalse)
4016 {
4017 char
4018 format[MaxTextExtent],
4019 message[MaxTextExtent];
4020
cristyb9080c92009-12-01 20:13:26 +00004021 (void) FormatMagickSize(length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00004022 (void) FormatMagickString(message,MaxTextExtent,
cristy2ce15c92010-03-12 14:03:41 +00004023 "extend %s (%s[%d], disk, %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00004024 cache_info->cache_filename,cache_info->file,format);
4025 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4026 }
4027 if (length != (MagickSizeType) ((MagickOffsetType) length))
4028 return(MagickFalse);
4029 extent=(MagickOffsetType) MagickSeek(cache_info->file,0,SEEK_END);
4030 if (extent < 0)
4031 return(MagickFalse);
4032 if ((MagickSizeType) extent >= length)
4033 return(MagickTrue);
4034 offset=(MagickOffsetType) length-1;
4035 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
4036 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
4037}
4038
4039static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
4040 ExceptionInfo *exception)
4041{
4042 char
4043 format[MaxTextExtent],
4044 message[MaxTextExtent];
4045
4046 CacheInfo
4047 *cache_info,
4048 source_info;
4049
4050 MagickSizeType
4051 length,
4052 number_pixels;
4053
4054 MagickStatusType
4055 status;
4056
4057 size_t
cristye076a6e2010-08-15 19:59:43 +00004058 columns,
cristy3ed852e2009-09-05 21:47:34 +00004059 packet_size;
4060
cristy3ed852e2009-09-05 21:47:34 +00004061 if (image->debug != MagickFalse)
4062 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4063 if ((image->columns == 0) || (image->rows == 0))
4064 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
4065 cache_info=(CacheInfo *) image->cache;
4066 source_info=(*cache_info);
4067 source_info.file=(-1);
cristye8c25f92010-06-03 00:53:06 +00004068 (void) FormatMagickString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
4069 image->filename,(double) GetImageIndexInList(image));
cristy87528ea2009-09-10 14:53:56 +00004070 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +00004071 cache_info->rows=image->rows;
4072 cache_info->columns=image->columns;
4073 cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
4074 (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
cristy73724512010-04-12 14:43:14 +00004075 if (image->ping != MagickFalse)
4076 {
4077 cache_info->storage_class=image->storage_class;
4078 cache_info->colorspace=image->colorspace;
4079 cache_info->type=PingCache;
4080 cache_info->pixels=(PixelPacket *) NULL;
4081 cache_info->indexes=(IndexPacket *) NULL;
4082 cache_info->length=0;
4083 return(MagickTrue);
4084 }
cristy3ed852e2009-09-05 21:47:34 +00004085 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4086 packet_size=sizeof(PixelPacket);
4087 if (cache_info->active_index_channel != MagickFalse)
4088 packet_size+=sizeof(IndexPacket);
4089 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00004090 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00004091 if (cache_info->columns != columns)
4092 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4093 image->filename);
4094 cache_info->length=length;
4095 status=AcquireMagickResource(AreaResource,cache_info->length);
4096 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4097 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4098 {
4099 status=AcquireMagickResource(MemoryResource,cache_info->length);
4100 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4101 (cache_info->type == MemoryCache))
4102 {
cristyd43a46b2010-01-21 02:13:41 +00004103 AllocatePixelCachePixels(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004104 if (cache_info->pixels == (PixelPacket *) NULL)
4105 cache_info->pixels=source_info.pixels;
4106 else
4107 {
4108 /*
4109 Create memory pixel cache.
4110 */
4111 if (image->debug != MagickFalse)
4112 {
cristy97e7a572009-12-05 15:07:53 +00004113 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004114 format);
cristy3ed852e2009-09-05 21:47:34 +00004115 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004116 "open %s (%s memory, %.20gx%.20g %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00004117 cache_info->mapped != MagickFalse ? "anonymous" : "heap",
cristye8c25f92010-06-03 00:53:06 +00004118 (double) cache_info->columns,(double) cache_info->rows,
4119 format);
cristy3ed852e2009-09-05 21:47:34 +00004120 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4121 message);
4122 }
4123 cache_info->storage_class=image->storage_class;
4124 cache_info->colorspace=image->colorspace;
4125 cache_info->type=MemoryCache;
4126 cache_info->indexes=(IndexPacket *) NULL;
4127 if (cache_info->active_index_channel != MagickFalse)
4128 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4129 number_pixels);
4130 if (source_info.storage_class != UndefinedClass)
4131 {
4132 status|=ClonePixelCachePixels(cache_info,&source_info,
4133 exception);
4134 RelinquishPixelCachePixels(&source_info);
4135 }
4136 return(MagickTrue);
4137 }
4138 }
4139 RelinquishMagickResource(MemoryResource,cache_info->length);
4140 }
4141 /*
4142 Create pixel cache on disk.
4143 */
4144 status=AcquireMagickResource(DiskResource,cache_info->length);
4145 if (status == MagickFalse)
4146 {
4147 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4148 "CacheResourcesExhausted","`%s'",image->filename);
4149 return(MagickFalse);
4150 }
4151 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4152 {
4153 RelinquishMagickResource(DiskResource,cache_info->length);
4154 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4155 image->filename);
4156 return(MagickFalse);
4157 }
4158 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4159 cache_info->length);
4160 if (status == MagickFalse)
4161 {
4162 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4163 image->filename);
4164 return(MagickFalse);
4165 }
4166 cache_info->storage_class=image->storage_class;
4167 cache_info->colorspace=image->colorspace;
4168 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4169 status=AcquireMagickResource(AreaResource,cache_info->length);
4170 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4171 cache_info->type=DiskCache;
4172 else
4173 {
4174 status=AcquireMagickResource(MapResource,cache_info->length);
4175 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4176 (cache_info->type != MemoryCache))
4177 cache_info->type=DiskCache;
4178 else
4179 {
4180 cache_info->pixels=(PixelPacket *) MapBlob(cache_info->file,mode,
4181 cache_info->offset,(size_t) cache_info->length);
4182 if (cache_info->pixels == (PixelPacket *) NULL)
4183 {
4184 cache_info->pixels=source_info.pixels;
4185 cache_info->type=DiskCache;
4186 }
4187 else
4188 {
4189 /*
4190 Create file-backed memory-mapped pixel cache.
4191 */
4192 (void) ClosePixelCacheOnDisk(cache_info);
4193 cache_info->type=MapCache;
4194 cache_info->mapped=MagickTrue;
4195 cache_info->indexes=(IndexPacket *) NULL;
4196 if (cache_info->active_index_channel != MagickFalse)
4197 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4198 number_pixels);
4199 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4200 {
4201 status=ClonePixelCachePixels(cache_info,&source_info,
4202 exception);
4203 RelinquishPixelCachePixels(&source_info);
4204 }
4205 if (image->debug != MagickFalse)
4206 {
cristy97e7a572009-12-05 15:07:53 +00004207 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004208 format);
cristy3ed852e2009-09-05 21:47:34 +00004209 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004210 "open %s (%s[%d], memory-mapped, %.20gx%.20g %sB)",
cristy3ed852e2009-09-05 21:47:34 +00004211 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004212 cache_info->file,(double) cache_info->columns,(double)
4213 cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004214 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4215 message);
4216 }
4217 return(MagickTrue);
4218 }
4219 }
4220 RelinquishMagickResource(MapResource,cache_info->length);
4221 }
4222 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4223 {
4224 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4225 RelinquishPixelCachePixels(&source_info);
4226 }
4227 if (image->debug != MagickFalse)
4228 {
cristyb9080c92009-12-01 20:13:26 +00004229 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00004230 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004231 "open %s (%s[%d], disk, %.20gx%.20g %sB)",cache_info->filename,
4232 cache_info->cache_filename,cache_info->file,(double)
4233 cache_info->columns,(double) cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004234 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4235 }
4236 return(MagickTrue);
4237}
4238
4239/*
4240%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4241% %
4242% %
4243% %
4244+ P e r s i s t P i x e l C a c h e %
4245% %
4246% %
4247% %
4248%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4249%
4250% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4251% persistent pixel cache is one that resides on disk and is not destroyed
4252% when the program exits.
4253%
4254% The format of the PersistPixelCache() method is:
4255%
4256% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4257% const MagickBooleanType attach,MagickOffsetType *offset,
4258% ExceptionInfo *exception)
4259%
4260% A description of each parameter follows:
4261%
4262% o image: the image.
4263%
4264% o filename: the persistent pixel cache filename.
4265%
cristy01b7eb02009-09-10 23:10:14 +00004266% o attach: A value other than zero initializes the persistent pixel
4267% cache.
4268%
cristy3ed852e2009-09-05 21:47:34 +00004269% o initialize: A value other than zero initializes the persistent pixel
4270% cache.
4271%
4272% o offset: the offset in the persistent cache to store pixels.
4273%
4274% o exception: return any errors or warnings in this structure.
4275%
4276*/
4277MagickExport MagickBooleanType PersistPixelCache(Image *image,
4278 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4279 ExceptionInfo *exception)
4280{
4281 CacheInfo
4282 *cache_info,
4283 *clone_info;
4284
4285 Image
4286 clone_image;
4287
cristy3ed852e2009-09-05 21:47:34 +00004288 MagickBooleanType
4289 status;
4290
cristye076a6e2010-08-15 19:59:43 +00004291 ssize_t
4292 page_size;
4293
cristy3ed852e2009-09-05 21:47:34 +00004294 assert(image != (Image *) NULL);
4295 assert(image->signature == MagickSignature);
4296 if (image->debug != MagickFalse)
4297 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4298 assert(image->cache != (void *) NULL);
4299 assert(filename != (const char *) NULL);
4300 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004301 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004302 cache_info=(CacheInfo *) image->cache;
4303 assert(cache_info->signature == MagickSignature);
4304 if (attach != MagickFalse)
4305 {
4306 /*
cristy01b7eb02009-09-10 23:10:14 +00004307 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004308 */
4309 if (image->debug != MagickFalse)
4310 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4311 "attach persistent cache");
4312 (void) CopyMagickString(cache_info->cache_filename,filename,
4313 MaxTextExtent);
4314 cache_info->type=DiskCache;
4315 cache_info->offset=(*offset);
4316 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4317 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004318 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004319 return(MagickTrue);
4320 }
cristy01b7eb02009-09-10 23:10:14 +00004321 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4322 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004323 {
cristyf84a1932010-01-03 18:00:18 +00004324 LockSemaphoreInfo(cache_info->semaphore);
cristy09449f72010-01-23 03:08:36 +00004325 if ((cache_info->mode != ReadMode) &&
4326 (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004327 (cache_info->reference_count == 1))
4328 {
4329 int
4330 status;
4331
4332 /*
cristy01b7eb02009-09-10 23:10:14 +00004333 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004334 */
4335 status=rename(cache_info->cache_filename,filename);
4336 if (status == 0)
4337 {
4338 (void) CopyMagickString(cache_info->cache_filename,filename,
4339 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004340 *offset+=cache_info->length+page_size-(cache_info->length %
4341 page_size);
cristyf84a1932010-01-03 18:00:18 +00004342 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004343 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004344 if (image->debug != MagickFalse)
4345 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4346 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004347 return(MagickTrue);
4348 }
4349 }
cristyf84a1932010-01-03 18:00:18 +00004350 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004351 }
4352 /*
cristy01b7eb02009-09-10 23:10:14 +00004353 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004354 */
4355 clone_image=(*image);
4356 clone_info=(CacheInfo *) clone_image.cache;
4357 image->cache=ClonePixelCache(cache_info);
4358 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4359 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4360 cache_info->type=DiskCache;
4361 cache_info->offset=(*offset);
4362 cache_info=(CacheInfo *) image->cache;
4363 status=ClonePixelCacheNexus(cache_info,clone_info,exception);
4364 if (status != MagickFalse)
4365 {
4366 status=OpenPixelCache(image,IOMode,exception);
4367 if (status != MagickFalse)
4368 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
4369 }
cristy688f07b2009-09-27 15:19:13 +00004370 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004371 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4372 return(status);
4373}
4374
4375/*
4376%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4377% %
4378% %
4379% %
4380+ Q u e u e A u t h e n t i c N e x u s %
4381% %
4382% %
4383% %
4384%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4385%
4386% QueueAuthenticNexus() allocates an region to store image pixels as defined
4387% by the region rectangle and returns a pointer to the region. This region is
4388% subsequently transferred from the pixel cache with
4389% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4390% pixels are transferred, otherwise a NULL is returned.
4391%
4392% The format of the QueueAuthenticNexus() method is:
4393%
cristy5f959472010-05-27 22:19:46 +00004394% PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
4395% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004396% NexusInfo *nexus_info,ExceptionInfo *exception)
4397%
4398% A description of each parameter follows:
4399%
4400% o image: the image.
4401%
4402% o x,y,columns,rows: These values define the perimeter of a region of
4403% pixels.
4404%
4405% o nexus_info: the cache nexus to set.
4406%
4407% o exception: return any errors or warnings in this structure.
4408%
4409*/
cristybb503372010-05-27 20:51:26 +00004410MagickExport PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy30097232010-07-01 02:16:30 +00004411 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
4412 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004413{
4414 CacheInfo
4415 *cache_info;
4416
4417 MagickOffsetType
4418 offset;
4419
4420 MagickSizeType
4421 number_pixels;
4422
4423 RectangleInfo
4424 region;
4425
4426 /*
4427 Validate pixel cache geometry.
4428 */
cristy77ff0282010-09-13 00:51:10 +00004429 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
4430 if (cache_info == (Cache) NULL)
4431 return((PixelPacket *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004432 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4433 {
4434 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4435 "NoPixelsDefinedInCache","`%s'",image->filename);
4436 return((PixelPacket *) NULL);
4437 }
cristybb503372010-05-27 20:51:26 +00004438 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4439 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004440 {
4441 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4442 "PixelsAreNotAuthentic","`%s'",image->filename);
4443 return((PixelPacket *) NULL);
4444 }
4445 offset=(MagickOffsetType) y*cache_info->columns+x;
4446 if (offset < 0)
4447 return((PixelPacket *) NULL);
4448 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4449 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4450 if ((MagickSizeType) offset >= number_pixels)
4451 return((PixelPacket *) NULL);
4452 /*
4453 Return pixel cache.
4454 */
4455 region.x=x;
4456 region.y=y;
4457 region.width=columns;
4458 region.height=rows;
4459 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4460}
4461
4462/*
4463%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4464% %
4465% %
4466% %
4467+ 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 %
4468% %
4469% %
4470% %
4471%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4472%
4473% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4474% defined by the region rectangle and returns a pointer to the region. This
4475% region is subsequently transferred from the pixel cache with
4476% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4477% pixels are transferred, otherwise a NULL is returned.
4478%
4479% The format of the QueueAuthenticPixelsCache() method is:
4480%
cristybb503372010-05-27 20:51:26 +00004481% PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4482% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004483% ExceptionInfo *exception)
4484%
4485% A description of each parameter follows:
4486%
4487% o image: the image.
4488%
4489% o x,y,columns,rows: These values define the perimeter of a region of
4490% pixels.
4491%
4492% o exception: return any errors or warnings in this structure.
4493%
4494*/
cristybb503372010-05-27 20:51:26 +00004495static PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4496 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004497 ExceptionInfo *exception)
4498{
4499 CacheInfo
4500 *cache_info;
4501
cristy6ebe97c2010-07-03 01:17:28 +00004502 int
cristy3ed852e2009-09-05 21:47:34 +00004503 id;
4504
4505 PixelPacket
4506 *pixels;
4507
cristy77ff0282010-09-13 00:51:10 +00004508 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00004509 if (cache_info == (Cache) NULL)
4510 return((PixelPacket *) NULL);
4511 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00004512 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00004513 pixels=QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4514 exception);
4515 return(pixels);
4516}
4517
4518/*
4519%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4520% %
4521% %
4522% %
4523% Q u e u e A u t h e n t i c P i x e l s %
4524% %
4525% %
4526% %
4527%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4528%
4529% QueueAuthenticPixels() queues a mutable pixel region. If the region is
4530% successfully intialized a pointer to a PixelPacket array representing the
4531% region is returned, otherwise NULL is returned. The returned pointer may
4532% point to a temporary working buffer for the pixels or it may point to the
4533% final location of the pixels in memory.
4534%
4535% Write-only access means that any existing pixel values corresponding to
4536% the region are ignored. This is useful if the initial image is being
4537% created from scratch, or if the existing pixel values are to be
4538% completely replaced without need to refer to their pre-existing values.
4539% The application is free to read and write the pixel buffer returned by
4540% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4541% initialize the pixel array values. Initializing pixel array values is the
4542% application's responsibility.
4543%
4544% Performance is maximized if the selected region is part of one row, or
4545% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004546% pixels in-place (without a copy) if the image is in memory, or in a
4547% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004548% by the user.
4549%
4550% Pixels accessed via the returned pointer represent a simple array of type
4551% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
4552% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
4553% the black color component or the colormap indexes (of type IndexPacket)
4554% corresponding to the region. Once the PixelPacket (and/or IndexPacket)
4555% array has been updated, the changes must be saved back to the underlying
4556% image using SyncAuthenticPixels() or they may be lost.
4557%
4558% The format of the QueueAuthenticPixels() method is:
4559%
cristy5f959472010-05-27 22:19:46 +00004560% PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4561% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004562% ExceptionInfo *exception)
4563%
4564% A description of each parameter follows:
4565%
4566% o image: the image.
4567%
4568% o x,y,columns,rows: These values define the perimeter of a region of
4569% pixels.
4570%
4571% o exception: return any errors or warnings in this structure.
4572%
4573*/
cristybb503372010-05-27 20:51:26 +00004574MagickExport PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4575 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004576 ExceptionInfo *exception)
4577{
4578 CacheInfo
4579 *cache_info;
4580
4581 PixelPacket
4582 *pixels;
4583
4584 assert(image != (Image *) NULL);
4585 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004586 assert(image->cache != (Cache) NULL);
4587 cache_info=(CacheInfo *) image->cache;
4588 assert(cache_info->signature == MagickSignature);
4589 if (cache_info->methods.queue_authentic_pixels_handler ==
4590 (QueueAuthenticPixelsHandler) NULL)
4591 return((PixelPacket *) NULL);
4592 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4593 rows,exception);
4594 return(pixels);
4595}
4596
4597/*
4598%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4599% %
4600% %
4601% %
4602+ R e a d P i x e l C a c h e I n d e x e s %
4603% %
4604% %
4605% %
4606%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4607%
4608% ReadPixelCacheIndexes() reads colormap indexes from the specified region of
4609% the pixel cache.
4610%
4611% The format of the ReadPixelCacheIndexes() method is:
4612%
4613% MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4614% NexusInfo *nexus_info,ExceptionInfo *exception)
4615%
4616% A description of each parameter follows:
4617%
4618% o cache_info: the pixel cache.
4619%
4620% o nexus_info: the cache nexus to read the colormap indexes.
4621%
4622% o exception: return any errors or warnings in this structure.
4623%
4624*/
4625static MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4626 NexusInfo *nexus_info,ExceptionInfo *exception)
4627{
4628 MagickOffsetType
4629 count,
4630 offset;
4631
4632 MagickSizeType
4633 length,
4634 number_pixels;
4635
4636 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004637 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004638
cristybb503372010-05-27 20:51:26 +00004639 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004640 y;
4641
cristybb503372010-05-27 20:51:26 +00004642 size_t
cristy3ed852e2009-09-05 21:47:34 +00004643 rows;
4644
cristy3ed852e2009-09-05 21:47:34 +00004645 if (cache_info->active_index_channel == MagickFalse)
4646 return(MagickFalse);
4647 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4648 return(MagickTrue);
4649 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4650 nexus_info->region.x;
4651 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
4652 rows=nexus_info->region.height;
4653 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004654 q=nexus_info->indexes;
4655 switch (cache_info->type)
4656 {
4657 case MemoryCache:
4658 case MapCache:
4659 {
4660 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004661 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004662
4663 /*
4664 Read indexes from memory.
4665 */
cristydd341db2010-03-04 19:06:38 +00004666 if ((cache_info->columns == nexus_info->region.width) &&
4667 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4668 {
4669 length=number_pixels;
4670 rows=1UL;
4671 }
cristy3ed852e2009-09-05 21:47:34 +00004672 p=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00004673 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004674 {
4675 (void) CopyMagickMemory(q,p,(size_t) length);
4676 p+=cache_info->columns;
4677 q+=nexus_info->region.width;
4678 }
4679 break;
4680 }
4681 case DiskCache:
4682 {
4683 /*
4684 Read indexes from disk.
4685 */
4686 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4687 {
4688 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4689 cache_info->cache_filename);
4690 return(MagickFalse);
4691 }
cristydd341db2010-03-04 19:06:38 +00004692 if ((cache_info->columns == nexus_info->region.width) &&
4693 (number_pixels < MagickMaxBufferExtent))
4694 {
4695 length=number_pixels;
4696 rows=1UL;
4697 }
cristy3ed852e2009-09-05 21:47:34 +00004698 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004699 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004700 {
4701 count=ReadPixelCacheRegion(cache_info,cache_info->offset+number_pixels*
4702 sizeof(PixelPacket)+offset*sizeof(*q),length,(unsigned char *) q);
4703 if ((MagickSizeType) count < length)
4704 break;
4705 offset+=cache_info->columns;
4706 q+=nexus_info->region.width;
4707 }
cristybb503372010-05-27 20:51:26 +00004708 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004709 {
4710 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4711 cache_info->cache_filename);
4712 return(MagickFalse);
4713 }
4714 break;
4715 }
4716 default:
4717 break;
4718 }
4719 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004720 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004721 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004722 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004723 nexus_info->region.width,(double) nexus_info->region.height,(double)
4724 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004725 return(MagickTrue);
4726}
4727
4728/*
4729%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4730% %
4731% %
4732% %
4733+ R e a d P i x e l C a c h e P i x e l s %
4734% %
4735% %
4736% %
4737%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4738%
4739% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4740% cache.
4741%
4742% The format of the ReadPixelCachePixels() method is:
4743%
4744% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4745% NexusInfo *nexus_info,ExceptionInfo *exception)
4746%
4747% A description of each parameter follows:
4748%
4749% o cache_info: the pixel cache.
4750%
4751% o nexus_info: the cache nexus to read the pixels.
4752%
4753% o exception: return any errors or warnings in this structure.
4754%
4755*/
4756static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4757 NexusInfo *nexus_info,ExceptionInfo *exception)
4758{
4759 MagickOffsetType
4760 count,
4761 offset;
4762
4763 MagickSizeType
4764 length,
4765 number_pixels;
4766
cristy3ed852e2009-09-05 21:47:34 +00004767 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004768 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004769
cristye076a6e2010-08-15 19:59:43 +00004770 register ssize_t
4771 y;
4772
cristybb503372010-05-27 20:51:26 +00004773 size_t
cristy3ed852e2009-09-05 21:47:34 +00004774 rows;
4775
cristy3ed852e2009-09-05 21:47:34 +00004776 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4777 return(MagickTrue);
4778 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4779 nexus_info->region.x;
4780 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
4781 rows=nexus_info->region.height;
4782 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004783 q=nexus_info->pixels;
4784 switch (cache_info->type)
4785 {
4786 case MemoryCache:
4787 case MapCache:
4788 {
4789 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004790 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004791
4792 /*
4793 Read pixels from memory.
4794 */
cristydd341db2010-03-04 19:06:38 +00004795 if ((cache_info->columns == nexus_info->region.width) &&
4796 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4797 {
4798 length=number_pixels;
4799 rows=1UL;
4800 }
cristy3ed852e2009-09-05 21:47:34 +00004801 p=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00004802 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004803 {
4804 (void) CopyMagickMemory(q,p,(size_t) length);
4805 p+=cache_info->columns;
4806 q+=nexus_info->region.width;
4807 }
4808 break;
4809 }
4810 case DiskCache:
4811 {
4812 /*
4813 Read pixels from disk.
4814 */
4815 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4816 {
4817 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4818 cache_info->cache_filename);
4819 return(MagickFalse);
4820 }
cristydd341db2010-03-04 19:06:38 +00004821 if ((cache_info->columns == nexus_info->region.width) &&
4822 (number_pixels < MagickMaxBufferExtent))
4823 {
4824 length=number_pixels;
4825 rows=1UL;
4826 }
cristybb503372010-05-27 20:51:26 +00004827 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004828 {
4829 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4830 sizeof(*q),length,(unsigned char *) q);
4831 if ((MagickSizeType) count < length)
4832 break;
4833 offset+=cache_info->columns;
4834 q+=nexus_info->region.width;
4835 }
cristybb503372010-05-27 20:51:26 +00004836 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004837 {
4838 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4839 cache_info->cache_filename);
4840 return(MagickFalse);
4841 }
4842 break;
4843 }
4844 default:
4845 break;
4846 }
4847 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004848 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004849 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004850 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004851 nexus_info->region.width,(double) nexus_info->region.height,(double)
4852 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004853 return(MagickTrue);
4854}
4855
4856/*
4857%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4858% %
4859% %
4860% %
4861+ R e f e r e n c e P i x e l C a c h e %
4862% %
4863% %
4864% %
4865%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4866%
4867% ReferencePixelCache() increments the reference count associated with the
4868% pixel cache returning a pointer to the cache.
4869%
4870% The format of the ReferencePixelCache method is:
4871%
4872% Cache ReferencePixelCache(Cache cache_info)
4873%
4874% A description of each parameter follows:
4875%
4876% o cache_info: the pixel cache.
4877%
4878*/
4879MagickExport Cache ReferencePixelCache(Cache cache)
4880{
4881 CacheInfo
4882 *cache_info;
4883
4884 assert(cache != (Cache *) NULL);
4885 cache_info=(CacheInfo *) cache;
4886 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004887 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004888 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004889 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004890 return(cache_info);
4891}
4892
4893/*
4894%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4895% %
4896% %
4897% %
4898+ S e t P i x e l C a c h e M e t h o d s %
4899% %
4900% %
4901% %
4902%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4903%
4904% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4905%
4906% The format of the SetPixelCacheMethods() method is:
4907%
4908% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4909%
4910% A description of each parameter follows:
4911%
4912% o cache: the pixel cache.
4913%
4914% o cache_methods: Specifies a pointer to a CacheMethods structure.
4915%
4916*/
4917MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4918{
4919 CacheInfo
4920 *cache_info;
4921
4922 GetOneAuthenticPixelFromHandler
4923 get_one_authentic_pixel_from_handler;
4924
4925 GetOneVirtualPixelFromHandler
4926 get_one_virtual_pixel_from_handler;
4927
4928 /*
4929 Set cache pixel methods.
4930 */
4931 assert(cache != (Cache) NULL);
4932 assert(cache_methods != (CacheMethods *) NULL);
4933 cache_info=(CacheInfo *) cache;
4934 assert(cache_info->signature == MagickSignature);
4935 if (cache_info->debug != MagickFalse)
4936 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4937 cache_info->filename);
4938 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4939 cache_info->methods.get_virtual_pixel_handler=
4940 cache_methods->get_virtual_pixel_handler;
4941 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4942 cache_info->methods.destroy_pixel_handler=
4943 cache_methods->destroy_pixel_handler;
4944 if (cache_methods->get_virtual_indexes_from_handler !=
4945 (GetVirtualIndexesFromHandler) NULL)
4946 cache_info->methods.get_virtual_indexes_from_handler=
4947 cache_methods->get_virtual_indexes_from_handler;
4948 if (cache_methods->get_authentic_pixels_handler !=
4949 (GetAuthenticPixelsHandler) NULL)
4950 cache_info->methods.get_authentic_pixels_handler=
4951 cache_methods->get_authentic_pixels_handler;
4952 if (cache_methods->queue_authentic_pixels_handler !=
4953 (QueueAuthenticPixelsHandler) NULL)
4954 cache_info->methods.queue_authentic_pixels_handler=
4955 cache_methods->queue_authentic_pixels_handler;
4956 if (cache_methods->sync_authentic_pixels_handler !=
4957 (SyncAuthenticPixelsHandler) NULL)
4958 cache_info->methods.sync_authentic_pixels_handler=
4959 cache_methods->sync_authentic_pixels_handler;
4960 if (cache_methods->get_authentic_pixels_from_handler !=
4961 (GetAuthenticPixelsFromHandler) NULL)
4962 cache_info->methods.get_authentic_pixels_from_handler=
4963 cache_methods->get_authentic_pixels_from_handler;
4964 if (cache_methods->get_authentic_indexes_from_handler !=
4965 (GetAuthenticIndexesFromHandler) NULL)
4966 cache_info->methods.get_authentic_indexes_from_handler=
4967 cache_methods->get_authentic_indexes_from_handler;
4968 get_one_virtual_pixel_from_handler=
4969 cache_info->methods.get_one_virtual_pixel_from_handler;
4970 if (get_one_virtual_pixel_from_handler !=
4971 (GetOneVirtualPixelFromHandler) NULL)
4972 cache_info->methods.get_one_virtual_pixel_from_handler=
4973 cache_methods->get_one_virtual_pixel_from_handler;
4974 get_one_authentic_pixel_from_handler=
4975 cache_methods->get_one_authentic_pixel_from_handler;
4976 if (get_one_authentic_pixel_from_handler !=
4977 (GetOneAuthenticPixelFromHandler) NULL)
4978 cache_info->methods.get_one_authentic_pixel_from_handler=
4979 cache_methods->get_one_authentic_pixel_from_handler;
4980}
4981
4982/*
4983%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4984% %
4985% %
4986% %
4987+ S e t P i x e l C a c h e N e x u s P i x e l s %
4988% %
4989% %
4990% %
4991%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4992%
4993% SetPixelCacheNexusPixels() defines the region of the cache for the
4994% specified cache nexus.
4995%
4996% The format of the SetPixelCacheNexusPixels() method is:
4997%
4998% PixelPacket SetPixelCacheNexusPixels(const Image *image,
4999% const RectangleInfo *region,NexusInfo *nexus_info,
5000% ExceptionInfo *exception)
5001%
5002% A description of each parameter follows:
5003%
5004% o image: the image.
5005%
5006% o region: A pointer to the RectangleInfo structure that defines the
5007% region of this particular cache nexus.
5008%
5009% o nexus_info: the cache nexus to set.
5010%
5011% o exception: return any errors or warnings in this structure.
5012%
5013*/
5014static PixelPacket *SetPixelCacheNexusPixels(const Image *image,
5015 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
5016{
5017 CacheInfo
5018 *cache_info;
5019
5020 MagickBooleanType
5021 status;
5022
cristy3ed852e2009-09-05 21:47:34 +00005023 MagickSizeType
5024 length,
5025 number_pixels;
5026
cristy3ed852e2009-09-05 21:47:34 +00005027 cache_info=(CacheInfo *) image->cache;
5028 assert(cache_info->signature == MagickSignature);
5029 if (cache_info->type == UndefinedCache)
5030 return((PixelPacket *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00005031 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00005032 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
5033 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00005034 {
cristybb503372010-05-27 20:51:26 +00005035 ssize_t
cristybad067a2010-02-15 17:20:55 +00005036 x,
5037 y;
cristy3ed852e2009-09-05 21:47:34 +00005038
cristyeaedf062010-05-29 22:36:02 +00005039 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
5040 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00005041 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5042 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristy731c3532010-02-15 15:40:03 +00005043 ((nexus_info->region.height == 1UL) ||
5044 ((nexus_info->region.x == 0) &&
5045 ((nexus_info->region.width == cache_info->columns) ||
5046 ((nexus_info->region.width % cache_info->columns) == 0)))))
5047 {
5048 MagickOffsetType
5049 offset;
5050
5051 /*
5052 Pixels are accessed directly from memory.
5053 */
5054 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5055 nexus_info->region.x;
5056 nexus_info->pixels=cache_info->pixels+offset;
5057 nexus_info->indexes=(IndexPacket *) NULL;
5058 if (cache_info->active_index_channel != MagickFalse)
5059 nexus_info->indexes=cache_info->indexes+offset;
5060 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00005061 }
5062 }
5063 /*
5064 Pixels are stored in a cache region until they are synced to the cache.
5065 */
5066 number_pixels=(MagickSizeType) nexus_info->region.width*
5067 nexus_info->region.height;
5068 length=number_pixels*sizeof(PixelPacket);
5069 if (cache_info->active_index_channel != MagickFalse)
5070 length+=number_pixels*sizeof(IndexPacket);
5071 if (nexus_info->cache == (PixelPacket *) NULL)
5072 {
5073 nexus_info->length=length;
5074 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5075 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005076 {
5077 nexus_info->length=0;
5078 return((PixelPacket *) NULL);
5079 }
cristy3ed852e2009-09-05 21:47:34 +00005080 }
5081 else
5082 if (nexus_info->length != length)
5083 {
5084 RelinquishCacheNexusPixels(nexus_info);
5085 nexus_info->length=length;
5086 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5087 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005088 {
5089 nexus_info->length=0;
5090 return((PixelPacket *) NULL);
5091 }
cristy3ed852e2009-09-05 21:47:34 +00005092 }
5093 nexus_info->pixels=nexus_info->cache;
5094 nexus_info->indexes=(IndexPacket *) NULL;
5095 if (cache_info->active_index_channel != MagickFalse)
5096 nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
5097 return(nexus_info->pixels);
5098}
5099
5100/*
5101%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5102% %
5103% %
5104% %
5105% 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 %
5106% %
5107% %
5108% %
5109%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5110%
5111% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5112% pixel cache and returns the previous setting. A virtual pixel is any pixel
5113% access that is outside the boundaries of the image cache.
5114%
5115% The format of the SetPixelCacheVirtualMethod() method is:
5116%
5117% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5118% const VirtualPixelMethod virtual_pixel_method)
5119%
5120% A description of each parameter follows:
5121%
5122% o image: the image.
5123%
5124% o virtual_pixel_method: choose the type of virtual pixel.
5125%
5126*/
5127MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5128 const VirtualPixelMethod virtual_pixel_method)
5129{
5130 CacheInfo
5131 *cache_info;
5132
5133 VirtualPixelMethod
5134 method;
5135
5136 assert(image != (Image *) NULL);
5137 assert(image->signature == MagickSignature);
5138 if (image->debug != MagickFalse)
5139 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5140 assert(image->cache != (Cache) NULL);
5141 cache_info=(CacheInfo *) image->cache;
5142 assert(cache_info->signature == MagickSignature);
5143 method=cache_info->virtual_pixel_method;
5144 cache_info->virtual_pixel_method=virtual_pixel_method;
5145 return(method);
5146}
5147
5148/*
5149%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5150% %
5151% %
5152% %
5153+ 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 %
5154% %
5155% %
5156% %
5157%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5158%
5159% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5160% in-memory or disk cache. The method returns MagickTrue if the pixel region
5161% is synced, otherwise MagickFalse.
5162%
5163% The format of the SyncAuthenticPixelCacheNexus() method is:
5164%
5165% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5166% NexusInfo *nexus_info,ExceptionInfo *exception)
5167%
5168% A description of each parameter follows:
5169%
5170% o image: the image.
5171%
5172% o nexus_info: the cache nexus to sync.
5173%
5174% o exception: return any errors or warnings in this structure.
5175%
5176*/
5177MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5178 NexusInfo *nexus_info,ExceptionInfo *exception)
5179{
5180 CacheInfo
5181 *cache_info;
5182
5183 MagickBooleanType
5184 status;
5185
5186 /*
5187 Transfer pixels to the cache.
5188 */
5189 assert(image != (Image *) NULL);
5190 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005191 if (image->cache == (Cache) NULL)
5192 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5193 cache_info=(CacheInfo *) image->cache;
5194 if (cache_info->type == UndefinedCache)
5195 return(MagickFalse);
5196 if ((image->clip_mask != (Image *) NULL) &&
5197 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5198 return(MagickFalse);
5199 if ((image->mask != (Image *) NULL) &&
5200 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5201 return(MagickFalse);
5202 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5203 return(MagickTrue);
5204 assert(cache_info->signature == MagickSignature);
5205 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5206 if ((cache_info->active_index_channel != MagickFalse) &&
5207 (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
5208 return(MagickFalse);
5209 return(status);
5210}
5211
5212/*
5213%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5214% %
5215% %
5216% %
5217+ S y n c A u t h e n t i c P i x e l C a c h e %
5218% %
5219% %
5220% %
5221%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5222%
5223% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5224% or disk cache. The method returns MagickTrue if the pixel region is synced,
5225% otherwise MagickFalse.
5226%
5227% The format of the SyncAuthenticPixelsCache() method is:
5228%
5229% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5230% ExceptionInfo *exception)
5231%
5232% A description of each parameter follows:
5233%
5234% o image: the image.
5235%
5236% o exception: return any errors or warnings in this structure.
5237%
5238*/
5239static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5240 ExceptionInfo *exception)
5241{
5242 CacheInfo
5243 *cache_info;
5244
cristy6ebe97c2010-07-03 01:17:28 +00005245 int
cristy3ed852e2009-09-05 21:47:34 +00005246 id;
5247
5248 MagickBooleanType
5249 status;
5250
5251 cache_info=(CacheInfo *) image->cache;
5252 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00005253 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00005254 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5255 exception);
5256 return(status);
5257}
5258
5259/*
5260%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5261% %
5262% %
5263% %
5264% S y n c A u t h e n t i c P i x e l s %
5265% %
5266% %
5267% %
5268%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5269%
5270% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5271% The method returns MagickTrue if the pixel region is flushed, otherwise
5272% MagickFalse.
5273%
5274% The format of the SyncAuthenticPixels() method is:
5275%
5276% MagickBooleanType SyncAuthenticPixels(Image *image,
5277% ExceptionInfo *exception)
5278%
5279% A description of each parameter follows:
5280%
5281% o image: the image.
5282%
5283% o exception: return any errors or warnings in this structure.
5284%
5285*/
5286MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5287 ExceptionInfo *exception)
5288{
5289 CacheInfo
5290 *cache_info;
5291
5292 assert(image != (Image *) NULL);
5293 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005294 assert(image->cache != (Cache) NULL);
5295 cache_info=(CacheInfo *) image->cache;
5296 assert(cache_info->signature == MagickSignature);
5297 if (cache_info->methods.sync_authentic_pixels_handler ==
5298 (SyncAuthenticPixelsHandler) NULL)
5299 return(MagickFalse);
5300 return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
5301}
5302
5303/*
5304%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5305% %
5306% %
5307% %
5308+ W r i t e P i x e l C a c h e I n d e x e s %
5309% %
5310% %
5311% %
5312%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5313%
5314% WritePixelCacheIndexes() writes the colormap indexes to the specified
5315% region of the pixel cache.
5316%
5317% The format of the WritePixelCacheIndexes() method is:
5318%
5319% MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5320% NexusInfo *nexus_info,ExceptionInfo *exception)
5321%
5322% A description of each parameter follows:
5323%
5324% o cache_info: the pixel cache.
5325%
5326% o nexus_info: the cache nexus to write the colormap indexes.
5327%
5328% o exception: return any errors or warnings in this structure.
5329%
5330*/
5331static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5332 NexusInfo *nexus_info,ExceptionInfo *exception)
5333{
5334 MagickOffsetType
5335 count,
5336 offset;
5337
5338 MagickSizeType
5339 length,
5340 number_pixels;
5341
5342 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005343 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005344
cristybb503372010-05-27 20:51:26 +00005345 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005346 y;
5347
cristybb503372010-05-27 20:51:26 +00005348 size_t
cristy3ed852e2009-09-05 21:47:34 +00005349 rows;
5350
cristy3ed852e2009-09-05 21:47:34 +00005351 if (cache_info->active_index_channel == MagickFalse)
5352 return(MagickFalse);
5353 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5354 return(MagickTrue);
5355 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5356 nexus_info->region.x;
5357 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
5358 rows=nexus_info->region.height;
5359 number_pixels=(MagickSizeType) length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005360 p=nexus_info->indexes;
5361 switch (cache_info->type)
5362 {
5363 case MemoryCache:
5364 case MapCache:
5365 {
5366 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005367 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005368
5369 /*
5370 Write indexes to memory.
5371 */
cristydd341db2010-03-04 19:06:38 +00005372 if ((cache_info->columns == nexus_info->region.width) &&
5373 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5374 {
5375 length=number_pixels;
5376 rows=1UL;
5377 }
cristy3ed852e2009-09-05 21:47:34 +00005378 q=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00005379 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005380 {
5381 (void) CopyMagickMemory(q,p,(size_t) length);
5382 p+=nexus_info->region.width;
5383 q+=cache_info->columns;
5384 }
5385 break;
5386 }
5387 case DiskCache:
5388 {
5389 /*
5390 Write indexes to disk.
5391 */
5392 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5393 {
5394 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5395 cache_info->cache_filename);
5396 return(MagickFalse);
5397 }
cristydd341db2010-03-04 19:06:38 +00005398 if ((cache_info->columns == nexus_info->region.width) &&
5399 (number_pixels < MagickMaxBufferExtent))
5400 {
5401 length=number_pixels;
5402 rows=1UL;
5403 }
cristy3ed852e2009-09-05 21:47:34 +00005404 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005405 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005406 {
5407 count=WritePixelCacheRegion(cache_info,cache_info->offset+number_pixels*
5408 sizeof(PixelPacket)+offset*sizeof(*p),length,
5409 (const unsigned char *) p);
5410 if ((MagickSizeType) count < length)
5411 break;
5412 p+=nexus_info->region.width;
5413 offset+=cache_info->columns;
5414 }
cristybb503372010-05-27 20:51:26 +00005415 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005416 {
5417 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5418 cache_info->cache_filename);
5419 return(MagickFalse);
5420 }
5421 break;
5422 }
5423 default:
5424 break;
5425 }
5426 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005427 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005428 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005429 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005430 nexus_info->region.width,(double) nexus_info->region.height,(double)
5431 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005432 return(MagickTrue);
5433}
5434
5435/*
5436%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5437% %
5438% %
5439% %
5440+ W r i t e C a c h e P i x e l s %
5441% %
5442% %
5443% %
5444%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5445%
5446% WritePixelCachePixels() writes image pixels to the specified region of the
5447% pixel cache.
5448%
5449% The format of the WritePixelCachePixels() method is:
5450%
5451% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5452% NexusInfo *nexus_info,ExceptionInfo *exception)
5453%
5454% A description of each parameter follows:
5455%
5456% o cache_info: the pixel cache.
5457%
5458% o nexus_info: the cache nexus to write the pixels.
5459%
5460% o exception: return any errors or warnings in this structure.
5461%
5462*/
5463static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5464 NexusInfo *nexus_info,ExceptionInfo *exception)
5465{
5466 MagickOffsetType
5467 count,
5468 offset;
5469
5470 MagickSizeType
5471 length,
5472 number_pixels;
5473
cristy3ed852e2009-09-05 21:47:34 +00005474 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005475 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005476
cristybb503372010-05-27 20:51:26 +00005477 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005478 y;
5479
cristybb503372010-05-27 20:51:26 +00005480 size_t
cristy3ed852e2009-09-05 21:47:34 +00005481 rows;
5482
cristy3ed852e2009-09-05 21:47:34 +00005483 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5484 return(MagickTrue);
5485 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5486 nexus_info->region.x;
5487 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
5488 rows=nexus_info->region.height;
5489 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005490 p=nexus_info->pixels;
5491 switch (cache_info->type)
5492 {
5493 case MemoryCache:
5494 case MapCache:
5495 {
5496 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005497 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005498
5499 /*
5500 Write pixels to memory.
5501 */
cristydd341db2010-03-04 19:06:38 +00005502 if ((cache_info->columns == nexus_info->region.width) &&
5503 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5504 {
5505 length=number_pixels;
5506 rows=1UL;
5507 }
cristy3ed852e2009-09-05 21:47:34 +00005508 q=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00005509 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005510 {
5511 (void) CopyMagickMemory(q,p,(size_t) length);
5512 p+=nexus_info->region.width;
5513 q+=cache_info->columns;
5514 }
5515 break;
5516 }
5517 case DiskCache:
5518 {
5519 /*
5520 Write pixels to disk.
5521 */
5522 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5523 {
5524 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5525 cache_info->cache_filename);
5526 return(MagickFalse);
5527 }
cristydd341db2010-03-04 19:06:38 +00005528 if ((cache_info->columns == nexus_info->region.width) &&
5529 (number_pixels < MagickMaxBufferExtent))
5530 {
5531 length=number_pixels;
5532 rows=1UL;
5533 }
cristybb503372010-05-27 20:51:26 +00005534 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005535 {
5536 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5537 sizeof(*p),length,(const unsigned char *) p);
5538 if ((MagickSizeType) count < length)
5539 break;
5540 p+=nexus_info->region.width;
5541 offset+=cache_info->columns;
5542 }
cristybb503372010-05-27 20:51:26 +00005543 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005544 {
5545 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5546 cache_info->cache_filename);
5547 return(MagickFalse);
5548 }
5549 break;
5550 }
5551 default:
5552 break;
5553 }
5554 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005555 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005556 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005557 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005558 nexus_info->region.width,(double) nexus_info->region.height,(double)
5559 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005560 return(MagickTrue);
5561}