blob: d6ea5cb89ff4d2206d5d585b9f89be37775a8eb2 [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];
597 q->mapped=p->mapped;
598 q->region=p->region;
599 q->length=p->length;
600 q->cache=p->cache;
601 q->pixels=p->pixels;
602 q->indexes=p->indexes;
603 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);
617 }
618 }
619 }
620 return(status);
621}
622
623/*
624%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
625% %
626% %
627% %
cristy60c44a82009-10-07 00:58:49 +0000628+ 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 +0000629% %
630% %
631% %
632%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
633% ClonePixelCachePixels() clones the source pixel cache to the destination
634% cache.
635%
636% The format of the ClonePixelCachePixels() method is:
637%
638% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
639% CacheInfo *source_info,ExceptionInfo *exception)
640%
641% A description of each parameter follows:
642%
643% o cache_info: the pixel cache.
644%
645% o source_info: the source pixel cache.
646%
647% o exception: return any errors or warnings in this structure.
648%
649*/
650
651static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
652{
653 int
654 status;
655
cristy5ee247a2010-02-12 15:42:34 +0000656 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000657 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000658 if (cache_info->file != -1)
659 status=close(cache_info->file);
cristy3ed852e2009-09-05 21:47:34 +0000660 cache_info->file=(-1);
661 RelinquishMagickResource(FileResource,1);
cristyf84a1932010-01-03 18:00:18 +0000662 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000663 return(status == -1 ? MagickFalse : MagickTrue);
664}
665
666static void LimitPixelCacheDescriptors(void)
667{
668 register CacheInfo
669 *p,
670 *q;
671
672 /*
673 Limit # of open file descriptors.
674 */
675 if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
676 return;
cristyf84a1932010-01-03 18:00:18 +0000677 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000678 if (cache_resources == (SplayTreeInfo *) NULL)
679 {
cristyf84a1932010-01-03 18:00:18 +0000680 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000681 return;
682 }
683 ResetSplayTreeIterator(cache_resources);
684 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
685 while (p != (CacheInfo *) NULL)
686 {
687 if ((p->type == DiskCache) && (p->file != -1))
cristy508d9312010-02-10 21:10:30 +0000688 break;
cristy3ed852e2009-09-05 21:47:34 +0000689 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
690 }
691 for (q=p; p != (CacheInfo *) NULL; )
692 {
693 if ((p->type == DiskCache) && (p->file != -1) &&
694 (p->timestamp < q->timestamp))
cristy508d9312010-02-10 21:10:30 +0000695 q=p;
cristy3ed852e2009-09-05 21:47:34 +0000696 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
697 }
698 if (q != (CacheInfo *) NULL)
cristy9e116922010-02-12 20:58:13 +0000699 {
700 /*
701 Close least recently used cache.
702 */
703 (void) close(q->file);
704 q->file=(-1);
705 }
cristyf84a1932010-01-03 18:00:18 +0000706 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000707}
708
709static inline MagickSizeType MagickMax(const MagickSizeType x,
710 const MagickSizeType y)
711{
712 if (x > y)
713 return(x);
714 return(y);
715}
716
717static inline MagickSizeType MagickMin(const MagickSizeType x,
718 const MagickSizeType y)
719{
720 if (x < y)
721 return(x);
722 return(y);
723}
724
725static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
726 const MapMode mode)
727{
728 int
729 file;
730
731 /*
732 Open pixel cache on disk.
733 */
cristyf84a1932010-01-03 18:00:18 +0000734 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000735 if (cache_info->file != -1)
736 {
cristyf84a1932010-01-03 18:00:18 +0000737 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000738 return(MagickTrue); /* cache already open */
739 }
740 LimitPixelCacheDescriptors();
741 if (*cache_info->cache_filename == '\0')
742 file=AcquireUniqueFileResource(cache_info->cache_filename);
743 else
744 switch (mode)
745 {
746 case ReadMode:
747 {
748 file=open(cache_info->cache_filename,O_RDONLY | O_BINARY);
749 break;
750 }
751 case WriteMode:
752 {
753 file=open(cache_info->cache_filename,O_WRONLY | O_CREAT | O_BINARY |
754 O_EXCL,S_MODE);
755 if (file == -1)
756 file=open(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
757 break;
758 }
759 case IOMode:
760 default:
761 {
762 file=open(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
763 O_EXCL,S_MODE);
764 if (file == -1)
765 file=open(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
766 break;
767 }
768 }
769 if (file == -1)
770 {
cristyf84a1932010-01-03 18:00:18 +0000771 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000772 return(MagickFalse);
773 }
774 (void) AcquireMagickResource(FileResource,1);
775 cache_info->file=file;
776 cache_info->timestamp=time(0);
cristyf84a1932010-01-03 18:00:18 +0000777 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000778 return(MagickTrue);
779}
780
781static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
782 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000783 unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000784{
785 register MagickOffsetType
786 i;
787
788 ssize_t
789 count;
790
cristy08a88202010-03-04 19:18:05 +0000791 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000792#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000793 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000794 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
795 {
cristyf84a1932010-01-03 18:00:18 +0000796 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000797 return((MagickOffsetType) -1);
798 }
799#endif
800 count=0;
801 for (i=0; i < (MagickOffsetType) length; i+=count)
802 {
803#if !defined(MAGICKCORE_HAVE_PREAD)
804 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
805 (MagickSizeType) SSIZE_MAX));
806#else
807 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
808 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
809#endif
810 if (count > 0)
811 continue;
812 count=0;
813 if (errno != EINTR)
814 {
815 i=(-1);
816 break;
817 }
818 }
819#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000820 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000821#endif
822 return(i);
823}
824
825static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
826 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000827 const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000828{
829 register MagickOffsetType
830 i;
831
832 ssize_t
833 count;
834
cristy08a88202010-03-04 19:18:05 +0000835 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000836#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000837 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000838 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
839 {
cristyf84a1932010-01-03 18:00:18 +0000840 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000841 return((MagickOffsetType) -1);
842 }
843#endif
844 count=0;
845 for (i=0; i < (MagickOffsetType) length; i+=count)
846 {
847#if !defined(MAGICKCORE_HAVE_PWRITE)
848 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
849 (MagickSizeType) SSIZE_MAX));
850#else
851 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
852 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
853#endif
854 if (count > 0)
855 continue;
856 count=0;
857 if (errno != EINTR)
858 {
859 i=(-1);
860 break;
861 }
862 }
863#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000864 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000865#endif
866 return(i);
867}
868
869static MagickBooleanType CloneDiskToDiskPixelCache(CacheInfo *clone_info,
870 CacheInfo *cache_info,ExceptionInfo *exception)
871{
872 MagickOffsetType
873 count,
874 offset,
875 source_offset;
876
877 MagickSizeType
878 length;
879
cristy3ed852e2009-09-05 21:47:34 +0000880 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000881 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +0000882
cristye076a6e2010-08-15 19:59:43 +0000883 register ssize_t
884 y;
885
cristybb503372010-05-27 20:51:26 +0000886 size_t
cristy3ed852e2009-09-05 21:47:34 +0000887 columns,
888 rows;
889
890 if (cache_info->debug != MagickFalse)
891 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
892 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
893 {
894 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
895 clone_info->cache_filename);
896 return(MagickFalse);
897 }
898 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
899 {
900 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
901 cache_info->cache_filename);
902 return(MagickFalse);
903 }
cristybb503372010-05-27 20:51:26 +0000904 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
905 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +0000906 if ((clone_info->active_index_channel != MagickFalse) &&
907 (cache_info->active_index_channel != MagickFalse))
908 {
909 register IndexPacket
910 *indexes;
911
912 /*
913 Clone cache indexes.
914 */
915 length=MagickMax(clone_info->columns,cache_info->columns)*
916 sizeof(*indexes);
917 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
918 if (indexes == (IndexPacket *) NULL)
919 {
920 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
921 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
922 return(MagickFalse);
923 }
924 (void) ResetMagickMemory(indexes,0,(size_t) length);
925 length=columns*sizeof(*indexes);
926 source_offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
927 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
928 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
929 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +0000930 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000931 {
932 source_offset-=cache_info->columns*sizeof(*indexes);
933 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
934 length,(unsigned char *) indexes);
935 if ((MagickSizeType) count != length)
936 break;
937 offset-=clone_info->columns*sizeof(*indexes);
938 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
939 (unsigned char *) indexes);
940 if ((MagickSizeType) count != length)
941 break;
942 }
cristybb503372010-05-27 20:51:26 +0000943 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000944 {
945 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
946 ThrowFileException(exception,CacheError,"UnableToCloneCache",
947 cache_info->cache_filename);
948 return(MagickFalse);
949 }
950 if (clone_info->columns > cache_info->columns)
951 {
952 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
953 (void) ResetMagickMemory(indexes,0,(size_t) length);
954 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
955 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +0000956 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000957 {
958 offset-=clone_info->columns*sizeof(*indexes);
959 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
960 length,(unsigned char *) indexes);
961 if ((MagickSizeType) count != length)
962 break;
963 }
cristybb503372010-05-27 20:51:26 +0000964 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000965 {
966 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
967 ThrowFileException(exception,CacheError,"UnableToCloneCache",
968 cache_info->cache_filename);
969 return(MagickFalse);
970 }
971 }
972 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
973 }
974 /*
975 Clone cache pixels.
976 */
977 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
978 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
979 if (pixels == (PixelPacket *) NULL)
980 {
981 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
982 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
983 return(MagickFalse);
984 }
985 (void) ResetMagickMemory(pixels,0,(size_t) length);
986 length=columns*sizeof(*pixels);
987 source_offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
988 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +0000989 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000990 {
991 source_offset-=cache_info->columns*sizeof(*pixels);
992 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
993 length,(unsigned char *) pixels);
994 if ((MagickSizeType) count != length)
995 break;
996 offset-=clone_info->columns*sizeof(*pixels);
997 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
998 (unsigned char *) pixels);
999 if ((MagickSizeType) count != length)
1000 break;
1001 }
cristybb503372010-05-27 20:51:26 +00001002 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001003 {
1004 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1005 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1006 cache_info->cache_filename);
1007 return(MagickFalse);
1008 }
1009 if (clone_info->columns > cache_info->columns)
1010 {
1011 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
1012 sizeof(*pixels);
1013 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1014 (void) ResetMagickMemory(pixels,0,(size_t) length);
cristybb503372010-05-27 20:51:26 +00001015 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001016 {
1017 offset-=clone_info->columns*sizeof(*pixels);
1018 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1019 (unsigned char *) pixels);
1020 if ((MagickSizeType) count != length)
1021 break;
1022 }
cristybb503372010-05-27 20:51:26 +00001023 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001024 {
1025 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1026 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1027 cache_info->cache_filename);
1028 return(MagickFalse);
1029 }
1030 }
1031 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1032 return(MagickTrue);
1033}
1034
1035static MagickBooleanType CloneDiskToMemoryPixelCache(CacheInfo *clone_info,
1036 CacheInfo *cache_info,ExceptionInfo *exception)
1037{
1038 MagickOffsetType
1039 count,
1040 offset;
1041
1042 MagickSizeType
1043 length;
1044
cristy3ed852e2009-09-05 21:47:34 +00001045 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001046 *restrict pixels,
1047 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00001048
cristye076a6e2010-08-15 19:59:43 +00001049 register ssize_t
1050 y;
1051
cristybb503372010-05-27 20:51:26 +00001052 size_t
cristy3ed852e2009-09-05 21:47:34 +00001053 columns,
1054 rows;
1055
1056 if (cache_info->debug != MagickFalse)
1057 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
1058 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
1059 {
1060 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1061 cache_info->cache_filename);
1062 return(MagickFalse);
1063 }
cristybb503372010-05-27 20:51:26 +00001064 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1065 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001066 if ((clone_info->active_index_channel != MagickFalse) &&
1067 (cache_info->active_index_channel != MagickFalse))
1068 {
1069 register IndexPacket
1070 *indexes,
1071 *q;
1072
1073 /*
1074 Clone cache indexes.
1075 */
1076 length=MagickMax(clone_info->columns,cache_info->columns)*
1077 sizeof(*indexes);
1078 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1079 if (indexes == (IndexPacket *) NULL)
1080 {
1081 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1082 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1083 return(MagickFalse);
1084 }
1085 (void) ResetMagickMemory(indexes,0,(size_t) length);
1086 length=columns*sizeof(IndexPacket);
1087 offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
1088 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
1089 q=clone_info->indexes+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001090 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001091 {
1092 offset-=cache_info->columns*sizeof(IndexPacket);
1093 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,
1094 length,(unsigned char *) indexes);
1095 if ((MagickSizeType) count != length)
1096 break;
1097 q-=clone_info->columns;
1098 (void) CopyMagickMemory(q,indexes,(size_t) length);
1099 if ((MagickSizeType) count != length)
1100 break;
1101 }
cristybb503372010-05-27 20:51:26 +00001102 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001103 {
1104 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1105 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1106 cache_info->cache_filename);
1107 return(MagickFalse);
1108 }
1109 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1110 }
1111 /*
1112 Clone cache pixels.
1113 */
1114 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1115 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1116 if (pixels == (PixelPacket *) NULL)
1117 {
1118 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1119 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1120 return(MagickFalse);
1121 }
1122 (void) ResetMagickMemory(pixels,0,(size_t) length);
1123 length=columns*sizeof(*pixels);
1124 offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
1125 q=clone_info->pixels+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001126 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001127 {
1128 offset-=cache_info->columns*sizeof(*pixels);
1129 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,length,
1130 (unsigned char *) pixels);
1131 if ((MagickSizeType) count != length)
1132 break;
1133 q-=clone_info->columns;
1134 (void) CopyMagickMemory(q,pixels,(size_t) length);
1135 }
cristybb503372010-05-27 20:51:26 +00001136 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001137 {
1138 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1139 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1140 cache_info->cache_filename);
1141 return(MagickFalse);
1142 }
1143 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1144 return(MagickTrue);
1145}
1146
1147static MagickBooleanType CloneMemoryToDiskPixelCache(CacheInfo *clone_info,
1148 CacheInfo *cache_info,ExceptionInfo *exception)
1149{
1150 MagickOffsetType
1151 count,
1152 offset;
1153
1154 MagickSizeType
1155 length;
1156
cristy3ed852e2009-09-05 21:47:34 +00001157 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001158 *restrict p,
1159 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +00001160
cristye076a6e2010-08-15 19:59:43 +00001161 register ssize_t
1162 y;
1163
cristybb503372010-05-27 20:51:26 +00001164 size_t
cristy3ed852e2009-09-05 21:47:34 +00001165 columns,
1166 rows;
1167
1168 if (cache_info->debug != MagickFalse)
1169 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
1170 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
1171 {
1172 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1173 clone_info->cache_filename);
1174 return(MagickFalse);
1175 }
cristybb503372010-05-27 20:51:26 +00001176 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1177 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001178 if ((clone_info->active_index_channel != MagickFalse) &&
1179 (cache_info->active_index_channel != MagickFalse))
1180 {
1181 register IndexPacket
1182 *p,
1183 *indexes;
1184
1185 /*
1186 Clone cache indexes.
1187 */
1188 length=MagickMax(clone_info->columns,cache_info->columns)*
1189 sizeof(*indexes);
1190 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1191 if (indexes == (IndexPacket *) NULL)
1192 {
1193 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1194 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1195 return(MagickFalse);
1196 }
1197 (void) ResetMagickMemory(indexes,0,(size_t) length);
1198 length=columns*sizeof(*indexes);
1199 p=cache_info->indexes+cache_info->columns*rows;
1200 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1201 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +00001202 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001203 {
1204 p-=cache_info->columns;
1205 (void) CopyMagickMemory(indexes,p,(size_t) length);
1206 offset-=clone_info->columns*sizeof(*indexes);
1207 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1208 (unsigned char *) indexes);
1209 if ((MagickSizeType) count != length)
1210 break;
1211 }
cristybb503372010-05-27 20:51:26 +00001212 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001213 {
1214 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1215 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1216 cache_info->cache_filename);
1217 return(MagickFalse);
1218 }
1219 if (clone_info->columns > cache_info->columns)
1220 {
1221 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
1222 (void) ResetMagickMemory(indexes,0,(size_t) length);
1223 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1224 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +00001225 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001226 {
1227 offset-=clone_info->columns*sizeof(*indexes);
1228 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
1229 length,(unsigned char *) indexes);
1230 if ((MagickSizeType) count != length)
1231 break;
1232 }
cristybb503372010-05-27 20:51:26 +00001233 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001234 {
1235 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1236 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1237 cache_info->cache_filename);
1238 return(MagickFalse);
1239 }
1240 }
1241 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1242 }
1243 /*
1244 Clone cache pixels.
1245 */
1246 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1247 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1248 if (pixels == (PixelPacket *) NULL)
1249 {
1250 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1251 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1252 return(MagickFalse);
1253 }
1254 (void) ResetMagickMemory(pixels,0,(size_t) length);
1255 length=columns*sizeof(*pixels);
1256 p=cache_info->pixels+cache_info->columns*rows;
1257 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +00001258 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001259 {
1260 p-=cache_info->columns;
1261 (void) CopyMagickMemory(pixels,p,(size_t) length);
1262 offset-=clone_info->columns*sizeof(*pixels);
1263 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1264 (unsigned char *) pixels);
1265 if ((MagickSizeType) count != length)
1266 break;
1267 }
cristybb503372010-05-27 20:51:26 +00001268 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001269 {
1270 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1271 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1272 cache_info->cache_filename);
1273 return(MagickFalse);
1274 }
1275 if (clone_info->columns > cache_info->columns)
1276 {
1277 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
1278 sizeof(*pixels);
1279 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1280 (void) ResetMagickMemory(pixels,0,(size_t) length);
cristybb503372010-05-27 20:51:26 +00001281 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001282 {
1283 offset-=clone_info->columns*sizeof(*pixels);
1284 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1285 (unsigned char *) pixels);
1286 if ((MagickSizeType) count != length)
1287 break;
1288 }
cristybb503372010-05-27 20:51:26 +00001289 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001290 {
1291 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1292 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1293 cache_info->cache_filename);
1294 return(MagickFalse);
1295 }
1296 }
1297 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1298 return(MagickTrue);
1299}
1300
1301static MagickBooleanType CloneMemoryToMemoryPixelCache(CacheInfo *clone_info,
1302 CacheInfo *cache_info,ExceptionInfo *magick_unused(exception))
1303{
cristy3ed852e2009-09-05 21:47:34 +00001304 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001305 *restrict pixels,
1306 *restrict source_pixels;
cristy3ed852e2009-09-05 21:47:34 +00001307
cristye076a6e2010-08-15 19:59:43 +00001308 register ssize_t
1309 y;
cristy3ed852e2009-09-05 21:47:34 +00001310
cristybb503372010-05-27 20:51:26 +00001311 size_t
cristy3ed852e2009-09-05 21:47:34 +00001312 columns,
cristye076a6e2010-08-15 19:59:43 +00001313 length,
cristy3ed852e2009-09-05 21:47:34 +00001314 rows;
1315
1316 if (cache_info->debug != MagickFalse)
1317 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
cristybb503372010-05-27 20:51:26 +00001318 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1319 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001320 if ((clone_info->active_index_channel != MagickFalse) &&
1321 (cache_info->active_index_channel != MagickFalse))
1322 {
1323 register IndexPacket
1324 *indexes,
1325 *source_indexes;
1326
1327 /*
1328 Clone cache indexes.
1329 */
1330 length=columns*sizeof(*indexes);
1331 if (clone_info->columns == cache_info->columns)
1332 (void) CopyMagickMemory(clone_info->indexes,cache_info->indexes,
1333 length*rows);
1334 else
1335 {
1336 source_indexes=cache_info->indexes+cache_info->columns*rows;
1337 indexes=clone_info->indexes+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001338 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001339 {
1340 source_indexes-=cache_info->columns;
1341 indexes-=clone_info->columns;
1342 (void) CopyMagickMemory(indexes,source_indexes,length);
1343 }
1344 if (clone_info->columns > cache_info->columns)
1345 {
1346 length=(clone_info->columns-cache_info->columns)*
1347 sizeof(*indexes);
1348 indexes=clone_info->indexes+clone_info->columns*rows+
1349 cache_info->columns;
cristybb503372010-05-27 20:51:26 +00001350 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001351 {
1352 indexes-=clone_info->columns;
1353 (void) ResetMagickMemory(indexes,0,length);
1354 }
1355 }
1356 }
1357 }
1358 /*
1359 Clone cache pixels.
1360 */
1361 length=columns*sizeof(*pixels);
1362 if (clone_info->columns == cache_info->columns)
1363 (void) CopyMagickMemory(clone_info->pixels,cache_info->pixels,length*rows);
1364 else
1365 {
1366 source_pixels=cache_info->pixels+cache_info->columns*rows;
1367 pixels=clone_info->pixels+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001368 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001369 {
1370 source_pixels-=cache_info->columns;
1371 pixels-=clone_info->columns;
1372 (void) CopyMagickMemory(pixels,source_pixels,length);
1373 }
1374 if (clone_info->columns > cache_info->columns)
1375 {
1376 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1377 pixels=clone_info->pixels+clone_info->columns*rows+
1378 cache_info->columns;
cristybb503372010-05-27 20:51:26 +00001379 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001380 {
1381 pixels-=clone_info->columns;
1382 (void) ResetMagickMemory(pixels,0,length);
1383 }
1384 }
1385 }
1386 return(MagickTrue);
1387}
1388
1389static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1390 CacheInfo *cache_info,ExceptionInfo *exception)
1391{
1392 if ((clone_info->type != DiskCache) && (cache_info->type != DiskCache))
1393 return(CloneMemoryToMemoryPixelCache(clone_info,cache_info,exception));
1394 if ((clone_info->type == DiskCache) && (cache_info->type == DiskCache))
1395 return(CloneDiskToDiskPixelCache(clone_info,cache_info,exception));
1396 if (cache_info->type == DiskCache)
1397 return(CloneDiskToMemoryPixelCache(clone_info,cache_info,exception));
1398 return(CloneMemoryToDiskPixelCache(clone_info,cache_info,exception));
1399}
1400
1401/*
1402%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1403% %
1404% %
1405% %
1406+ C l o n e P i x e l C a c h e M e t h o d s %
1407% %
1408% %
1409% %
1410%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1411%
1412% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1413% another.
1414%
1415% The format of the ClonePixelCacheMethods() method is:
1416%
1417% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1418%
1419% A description of each parameter follows:
1420%
1421% o clone: Specifies a pointer to a Cache structure.
1422%
1423% o cache: the pixel cache.
1424%
1425*/
1426MagickExport void ClonePixelCacheMethods(Cache clone,const Cache cache)
1427{
1428 CacheInfo
1429 *cache_info,
1430 *source_info;
1431
1432 assert(clone != (Cache) NULL);
1433 source_info=(CacheInfo *) clone;
1434 assert(source_info->signature == MagickSignature);
1435 if (source_info->debug != MagickFalse)
1436 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1437 source_info->filename);
1438 assert(cache != (Cache) NULL);
1439 cache_info=(CacheInfo *) cache;
1440 assert(cache_info->signature == MagickSignature);
1441 source_info->methods=cache_info->methods;
1442}
1443
1444/*
1445%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1446% %
1447% %
1448% %
1449+ D e s t r o y I m a g e P i x e l C a c h e %
1450% %
1451% %
1452% %
1453%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1454%
1455% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1456%
1457% The format of the DestroyImagePixelCache() method is:
1458%
1459% void DestroyImagePixelCache(Image *image)
1460%
1461% A description of each parameter follows:
1462%
1463% o image: the image.
1464%
1465*/
1466static void DestroyImagePixelCache(Image *image)
1467{
1468 assert(image != (Image *) NULL);
1469 assert(image->signature == MagickSignature);
1470 if (image->debug != MagickFalse)
1471 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1472 if (image->cache == (void *) NULL)
1473 return;
1474 image->cache=DestroyPixelCache(image->cache);
1475}
1476
1477/*
1478%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1479% %
1480% %
1481% %
1482+ D e s t r o y I m a g e P i x e l s %
1483% %
1484% %
1485% %
1486%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1487%
1488% DestroyImagePixels() deallocates memory associated with the pixel cache.
1489%
1490% The format of the DestroyImagePixels() method is:
1491%
1492% void DestroyImagePixels(Image *image)
1493%
1494% A description of each parameter follows:
1495%
1496% o image: the image.
1497%
1498*/
1499MagickExport void DestroyImagePixels(Image *image)
1500{
1501 CacheInfo
1502 *cache_info;
1503
1504 assert(image != (const Image *) NULL);
1505 assert(image->signature == MagickSignature);
1506 if (image->debug != MagickFalse)
1507 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1508 assert(image->cache != (Cache) NULL);
1509 cache_info=(CacheInfo *) image->cache;
1510 assert(cache_info->signature == MagickSignature);
1511 if (cache_info->methods.destroy_pixel_handler == (DestroyPixelHandler) NULL)
1512 return;
1513 cache_info->methods.destroy_pixel_handler(image);
1514}
1515
1516/*
1517%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1518% %
1519% %
1520% %
1521+ D e s t r o y P i x e l C a c h e %
1522% %
1523% %
1524% %
1525%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1526%
1527% DestroyPixelCache() deallocates memory associated with the pixel cache.
1528%
1529% The format of the DestroyPixelCache() method is:
1530%
1531% Cache DestroyPixelCache(Cache cache)
1532%
1533% A description of each parameter follows:
1534%
1535% o cache: the pixel cache.
1536%
1537*/
1538
1539static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1540{
1541 switch (cache_info->type)
1542 {
1543 case MemoryCache:
1544 {
1545 if (cache_info->mapped == MagickFalse)
1546 cache_info->pixels=(PixelPacket *) RelinquishMagickMemory(
1547 cache_info->pixels);
1548 else
1549 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,
1550 (size_t) cache_info->length);
1551 RelinquishMagickResource(MemoryResource,cache_info->length);
1552 break;
1553 }
1554 case MapCache:
1555 {
1556 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,(size_t)
1557 cache_info->length);
1558 RelinquishMagickResource(MapResource,cache_info->length);
1559 }
1560 case DiskCache:
1561 {
1562 if (cache_info->file != -1)
1563 (void) ClosePixelCacheOnDisk(cache_info);
1564 RelinquishMagickResource(DiskResource,cache_info->length);
1565 break;
1566 }
1567 default:
1568 break;
1569 }
1570 cache_info->type=UndefinedCache;
1571 cache_info->mapped=MagickFalse;
1572 cache_info->indexes=(IndexPacket *) NULL;
1573}
1574
1575MagickExport Cache DestroyPixelCache(Cache cache)
1576{
1577 CacheInfo
1578 *cache_info;
1579
cristy3ed852e2009-09-05 21:47:34 +00001580 assert(cache != (Cache) NULL);
1581 cache_info=(CacheInfo *) cache;
1582 assert(cache_info->signature == MagickSignature);
1583 if (cache_info->debug != MagickFalse)
1584 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1585 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001586 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001587 cache_info->reference_count--;
1588 if (cache_info->reference_count != 0)
1589 {
cristyf84a1932010-01-03 18:00:18 +00001590 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001591 return((Cache) NULL);
1592 }
cristyf84a1932010-01-03 18:00:18 +00001593 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001594 if (cache_resources != (SplayTreeInfo *) NULL)
1595 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
cristy5b8de732009-09-10 23:50:40 +00001596 if (cache_info->debug != MagickFalse)
1597 {
1598 char
1599 message[MaxTextExtent];
1600
1601 (void) FormatMagickString(message,MaxTextExtent,"destroy %s",
1602 cache_info->filename);
1603 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1604 }
cristyc2e1bdd2009-09-10 23:43:34 +00001605 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1606 (cache_info->type != DiskCache)))
1607 RelinquishPixelCachePixels(cache_info);
1608 else
1609 {
1610 RelinquishPixelCachePixels(cache_info);
1611 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1612 }
cristy3ed852e2009-09-05 21:47:34 +00001613 *cache_info->cache_filename='\0';
1614 if (cache_info->nexus_info != (NexusInfo **) NULL)
1615 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1616 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001617 if (cache_info->random_info != (RandomInfo *) NULL)
1618 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001619 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1620 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1621 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1622 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001623 cache_info->signature=(~MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001624 cache_info=(CacheInfo *) RelinquishAlignedMemory(cache_info);
1625 cache=(Cache) NULL;
1626 return(cache);
1627}
1628
1629/*
1630%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1631% %
1632% %
1633% %
1634+ D e s t r o y P i x e l C a c h e N e x u s %
1635% %
1636% %
1637% %
1638%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1639%
1640% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1641%
1642% The format of the DestroyPixelCacheNexus() method is:
1643%
1644% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001645% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001646%
1647% A description of each parameter follows:
1648%
1649% o nexus_info: the nexus to destroy.
1650%
1651% o number_threads: the number of nexus threads.
1652%
1653*/
1654
1655static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1656{
1657 if (nexus_info->mapped == MagickFalse)
1658 (void) RelinquishMagickMemory(nexus_info->cache);
1659 else
1660 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1661 nexus_info->cache=(PixelPacket *) NULL;
1662 nexus_info->pixels=(PixelPacket *) NULL;
1663 nexus_info->indexes=(IndexPacket *) NULL;
1664 nexus_info->length=0;
1665 nexus_info->mapped=MagickFalse;
1666}
1667
1668MagickExport NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001669 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001670{
cristybb503372010-05-27 20:51:26 +00001671 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001672 i;
1673
1674 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001675 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001676 {
1677 if (nexus_info[i]->cache != (PixelPacket *) NULL)
1678 RelinquishCacheNexusPixels(nexus_info[i]);
1679 nexus_info[i]->signature=(~MagickSignature);
1680 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
1681 }
1682 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
1683 return(nexus_info);
1684}
1685
1686/*
1687%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1688% %
1689% %
1690% %
cristy3ed852e2009-09-05 21:47:34 +00001691+ 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 %
1692% %
1693% %
1694% %
1695%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1696%
1697% GetAuthenticIndexesFromCache() returns the indexes associated with the last
1698% call to QueueAuthenticPixelsCache() or GetAuthenticPixelsCache().
1699%
1700% The format of the GetAuthenticIndexesFromCache() method is:
1701%
1702% IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1703%
1704% A description of each parameter follows:
1705%
1706% o image: the image.
1707%
1708*/
1709static IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1710{
1711 CacheInfo
1712 *cache_info;
1713
1714 IndexPacket
1715 *indexes;
1716
cristy6ebe97c2010-07-03 01:17:28 +00001717 int
cristy3ed852e2009-09-05 21:47:34 +00001718 id;
1719
cristy3ed852e2009-09-05 21:47:34 +00001720 cache_info=(CacheInfo *) image->cache;
1721 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00001722 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001723 indexes=GetPixelCacheNexusIndexes(image->cache,cache_info->nexus_info[id]);
1724 return(indexes);
1725}
1726
1727/*
1728%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1729% %
1730% %
1731% %
1732% G e t A u t h e n t i c I n d e x Q u e u e %
1733% %
1734% %
1735% %
1736%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1737%
1738% GetAuthenticIndexQueue() returns the authentic black channel or the colormap
1739% indexes associated with the last call to QueueAuthenticPixels() or
1740% GetVirtualPixels(). NULL is returned if the black channel or colormap
1741% indexes are not available.
1742%
1743% The format of the GetAuthenticIndexQueue() method is:
1744%
1745% IndexPacket *GetAuthenticIndexQueue(const Image *image)
1746%
1747% A description of each parameter follows:
1748%
1749% o image: the image.
1750%
1751*/
1752MagickExport IndexPacket *GetAuthenticIndexQueue(const Image *image)
1753{
1754 CacheInfo
1755 *cache_info;
1756
1757 assert(image != (const Image *) NULL);
1758 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001759 assert(image->cache != (Cache) NULL);
1760 cache_info=(CacheInfo *) image->cache;
1761 assert(cache_info->signature == MagickSignature);
1762 if (cache_info->methods.get_authentic_indexes_from_handler ==
1763 (GetAuthenticIndexesFromHandler) NULL)
1764 return((IndexPacket *) NULL);
1765 return(cache_info->methods.get_authentic_indexes_from_handler(image));
1766}
1767
1768/*
1769%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1770% %
1771% %
1772% %
1773+ 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 %
1774% %
1775% %
1776% %
1777%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1778%
1779% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1780% disk pixel cache as defined by the geometry parameters. A pointer to the
1781% pixels is returned if the pixels are transferred, otherwise a NULL is
1782% returned.
1783%
1784% The format of the GetAuthenticPixelCacheNexus() method is:
1785%
cristybb503372010-05-27 20:51:26 +00001786% PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1787% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001788% NexusInfo *nexus_info,ExceptionInfo *exception)
1789%
1790% A description of each parameter follows:
1791%
1792% o image: the image.
1793%
1794% o x,y,columns,rows: These values define the perimeter of a region of
1795% pixels.
1796%
1797% o nexus_info: the cache nexus to return.
1798%
1799% o exception: return any errors or warnings in this structure.
1800%
1801*/
1802
1803static inline MagickBooleanType IsNexusInCore(const CacheInfo *cache_info,
1804 NexusInfo *nexus_info)
1805{
1806 MagickOffsetType
1807 offset;
1808
cristy73724512010-04-12 14:43:14 +00001809 if (cache_info->type == PingCache)
1810 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001811 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1812 nexus_info->region.x;
1813 if (nexus_info->pixels != (cache_info->pixels+offset))
1814 return(MagickFalse);
1815 return(MagickTrue);
1816}
1817
cristye076a6e2010-08-15 19:59:43 +00001818MagickExport PixelPacket *GetAuthenticPixelCacheNexus(Image *image,
1819 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001820 NexusInfo *nexus_info,ExceptionInfo *exception)
1821{
1822 CacheInfo
1823 *cache_info;
1824
1825 PixelPacket
1826 *pixels;
1827
1828 /*
1829 Transfer pixels from the cache.
1830 */
1831 assert(image != (Image *) NULL);
1832 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001833 pixels=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
1834 if (pixels == (PixelPacket *) NULL)
1835 return((PixelPacket *) NULL);
1836 cache_info=(CacheInfo *) image->cache;
1837 assert(cache_info->signature == MagickSignature);
1838 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
1839 return(pixels);
1840 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1841 return((PixelPacket *) NULL);
1842 if (cache_info->active_index_channel != MagickFalse)
1843 if (ReadPixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse)
1844 return((PixelPacket *) NULL);
1845 return(pixels);
1846}
1847
1848/*
1849%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1850% %
1851% %
1852% %
1853+ 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 %
1854% %
1855% %
1856% %
1857%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1858%
1859% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1860% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1861%
1862% The format of the GetAuthenticPixelsFromCache() method is:
1863%
1864% PixelPacket *GetAuthenticPixelsFromCache(const Image image)
1865%
1866% A description of each parameter follows:
1867%
1868% o image: the image.
1869%
1870*/
1871static PixelPacket *GetAuthenticPixelsFromCache(const Image *image)
1872{
1873 CacheInfo
1874 *cache_info;
1875
cristy6ebe97c2010-07-03 01:17:28 +00001876 int
cristy3ed852e2009-09-05 21:47:34 +00001877 id;
1878
1879 PixelPacket
1880 *pixels;
1881
cristy3ed852e2009-09-05 21:47:34 +00001882 cache_info=(CacheInfo *) image->cache;
1883 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00001884 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001885 pixels=GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]);
1886 return(pixels);
1887}
1888
1889/*
1890%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1891% %
1892% %
1893% %
1894% G e t A u t h e n t i c P i x e l Q u e u e %
1895% %
1896% %
1897% %
1898%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1899%
1900% GetAuthenticPixelQueue() returns the authentic pixels associated with the
1901% last call to QueueAuthenticPixels() or GetAuthenticPixels().
1902%
1903% The format of the GetAuthenticPixelQueue() method is:
1904%
1905% PixelPacket *GetAuthenticPixelQueue(const Image image)
1906%
1907% A description of each parameter follows:
1908%
1909% o image: the image.
1910%
1911*/
1912MagickExport PixelPacket *GetAuthenticPixelQueue(const Image *image)
1913{
1914 CacheInfo
1915 *cache_info;
1916
1917 assert(image != (const Image *) NULL);
1918 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001919 assert(image->cache != (Cache) NULL);
1920 cache_info=(CacheInfo *) image->cache;
1921 assert(cache_info->signature == MagickSignature);
1922 if (cache_info->methods.get_authentic_pixels_from_handler ==
1923 (GetAuthenticPixelsFromHandler) NULL)
1924 return((PixelPacket *) NULL);
1925 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1926}
1927
1928/*
1929%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1930% %
1931% %
1932% %
1933% G e t A u t h e n t i c P i x e l s %
1934% %
1935% %
1936% %
1937%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1938%
1939% GetAuthenticPixels() obtains a pixel region for read/write access. If the
1940% region is successfully accessed, a pointer to a PixelPacket array
1941% representing the region is returned, otherwise NULL is returned.
1942%
1943% The returned pointer may point to a temporary working copy of the pixels
1944% or it may point to the original pixels in memory. Performance is maximized
1945% if the selected region is part of one row, or one or more full rows, since
1946% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001947% if the image is in memory, or in a memory-mapped file. The returned pointer
1948% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001949%
1950% Pixels accessed via the returned pointer represent a simple array of type
1951% PixelPacket. If the image type is CMYK or if the storage class is
1952% PseduoClass, call GetAuthenticIndexQueue() after invoking
1953% GetAuthenticPixels() to obtain the black color component or colormap indexes
1954% (of type IndexPacket) corresponding to the region. Once the PixelPacket
1955% (and/or IndexPacket) array has been updated, the changes must be saved back
1956% to the underlying image using SyncAuthenticPixels() or they may be lost.
1957%
1958% The format of the GetAuthenticPixels() method is:
1959%
cristy5f959472010-05-27 22:19:46 +00001960% PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1961% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001962% ExceptionInfo *exception)
1963%
1964% A description of each parameter follows:
1965%
1966% o image: the image.
1967%
1968% o x,y,columns,rows: These values define the perimeter of a region of
1969% pixels.
1970%
1971% o exception: return any errors or warnings in this structure.
1972%
1973*/
cristybb503372010-05-27 20:51:26 +00001974MagickExport PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1975 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001976 ExceptionInfo *exception)
1977{
1978 CacheInfo
1979 *cache_info;
1980
1981 PixelPacket
1982 *pixels;
1983
1984 assert(image != (Image *) NULL);
1985 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001986 assert(image->cache != (Cache) NULL);
1987 cache_info=(CacheInfo *) image->cache;
1988 assert(cache_info->signature == MagickSignature);
1989 if (cache_info->methods.get_authentic_pixels_handler ==
1990 (GetAuthenticPixelsHandler) NULL)
1991 return((PixelPacket *) NULL);
1992 pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1993 rows,exception);
1994 return(pixels);
1995}
1996
1997/*
1998%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1999% %
2000% %
2001% %
2002+ G e t A u t h e n t i c P i x e l s C a c h e %
2003% %
2004% %
2005% %
2006%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2007%
2008% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
2009% as defined by the geometry parameters. A pointer to the pixels is returned
2010% if the pixels are transferred, otherwise a NULL is returned.
2011%
2012% The format of the GetAuthenticPixelsCache() method is:
2013%
cristybb503372010-05-27 20:51:26 +00002014% PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
2015% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00002016% ExceptionInfo *exception)
2017%
2018% A description of each parameter follows:
2019%
2020% o image: the image.
2021%
2022% o x,y,columns,rows: These values define the perimeter of a region of
2023% pixels.
2024%
2025% o exception: return any errors or warnings in this structure.
2026%
2027*/
cristybb503372010-05-27 20:51:26 +00002028static PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
2029 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00002030 ExceptionInfo *exception)
2031{
2032 CacheInfo
2033 *cache_info;
2034
cristy6ebe97c2010-07-03 01:17:28 +00002035 int
cristy3ed852e2009-09-05 21:47:34 +00002036 id;
2037
2038 PixelPacket
2039 *pixels;
2040
cristy77ff0282010-09-13 00:51:10 +00002041 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00002042 if (cache_info == (Cache) NULL)
2043 return((PixelPacket *) NULL);
2044 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00002045 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00002046 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
2047 cache_info->nexus_info[id],exception);
2048 return(pixels);
2049}
2050
2051/*
2052%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2053% %
2054% %
2055% %
2056+ G e t I m a g e E x t e n t %
2057% %
2058% %
2059% %
2060%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2061%
2062% GetImageExtent() returns the extent of the pixels associated with the
2063% last call to QueueAuthenticPixels() or GetAuthenticPixels().
2064%
2065% The format of the GetImageExtent() method is:
2066%
2067% MagickSizeType GetImageExtent(const Image *image)
2068%
2069% A description of each parameter follows:
2070%
2071% o image: the image.
2072%
2073*/
2074MagickExport MagickSizeType GetImageExtent(const Image *image)
2075{
2076 CacheInfo
2077 *cache_info;
2078
cristy6ebe97c2010-07-03 01:17:28 +00002079 int
cristy3ed852e2009-09-05 21:47:34 +00002080 id;
2081
2082 MagickSizeType
2083 extent;
2084
2085 assert(image != (Image *) NULL);
2086 assert(image->signature == MagickSignature);
2087 if (image->debug != MagickFalse)
2088 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2089 assert(image->cache != (Cache) NULL);
2090 cache_info=(CacheInfo *) image->cache;
2091 assert(cache_info->signature == MagickSignature);
2092 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00002093 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00002094 extent=GetPixelCacheNexusExtent(image->cache,cache_info->nexus_info[id]);
2095 return(extent);
2096}
2097
2098/*
2099%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2100% %
2101% %
2102% %
2103+ G e t I m a g e P i x e l C a c h e %
2104% %
2105% %
2106% %
2107%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2108%
2109% GetImagePixelCache() ensures that there is only a single reference to the
2110% pixel cache to be modified, updating the provided cache pointer to point to
2111% a clone of the original pixel cache if necessary.
2112%
2113% The format of the GetImagePixelCache method is:
2114%
2115% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2116% ExceptionInfo *exception)
2117%
2118% A description of each parameter follows:
2119%
2120% o image: the image.
2121%
2122% o clone: any value other than MagickFalse clones the cache pixels.
2123%
2124% o exception: return any errors or warnings in this structure.
2125%
2126*/
cristy3ed852e2009-09-05 21:47:34 +00002127static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
2128{
2129 CacheInfo
2130 *cache_info;
2131
2132 /*
2133 Does the image match the pixel cache morphology?
2134 */
2135 cache_info=(CacheInfo *) image->cache;
2136 if ((image->storage_class != cache_info->storage_class) ||
2137 (image->colorspace != cache_info->colorspace) ||
2138 (image->columns != cache_info->columns) ||
2139 (image->rows != cache_info->rows) ||
2140 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2141 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2142 return(MagickFalse);
2143 return(MagickTrue);
2144}
2145
cristy77ff0282010-09-13 00:51:10 +00002146static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2147 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002148{
2149 CacheInfo
2150 *cache_info;
2151
cristy3ed852e2009-09-05 21:47:34 +00002152 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00002153 destroy,
cristy3ed852e2009-09-05 21:47:34 +00002154 status;
2155
cristy50a10922010-02-15 18:35:25 +00002156 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00002157 cpu_throttle = 0,
2158 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00002159 time_limit = 0;
2160
cristy1ea34962010-07-01 19:49:21 +00002161 static time_t
cristya21afde2010-07-02 00:45:40 +00002162 cache_genesis = 0;
cristy1ea34962010-07-01 19:49:21 +00002163
cristyc4f9f132010-03-04 18:50:01 +00002164 status=MagickTrue;
2165 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00002166 if (cpu_throttle == 0)
2167 {
2168 char
2169 *limit;
2170
2171 /*
2172 Set CPU throttle in milleseconds.
2173 */
2174 cpu_throttle=MagickResourceInfinity;
2175 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2176 if (limit == (char *) NULL)
2177 limit=GetPolicyValue("throttle");
2178 if (limit != (char *) NULL)
2179 {
2180 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2181 limit=DestroyString(limit);
2182 }
2183 }
2184 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2185 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00002186 if (time_limit == 0)
2187 {
cristy6ebe97c2010-07-03 01:17:28 +00002188 /*
2189 Set the exire time in seconds.
2190 */
cristy1ea34962010-07-01 19:49:21 +00002191 time_limit=GetMagickResourceLimit(TimeResource);
cristya21afde2010-07-02 00:45:40 +00002192 cache_genesis=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00002193 }
2194 if ((time_limit != MagickResourceInfinity) &&
cristya21afde2010-07-02 00:45:40 +00002195 ((MagickSizeType) (time((time_t *) NULL)-cache_genesis) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00002196 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00002197 assert(image->cache != (Cache) NULL);
2198 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002199 destroy=MagickFalse;
cristy01b7eb02009-09-10 23:10:14 +00002200 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002201 {
cristyaaa0cb62010-02-15 17:47:27 +00002202 LockSemaphoreInfo(cache_info->semaphore);
2203 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002204 {
cristyaaa0cb62010-02-15 17:47:27 +00002205 Image
2206 clone_image;
2207
2208 CacheInfo
2209 *clone_info;
2210
2211 /*
2212 Clone pixel cache.
2213 */
2214 clone_image=(*image);
cristy93505cf2010-08-10 21:37:49 +00002215 clone_image.semaphore=AllocateSemaphoreInfo();
2216 clone_image.reference_count=1;
cristyaaa0cb62010-02-15 17:47:27 +00002217 clone_image.cache=ClonePixelCache(cache_info);
2218 clone_info=(CacheInfo *) clone_image.cache;
2219 status=ClonePixelCacheNexus(cache_info,clone_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002220 if (status != MagickFalse)
2221 {
cristyaaa0cb62010-02-15 17:47:27 +00002222 status=OpenPixelCache(&clone_image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00002223 if (status != MagickFalse)
2224 {
cristyaaa0cb62010-02-15 17:47:27 +00002225 if (clone != MagickFalse)
2226 status=ClonePixelCachePixels(clone_info,cache_info,
2227 exception);
2228 if (status != MagickFalse)
2229 {
2230 destroy=MagickTrue;
2231 image->cache=clone_image.cache;
2232 }
cristy3ed852e2009-09-05 21:47:34 +00002233 }
2234 }
cristy93505cf2010-08-10 21:37:49 +00002235 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002236 }
cristyaaa0cb62010-02-15 17:47:27 +00002237 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002238 }
cristy4320e0e2009-09-10 15:00:08 +00002239 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002240 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002241 if (status != MagickFalse)
2242 {
2243 /*
2244 Ensure the image matches the pixel cache morphology.
2245 */
2246 image->taint=MagickTrue;
2247 image->type=UndefinedType;
cristydd438462010-05-06 13:44:04 +00002248 if (image->colorspace == GRAYColorspace)
2249 image->colorspace=RGBColorspace;
cristy3ed852e2009-09-05 21:47:34 +00002250 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2251 status=OpenPixelCache(image,IOMode,exception);
2252 }
cristyf84a1932010-01-03 18:00:18 +00002253 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002254 if (status == MagickFalse)
2255 return((Cache) NULL);
2256 return(image->cache);
2257}
2258
2259/*
2260%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2261% %
2262% %
2263% %
2264% G e t O n e A u t h e n t i c P i x e l %
2265% %
2266% %
2267% %
2268%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2269%
2270% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2271% location. The image background color is returned if an error occurs.
2272%
2273% The format of the GetOneAuthenticPixel() method is:
2274%
cristybb503372010-05-27 20:51:26 +00002275% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2276% const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002277%
2278% A description of each parameter follows:
2279%
2280% o image: the image.
2281%
2282% o x,y: These values define the location of the pixel to return.
2283%
2284% o pixel: return a pixel at the specified (x,y) location.
2285%
2286% o exception: return any errors or warnings in this structure.
2287%
2288*/
cristyacbbb7c2010-06-30 18:56:48 +00002289MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2290 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002291{
2292 CacheInfo
2293 *cache_info;
2294
2295 GetOneAuthenticPixelFromHandler
2296 get_one_authentic_pixel_from_handler;
2297
2298 MagickBooleanType
2299 status;
2300
2301 assert(image != (Image *) NULL);
2302 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002303 assert(image->cache != (Cache) NULL);
2304 cache_info=(CacheInfo *) image->cache;
2305 assert(cache_info->signature == MagickSignature);
2306 *pixel=image->background_color;
2307 get_one_authentic_pixel_from_handler=
2308 cache_info->methods.get_one_authentic_pixel_from_handler;
2309 if (get_one_authentic_pixel_from_handler ==
2310 (GetOneAuthenticPixelFromHandler) NULL)
2311 return(MagickFalse);
2312 status=cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2313 pixel,exception);
2314 return(status);
2315}
2316
2317/*
2318%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2319% %
2320% %
2321% %
2322+ 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 %
2323% %
2324% %
2325% %
2326%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2327%
2328% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2329% location. The image background color is returned if an error occurs.
2330%
2331% The format of the GetOneAuthenticPixelFromCache() method is:
2332%
2333% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy5f959472010-05-27 22:19:46 +00002334% const ssize_t x,const ssize_t y,PixelPacket *pixel,
2335% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002336%
2337% A description of each parameter follows:
2338%
2339% o image: the image.
2340%
2341% o x,y: These values define the location of the pixel to return.
2342%
2343% o pixel: return a pixel at the specified (x,y) location.
2344%
2345% o exception: return any errors or warnings in this structure.
2346%
2347*/
2348static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristybb503372010-05-27 20:51:26 +00002349 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002350{
2351 PixelPacket
2352 *pixels;
2353
cristy3ed852e2009-09-05 21:47:34 +00002354 *pixel=image->background_color;
2355 pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2356 if (pixels == (PixelPacket *) NULL)
2357 return(MagickFalse);
2358 *pixel=(*pixels);
2359 return(MagickTrue);
2360}
2361
2362/*
2363%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2364% %
2365% %
2366% %
2367% G e t O n e V i r t u a l M a g i c k P i x e l %
2368% %
2369% %
2370% %
2371%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2372%
2373% GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2374% location. The image background color is returned if an error occurs. If
2375% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2376%
2377% The format of the GetOneVirtualMagickPixel() method is:
2378%
2379% MagickBooleanType GetOneVirtualMagickPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002380% const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
cristy3ed852e2009-09-05 21:47:34 +00002381% ExceptionInfo exception)
2382%
2383% A description of each parameter follows:
2384%
2385% o image: the image.
2386%
2387% o x,y: these values define the location of the pixel to return.
2388%
2389% o pixel: return a pixel at the specified (x,y) location.
2390%
2391% o exception: return any errors or warnings in this structure.
2392%
2393*/
2394MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
cristyacbbb7c2010-06-30 18:56:48 +00002395 const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
2396 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002397{
2398 CacheInfo
2399 *cache_info;
2400
2401 register const IndexPacket
2402 *indexes;
2403
2404 register const PixelPacket
2405 *p;
2406
2407 assert(image != (const Image *) NULL);
2408 assert(image->signature == MagickSignature);
2409 assert(image->cache != (Cache) NULL);
2410 cache_info=(CacheInfo *) image->cache;
2411 assert(cache_info->signature == MagickSignature);
2412 GetMagickPixelPacket(image,pixel);
2413 p=GetVirtualPixelCache(image,GetPixelCacheVirtualMethod(image),x,y,1,1,
2414 exception);
2415 if (p == (const PixelPacket *) NULL)
2416 return(MagickFalse);
2417 indexes=GetVirtualIndexQueue(image);
2418 SetMagickPixelPacket(image,p,indexes,pixel);
2419 return(MagickTrue);
2420}
2421
2422/*
2423%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2424% %
2425% %
2426% %
2427% G e t O n e V i r t u a l M e t h o d P i x e l %
2428% %
2429% %
2430% %
2431%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2432%
2433% GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2434% location as defined by specified pixel method. The image background color
2435% is returned if an error occurs. If you plan to modify the pixel, use
2436% GetOneAuthenticPixel() instead.
2437%
2438% The format of the GetOneVirtualMethodPixel() method is:
2439%
2440% MagickBooleanType GetOneVirtualMethodPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002441% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2442% const ssize_t y,Pixelpacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002443%
2444% A description of each parameter follows:
2445%
2446% o image: the image.
2447%
2448% o virtual_pixel_method: the virtual pixel method.
2449%
2450% o x,y: These values define the location of the pixel to return.
2451%
2452% o pixel: return a pixel at the specified (x,y) location.
2453%
2454% o exception: return any errors or warnings in this structure.
2455%
2456*/
2457MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002458 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002459 PixelPacket *pixel,ExceptionInfo *exception)
2460{
2461 GetOneVirtualPixelFromHandler
2462 get_one_virtual_pixel_from_handler;
2463
2464 CacheInfo
2465 *cache_info;
2466
2467 MagickBooleanType
2468 status;
2469
2470 assert(image != (const Image *) NULL);
2471 assert(image->signature == MagickSignature);
2472 assert(image->cache != (Cache) NULL);
2473 cache_info=(CacheInfo *) image->cache;
2474 assert(cache_info->signature == MagickSignature);
2475 *pixel=image->background_color;
2476 get_one_virtual_pixel_from_handler=
2477 cache_info->methods.get_one_virtual_pixel_from_handler;
2478 if (get_one_virtual_pixel_from_handler ==
2479 (GetOneVirtualPixelFromHandler) NULL)
2480 return(MagickFalse);
2481 status=get_one_virtual_pixel_from_handler(image,virtual_pixel_method,x,y,
2482 pixel,exception);
2483 return(status);
2484}
2485
2486/*
2487%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2488% %
2489% %
2490% %
2491% G e t O n e V i r t u a l P i x e l %
2492% %
2493% %
2494% %
2495%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2496%
2497% GetOneVirtualPixel() returns a single virtual pixel at the specified
2498% (x,y) location. The image background color is returned if an error occurs.
2499% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2500%
2501% The format of the GetOneVirtualPixel() method is:
2502%
cristybb503372010-05-27 20:51:26 +00002503% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2504% const ssize_t y,PixelPacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002505%
2506% A description of each parameter follows:
2507%
2508% o image: the image.
2509%
2510% o x,y: These values define the location of the pixel to return.
2511%
2512% o pixel: return a pixel at the specified (x,y) location.
2513%
2514% o exception: return any errors or warnings in this structure.
2515%
2516*/
2517MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002518 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002519{
2520 GetOneVirtualPixelFromHandler
2521 get_one_virtual_pixel_from_handler;
2522
2523 CacheInfo
2524 *cache_info;
2525
2526 MagickBooleanType
2527 status;
2528
2529 assert(image != (const Image *) NULL);
2530 assert(image->signature == MagickSignature);
2531 assert(image->cache != (Cache) NULL);
2532 cache_info=(CacheInfo *) image->cache;
2533 assert(cache_info->signature == MagickSignature);
2534 *pixel=image->background_color;
2535 get_one_virtual_pixel_from_handler=
2536 cache_info->methods.get_one_virtual_pixel_from_handler;
2537 if (get_one_virtual_pixel_from_handler ==
2538 (GetOneVirtualPixelFromHandler) NULL)
2539 return(MagickFalse);
2540 status=get_one_virtual_pixel_from_handler(image,GetPixelCacheVirtualMethod(
2541 image),x,y,pixel,exception);
2542 return(status);
2543}
2544
2545/*
2546%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2547% %
2548% %
2549% %
2550+ 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 %
2551% %
2552% %
2553% %
2554%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2555%
2556% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2557% specified (x,y) location. The image background color is returned if an
2558% error occurs.
2559%
2560% The format of the GetOneVirtualPixelFromCache() method is:
2561%
2562% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristybb503372010-05-27 20:51:26 +00002563% const VirtualPixelPacket method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002564% PixelPacket *pixel,ExceptionInfo *exception)
2565%
2566% A description of each parameter follows:
2567%
2568% o image: the image.
2569%
2570% o virtual_pixel_method: the virtual pixel method.
2571%
2572% o x,y: These values define the location of the pixel to return.
2573%
2574% o pixel: return a pixel at the specified (x,y) location.
2575%
2576% o exception: return any errors or warnings in this structure.
2577%
2578*/
2579static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002580 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002581 PixelPacket *pixel,ExceptionInfo *exception)
2582{
2583 const PixelPacket
2584 *pixels;
2585
2586 *pixel=image->background_color;
2587 pixels=GetVirtualPixelCache(image,virtual_pixel_method,x,y,1UL,1UL,exception);
2588 if (pixels == (const PixelPacket *) NULL)
2589 return(MagickFalse);
2590 *pixel=(*pixels);
2591 return(MagickTrue);
2592}
2593
2594/*
2595%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2596% %
2597% %
2598% %
2599+ G e t P i x e l C a c h e C o l o r s p a c e %
2600% %
2601% %
2602% %
2603%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2604%
2605% GetPixelCacheColorspace() returns the class type of the pixel cache.
2606%
2607% The format of the GetPixelCacheColorspace() method is:
2608%
2609% Colorspace GetPixelCacheColorspace(Cache cache)
2610%
2611% A description of each parameter follows:
2612%
2613% o cache: the pixel cache.
2614%
2615*/
2616MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
2617{
2618 CacheInfo
2619 *cache_info;
2620
2621 assert(cache != (Cache) NULL);
2622 cache_info=(CacheInfo *) cache;
2623 assert(cache_info->signature == MagickSignature);
2624 if (cache_info->debug != MagickFalse)
2625 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2626 cache_info->filename);
2627 return(cache_info->colorspace);
2628}
2629
2630/*
2631%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2632% %
2633% %
2634% %
2635+ G e t P i x e l C a c h e M e t h o d s %
2636% %
2637% %
2638% %
2639%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2640%
2641% GetPixelCacheMethods() initializes the CacheMethods structure.
2642%
2643% The format of the GetPixelCacheMethods() method is:
2644%
2645% void GetPixelCacheMethods(CacheMethods *cache_methods)
2646%
2647% A description of each parameter follows:
2648%
2649% o cache_methods: Specifies a pointer to a CacheMethods structure.
2650%
2651*/
2652MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
2653{
2654 assert(cache_methods != (CacheMethods *) NULL);
2655 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2656 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2657 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2658 cache_methods->get_virtual_indexes_from_handler=GetVirtualIndexesFromCache;
2659 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2660 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2661 cache_methods->get_authentic_indexes_from_handler=
2662 GetAuthenticIndexesFromCache;
2663 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2664 cache_methods->get_one_authentic_pixel_from_handler=
2665 GetOneAuthenticPixelFromCache;
2666 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2667 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2668 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2669}
2670
2671/*
2672%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2673% %
2674% %
2675% %
2676+ G e t P i x e l C a c h e N e x u s E x t e n t %
2677% %
2678% %
2679% %
2680%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2681%
2682% GetPixelCacheNexusExtent() returns the extent of the pixels associated with
2683% the last call to SetPixelCacheNexusPixels() or GetPixelCacheNexusPixels().
2684%
2685% The format of the GetPixelCacheNexusExtent() method is:
2686%
2687% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2688% NexusInfo *nexus_info)
2689%
2690% A description of each parameter follows:
2691%
2692% o nexus_info: the nexus info.
2693%
2694*/
2695MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2696 NexusInfo *nexus_info)
2697{
2698 CacheInfo
2699 *cache_info;
2700
2701 MagickSizeType
2702 extent;
2703
2704 if (cache == (Cache) NULL)
2705 return(0);
2706 cache_info=(CacheInfo *) cache;
2707 assert(cache_info->signature == MagickSignature);
2708 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2709 if (extent == 0)
2710 return((MagickSizeType) cache_info->columns*cache_info->rows);
2711 return(extent);
2712}
2713
2714/*
2715%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2716% %
2717% %
2718% %
2719+ 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 %
2720% %
2721% %
2722% %
2723%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2724%
2725% GetPixelCacheNexusIndexes() returns the indexes associated with the
2726% specified cache nexus.
2727%
2728% The format of the GetPixelCacheNexusIndexes() method is:
2729%
2730% IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2731% NexusInfo *nexus_info)
2732%
2733% A description of each parameter follows:
2734%
2735% o cache: the pixel cache.
2736%
2737% o nexus_info: the cache nexus to return the colormap indexes.
2738%
2739*/
2740MagickExport IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2741 NexusInfo *nexus_info)
2742{
2743 CacheInfo
2744 *cache_info;
2745
2746 if (cache == (Cache) NULL)
2747 return((IndexPacket *) NULL);
2748 cache_info=(CacheInfo *) cache;
2749 assert(cache_info->signature == MagickSignature);
2750 if (cache_info->storage_class == UndefinedClass)
2751 return((IndexPacket *) NULL);
2752 return(nexus_info->indexes);
2753}
2754
2755/*
2756%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2757% %
2758% %
2759% %
2760+ G e t P i x e l C a c h e N e x u s P i x e l s %
2761% %
2762% %
2763% %
2764%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2765%
2766% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2767% cache nexus.
2768%
2769% The format of the GetPixelCacheNexusPixels() method is:
2770%
2771% PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2772% NexusInfo *nexus_info)
2773%
2774% A description of each parameter follows:
2775%
2776% o cache: the pixel cache.
2777%
2778% o nexus_info: the cache nexus to return the pixels.
2779%
2780*/
2781MagickExport PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2782 NexusInfo *nexus_info)
2783{
2784 CacheInfo
2785 *cache_info;
2786
2787 if (cache == (Cache) NULL)
2788 return((PixelPacket *) NULL);
2789 cache_info=(CacheInfo *) cache;
2790 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002791 if (cache_info->storage_class == UndefinedClass)
2792 return((PixelPacket *) NULL);
2793 return(nexus_info->pixels);
2794}
2795
2796/*
2797%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2798% %
2799% %
2800% %
cristy056ba772010-01-02 23:33:54 +00002801+ G e t P i x e l C a c h e P i x e l s %
2802% %
2803% %
2804% %
2805%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2806%
2807% GetPixelCachePixels() returns the pixels associated with the specified image.
2808%
2809% The format of the GetPixelCachePixels() method is:
2810%
cristyf84a1932010-01-03 18:00:18 +00002811% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2812% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002813%
2814% A description of each parameter follows:
2815%
2816% o image: the image.
2817%
2818% o length: the pixel cache length.
2819%
cristyf84a1932010-01-03 18:00:18 +00002820% o exception: return any errors or warnings in this structure.
2821%
cristy056ba772010-01-02 23:33:54 +00002822*/
cristyf84a1932010-01-03 18:00:18 +00002823MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2824 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002825{
2826 CacheInfo
2827 *cache_info;
2828
2829 assert(image != (const Image *) NULL);
2830 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002831 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00002832 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002833 assert(cache_info->signature == MagickSignature);
2834 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002835 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002836 return((void *) NULL);
2837 *length=cache_info->length;
2838 return((void *) cache_info->pixels);
2839}
2840
2841/*
2842%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2843% %
2844% %
2845% %
cristyb32b90a2009-09-07 21:45:48 +00002846+ 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 +00002847% %
2848% %
2849% %
2850%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2851%
2852% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2853%
2854% The format of the GetPixelCacheStorageClass() method is:
2855%
2856% ClassType GetPixelCacheStorageClass(Cache cache)
2857%
2858% A description of each parameter follows:
2859%
2860% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2861%
2862% o cache: the pixel cache.
2863%
2864*/
2865MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
2866{
2867 CacheInfo
2868 *cache_info;
2869
2870 assert(cache != (Cache) NULL);
2871 cache_info=(CacheInfo *) cache;
2872 assert(cache_info->signature == MagickSignature);
2873 if (cache_info->debug != MagickFalse)
2874 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2875 cache_info->filename);
2876 return(cache_info->storage_class);
2877}
2878
2879/*
2880%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2881% %
2882% %
2883% %
cristyb32b90a2009-09-07 21:45:48 +00002884+ G e t P i x e l C a c h e T i l e S i z e %
2885% %
2886% %
2887% %
2888%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2889%
2890% GetPixelCacheTileSize() returns the pixel cache tile size.
2891%
2892% The format of the GetPixelCacheTileSize() method is:
2893%
cristybb503372010-05-27 20:51:26 +00002894% void GetPixelCacheTileSize(const Image *image,size_t *width,
2895% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002896%
2897% A description of each parameter follows:
2898%
2899% o image: the image.
2900%
2901% o width: the optimize cache tile width in pixels.
2902%
2903% o height: the optimize cache tile height in pixels.
2904%
2905*/
cristybb503372010-05-27 20:51:26 +00002906MagickExport void GetPixelCacheTileSize(const Image *image,size_t *width,
2907 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002908{
2909 CacheInfo
2910 *cache_info;
2911
2912 assert(image != (Image *) NULL);
2913 assert(image->signature == MagickSignature);
2914 if (image->debug != MagickFalse)
2915 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2916 assert(image->cache != (Cache) NULL);
2917 cache_info=(CacheInfo *) image->cache;
2918 assert(cache_info->signature == MagickSignature);
2919 *width=2048UL/sizeof(PixelPacket);
2920 if (GetPixelCacheType(image) == DiskCache)
cristydaa97692009-09-13 02:10:35 +00002921 *width=8192UL/sizeof(PixelPacket);
cristyb32b90a2009-09-07 21:45:48 +00002922 *height=(*width);
2923}
2924
2925/*
2926%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2927% %
2928% %
2929% %
2930+ G e t P i x e l C a c h e T y p e %
2931% %
2932% %
2933% %
2934%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2935%
2936% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2937%
2938% The format of the GetPixelCacheType() method is:
2939%
2940% CacheType GetPixelCacheType(const Image *image)
2941%
2942% A description of each parameter follows:
2943%
2944% o image: the image.
2945%
2946*/
2947MagickExport CacheType GetPixelCacheType(const Image *image)
2948{
2949 CacheInfo
2950 *cache_info;
2951
2952 assert(image != (Image *) NULL);
2953 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002954 assert(image->cache != (Cache) NULL);
2955 cache_info=(CacheInfo *) image->cache;
2956 assert(cache_info->signature == MagickSignature);
2957 return(cache_info->type);
2958}
2959
2960/*
2961%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2962% %
2963% %
2964% %
cristy3ed852e2009-09-05 21:47:34 +00002965+ 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 %
2966% %
2967% %
2968% %
2969%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2970%
2971% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2972% pixel cache. A virtual pixel is any pixel access that is outside the
2973% boundaries of the image cache.
2974%
2975% The format of the GetPixelCacheVirtualMethod() method is:
2976%
2977% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2978%
2979% A description of each parameter follows:
2980%
2981% o image: the image.
2982%
2983*/
2984MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2985{
2986 CacheInfo
2987 *cache_info;
2988
2989 assert(image != (Image *) NULL);
2990 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002991 assert(image->cache != (Cache) NULL);
2992 cache_info=(CacheInfo *) image->cache;
2993 assert(cache_info->signature == MagickSignature);
2994 return(cache_info->virtual_pixel_method);
2995}
2996
2997/*
2998%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2999% %
3000% %
3001% %
3002+ 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 %
3003% %
3004% %
3005% %
3006%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3007%
3008% GetVirtualIndexesFromCache() returns the indexes associated with the last
3009% call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3010%
3011% The format of the GetVirtualIndexesFromCache() method is:
3012%
3013% IndexPacket *GetVirtualIndexesFromCache(const Image *image)
3014%
3015% A description of each parameter follows:
3016%
3017% o image: the image.
3018%
3019*/
3020static const IndexPacket *GetVirtualIndexesFromCache(const Image *image)
3021{
3022 CacheInfo
3023 *cache_info;
3024
3025 const IndexPacket
3026 *indexes;
3027
cristy6ebe97c2010-07-03 01:17:28 +00003028 int
cristy3ed852e2009-09-05 21:47:34 +00003029 id;
3030
cristy3ed852e2009-09-05 21:47:34 +00003031 cache_info=(CacheInfo *) image->cache;
3032 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00003033 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00003034 indexes=GetVirtualIndexesFromNexus(image->cache,cache_info->nexus_info[id]);
3035 return(indexes);
3036}
3037
3038/*
3039%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3040% %
3041% %
3042% %
3043+ 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 %
3044% %
3045% %
3046% %
3047%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3048%
3049% GetVirtualIndexesFromNexus() returns the indexes associated with the
3050% specified cache nexus.
3051%
3052% The format of the GetVirtualIndexesFromNexus() method is:
3053%
3054% const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
3055% NexusInfo *nexus_info)
3056%
3057% A description of each parameter follows:
3058%
3059% o cache: the pixel cache.
3060%
3061% o nexus_info: the cache nexus to return the colormap indexes.
3062%
3063*/
3064MagickExport const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
3065 NexusInfo *nexus_info)
3066{
3067 CacheInfo
3068 *cache_info;
3069
3070 if (cache == (Cache) NULL)
3071 return((IndexPacket *) NULL);
3072 cache_info=(CacheInfo *) cache;
3073 assert(cache_info->signature == MagickSignature);
3074 if (cache_info->storage_class == UndefinedClass)
3075 return((IndexPacket *) NULL);
3076 return(nexus_info->indexes);
3077}
3078
3079/*
3080%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3081% %
3082% %
3083% %
3084% G e t V i r t u a l I n d e x Q u e u e %
3085% %
3086% %
3087% %
3088%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3089%
3090% GetVirtualIndexQueue() returns the virtual black channel or the
3091% colormap indexes associated with the last call to QueueAuthenticPixels() or
3092% GetVirtualPixels(). NULL is returned if the black channel or colormap
3093% indexes are not available.
3094%
3095% The format of the GetVirtualIndexQueue() method is:
3096%
3097% const IndexPacket *GetVirtualIndexQueue(const Image *image)
3098%
3099% A description of each parameter follows:
3100%
3101% o image: the image.
3102%
3103*/
3104MagickExport const IndexPacket *GetVirtualIndexQueue(const Image *image)
3105{
3106 CacheInfo
3107 *cache_info;
3108
3109 assert(image != (const Image *) NULL);
3110 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003111 assert(image->cache != (Cache) NULL);
3112 cache_info=(CacheInfo *) image->cache;
3113 assert(cache_info->signature == MagickSignature);
3114 if (cache_info->methods.get_virtual_indexes_from_handler ==
3115 (GetVirtualIndexesFromHandler) NULL)
3116 return((IndexPacket *) NULL);
3117 return(cache_info->methods.get_virtual_indexes_from_handler(image));
3118}
3119
3120/*
3121%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3122% %
3123% %
3124% %
3125+ 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 %
3126% %
3127% %
3128% %
3129%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3130%
3131% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3132% pixel cache as defined by the geometry parameters. A pointer to the pixels
3133% is returned if the pixels are transferred, otherwise a NULL is returned.
3134%
3135% The format of the GetVirtualPixelsFromNexus() method is:
3136%
3137% PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003138% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00003139% const size_t columns,const size_t rows,NexusInfo *nexus_info,
3140% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003141%
3142% A description of each parameter follows:
3143%
3144% o image: the image.
3145%
3146% o virtual_pixel_method: the virtual pixel method.
3147%
3148% o x,y,columns,rows: These values define the perimeter of a region of
3149% pixels.
3150%
3151% o nexus_info: the cache nexus to acquire.
3152%
3153% o exception: return any errors or warnings in this structure.
3154%
3155*/
3156
cristybb503372010-05-27 20:51:26 +00003157static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003158 DitherMatrix[64] =
3159 {
3160 0, 48, 12, 60, 3, 51, 15, 63,
3161 32, 16, 44, 28, 35, 19, 47, 31,
3162 8, 56, 4, 52, 11, 59, 7, 55,
3163 40, 24, 36, 20, 43, 27, 39, 23,
3164 2, 50, 14, 62, 1, 49, 13, 61,
3165 34, 18, 46, 30, 33, 17, 45, 29,
3166 10, 58, 6, 54, 9, 57, 5, 53,
3167 42, 26, 38, 22, 41, 25, 37, 21
3168 };
3169
cristybb503372010-05-27 20:51:26 +00003170static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003171{
cristybb503372010-05-27 20:51:26 +00003172 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003173 index;
3174
3175 index=x+DitherMatrix[x & 0x07]-32L;
3176 if (index < 0L)
3177 return(0L);
cristybb503372010-05-27 20:51:26 +00003178 if (index >= (ssize_t) columns)
3179 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00003180 return(index);
3181}
3182
cristybb503372010-05-27 20:51:26 +00003183static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003184{
cristybb503372010-05-27 20:51:26 +00003185 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003186 index;
3187
3188 index=y+DitherMatrix[y & 0x07]-32L;
3189 if (index < 0L)
3190 return(0L);
cristybb503372010-05-27 20:51:26 +00003191 if (index >= (ssize_t) rows)
3192 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00003193 return(index);
3194}
3195
cristybb503372010-05-27 20:51:26 +00003196static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003197{
3198 if (x < 0L)
3199 return(0L);
cristybb503372010-05-27 20:51:26 +00003200 if (x >= (ssize_t) columns)
3201 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003202 return(x);
3203}
3204
cristybb503372010-05-27 20:51:26 +00003205static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003206{
3207 if (y < 0L)
3208 return(0L);
cristybb503372010-05-27 20:51:26 +00003209 if (y >= (ssize_t) rows)
3210 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003211 return(y);
3212}
3213
cristybb503372010-05-27 20:51:26 +00003214static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003215{
cristybb503372010-05-27 20:51:26 +00003216 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003217}
3218
cristybb503372010-05-27 20:51:26 +00003219static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003220{
cristybb503372010-05-27 20:51:26 +00003221 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003222}
3223
3224/*
3225 VirtualPixelModulo() computes the remainder of dividing offset by extent. It
3226 returns not only the quotient (tile the offset falls in) but also the positive
3227 remainer within that tile such that 0 <= remainder < extent. This method is
3228 essentially a ldiv() using a floored modulo division rather than the normal
3229 default truncated modulo division.
3230*/
cristybb503372010-05-27 20:51:26 +00003231static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3232 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003233{
3234 MagickModulo
3235 modulo;
3236
cristybb503372010-05-27 20:51:26 +00003237 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003238 if (offset < 0L)
3239 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003240 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003241 return(modulo);
3242}
3243
3244MagickExport const PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003245 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3246 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003247 ExceptionInfo *exception)
3248{
3249 CacheInfo
3250 *cache_info;
3251
cristyc3ec0d42010-04-07 01:18:08 +00003252 IndexPacket
3253 virtual_index;
3254
cristy3ed852e2009-09-05 21:47:34 +00003255 MagickOffsetType
3256 offset;
3257
3258 MagickSizeType
3259 length,
3260 number_pixels;
3261
3262 NexusInfo
3263 **virtual_nexus;
3264
3265 PixelPacket
3266 *pixels,
3267 virtual_pixel;
3268
3269 RectangleInfo
3270 region;
3271
3272 register const IndexPacket
cristyc3ec0d42010-04-07 01:18:08 +00003273 *restrict virtual_indexes;
cristy3ed852e2009-09-05 21:47:34 +00003274
3275 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003276 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003277
3278 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003279 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003280
cristye076a6e2010-08-15 19:59:43 +00003281 register PixelPacket
3282 *restrict q;
3283
cristybb503372010-05-27 20:51:26 +00003284 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003285 u,
3286 v;
3287
cristy3ed852e2009-09-05 21:47:34 +00003288 /*
3289 Acquire pixels.
3290 */
cristy3ed852e2009-09-05 21:47:34 +00003291 cache_info=(CacheInfo *) image->cache;
cristy4cfbb3f2010-03-14 20:40:23 +00003292 if (cache_info->type == UndefinedCache)
cristy3ed852e2009-09-05 21:47:34 +00003293 return((const PixelPacket *) NULL);
3294 region.x=x;
3295 region.y=y;
3296 region.width=columns;
3297 region.height=rows;
3298 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
3299 if (pixels == (PixelPacket *) NULL)
3300 return((const PixelPacket *) NULL);
cristydf415c82010-03-11 16:47:50 +00003301 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3302 nexus_info->region.x;
3303 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3304 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003305 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3306 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003307 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3308 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003309 {
3310 MagickBooleanType
3311 status;
3312
3313 /*
3314 Pixel request is inside cache extents.
3315 */
3316 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
3317 return(pixels);
3318 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3319 if (status == MagickFalse)
3320 return((const PixelPacket *) NULL);
3321 if ((cache_info->storage_class == PseudoClass) ||
3322 (cache_info->colorspace == CMYKColorspace))
3323 {
3324 status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
3325 if (status == MagickFalse)
3326 return((const PixelPacket *) NULL);
3327 }
3328 return(pixels);
3329 }
3330 /*
3331 Pixel request is outside cache extents.
3332 */
3333 q=pixels;
3334 indexes=GetPixelCacheNexusIndexes(cache_info,nexus_info);
3335 virtual_nexus=AcquirePixelCacheNexus(1);
3336 if (virtual_nexus == (NexusInfo **) NULL)
3337 {
3338 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3339 "UnableToGetCacheNexus","`%s'",image->filename);
3340 return((const PixelPacket *) NULL);
3341 }
3342 switch (virtual_pixel_method)
3343 {
3344 case BlackVirtualPixelMethod:
3345 {
cristy4789f0d2010-01-10 00:01:06 +00003346 SetRedPixelComponent(&virtual_pixel,0);
3347 SetGreenPixelComponent(&virtual_pixel,0);
3348 SetBluePixelComponent(&virtual_pixel,0);
3349 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003350 break;
3351 }
3352 case GrayVirtualPixelMethod:
3353 {
cristy4789f0d2010-01-10 00:01:06 +00003354 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3355 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3356 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3357 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003358 break;
3359 }
3360 case TransparentVirtualPixelMethod:
3361 {
cristy4789f0d2010-01-10 00:01:06 +00003362 SetRedPixelComponent(&virtual_pixel,0);
3363 SetGreenPixelComponent(&virtual_pixel,0);
3364 SetBluePixelComponent(&virtual_pixel,0);
3365 SetOpacityPixelComponent(&virtual_pixel,TransparentOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003366 break;
3367 }
3368 case MaskVirtualPixelMethod:
3369 case WhiteVirtualPixelMethod:
3370 {
cristy4789f0d2010-01-10 00:01:06 +00003371 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3372 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3373 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3374 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003375 break;
3376 }
3377 default:
3378 {
3379 virtual_pixel=image->background_color;
3380 break;
3381 }
3382 }
cristyc3ec0d42010-04-07 01:18:08 +00003383 virtual_index=0;
cristybb503372010-05-27 20:51:26 +00003384 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003385 {
cristybb503372010-05-27 20:51:26 +00003386 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003387 {
3388 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003389 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003390 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3391 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003392 {
3393 MagickModulo
3394 x_modulo,
3395 y_modulo;
3396
3397 /*
3398 Transfer a single pixel.
3399 */
3400 length=(MagickSizeType) 1;
3401 switch (virtual_pixel_method)
3402 {
3403 case BackgroundVirtualPixelMethod:
3404 case ConstantVirtualPixelMethod:
3405 case BlackVirtualPixelMethod:
3406 case GrayVirtualPixelMethod:
3407 case TransparentVirtualPixelMethod:
3408 case MaskVirtualPixelMethod:
3409 case WhiteVirtualPixelMethod:
3410 {
3411 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003412 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003413 break;
3414 }
3415 case EdgeVirtualPixelMethod:
3416 default:
3417 {
3418 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003419 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003420 1UL,1UL,virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003421 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3422 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003423 break;
3424 }
3425 case RandomVirtualPixelMethod:
3426 {
3427 if (cache_info->random_info == (RandomInfo *) NULL)
3428 cache_info->random_info=AcquireRandomInfo();
3429 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003430 RandomX(cache_info->random_info,cache_info->columns),
3431 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003432 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003433 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3434 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003435 break;
3436 }
3437 case DitherVirtualPixelMethod:
3438 {
3439 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003440 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003441 1UL,1UL,virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003442 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3443 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003444 break;
3445 }
3446 case TileVirtualPixelMethod:
3447 {
3448 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3449 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3450 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3451 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3452 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003453 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3454 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003455 break;
3456 }
3457 case MirrorVirtualPixelMethod:
3458 {
3459 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3460 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003461 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003462 x_modulo.remainder-1L;
3463 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3464 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003465 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003466 y_modulo.remainder-1L;
3467 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3468 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3469 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003470 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3471 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003472 break;
3473 }
3474 case CheckerTileVirtualPixelMethod:
3475 {
3476 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3477 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3478 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3479 {
3480 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003481 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003482 break;
3483 }
3484 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3485 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3486 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003487 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3488 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003489 break;
3490 }
3491 case HorizontalTileVirtualPixelMethod:
3492 {
cristybb503372010-05-27 20:51:26 +00003493 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003494 {
3495 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003496 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003497 break;
3498 }
3499 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3500 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3501 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3502 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3503 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003504 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3505 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003506 break;
3507 }
3508 case VerticalTileVirtualPixelMethod:
3509 {
cristybb503372010-05-27 20:51:26 +00003510 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
cristy3ed852e2009-09-05 21:47:34 +00003511 {
3512 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003513 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003514 break;
3515 }
3516 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3517 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3518 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3519 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3520 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003521 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3522 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003523 break;
3524 }
3525 case HorizontalTileEdgeVirtualPixelMethod:
3526 {
3527 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3528 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003529 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003530 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003531 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3532 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003533 break;
3534 }
3535 case VerticalTileEdgeVirtualPixelMethod:
3536 {
3537 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3538 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003539 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003540 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003541 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3542 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003543 break;
3544 }
3545 }
3546 if (p == (const PixelPacket *) NULL)
3547 break;
3548 *q++=(*p);
cristyc3ec0d42010-04-07 01:18:08 +00003549 if ((indexes != (IndexPacket *) NULL) &&
3550 (virtual_indexes != (const IndexPacket *) NULL))
3551 *indexes++=(*virtual_indexes);
cristy3ed852e2009-09-05 21:47:34 +00003552 continue;
3553 }
3554 /*
3555 Transfer a run of pixels.
3556 */
3557 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,
cristybb503372010-05-27 20:51:26 +00003558 (size_t) length,1UL,virtual_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003559 if (p == (const PixelPacket *) NULL)
3560 break;
cristyc3ec0d42010-04-07 01:18:08 +00003561 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003562 (void) CopyMagickMemory(q,p,(size_t) length*sizeof(*p));
3563 q+=length;
cristyc3ec0d42010-04-07 01:18:08 +00003564 if ((indexes != (IndexPacket *) NULL) &&
3565 (virtual_indexes != (const IndexPacket *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003566 {
cristyc3ec0d42010-04-07 01:18:08 +00003567 (void) CopyMagickMemory(indexes,virtual_indexes,(size_t) length*
3568 sizeof(*virtual_indexes));
3569 indexes+=length;
cristy3ed852e2009-09-05 21:47:34 +00003570 }
3571 }
3572 }
3573 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3574 return(pixels);
3575}
3576
3577/*
3578%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3579% %
3580% %
3581% %
3582+ G e t V i r t u a l P i x e l C a c h e %
3583% %
3584% %
3585% %
3586%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3587%
3588% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3589% cache as defined by the geometry parameters. A pointer to the pixels
3590% is returned if the pixels are transferred, otherwise a NULL is returned.
3591%
3592% The format of the GetVirtualPixelCache() method is:
3593%
3594% const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003595% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3596% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003597% ExceptionInfo *exception)
3598%
3599% A description of each parameter follows:
3600%
3601% o image: the image.
3602%
3603% o virtual_pixel_method: the virtual pixel method.
3604%
3605% o x,y,columns,rows: These values define the perimeter of a region of
3606% pixels.
3607%
3608% o exception: return any errors or warnings in this structure.
3609%
3610*/
3611static const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003612 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3613 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003614{
3615 CacheInfo
3616 *cache_info;
3617
3618 const PixelPacket
3619 *pixels;
3620
cristy6ebe97c2010-07-03 01:17:28 +00003621 int
cristy3ed852e2009-09-05 21:47:34 +00003622 id;
3623
cristy3ed852e2009-09-05 21:47:34 +00003624 cache_info=(CacheInfo *) image->cache;
3625 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00003626 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00003627 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3628 cache_info->nexus_info[id],exception);
3629 return(pixels);
3630}
3631
3632/*
3633%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3634% %
3635% %
3636% %
3637% G e t V i r t u a l P i x e l Q u e u e %
3638% %
3639% %
3640% %
3641%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3642%
3643% GetVirtualPixelQueue() returns the virtual pixels associated with the
3644% last call to QueueAuthenticPixels() or GetVirtualPixels().
3645%
3646% The format of the GetVirtualPixelQueue() method is:
3647%
3648% const PixelPacket *GetVirtualPixelQueue(const Image image)
3649%
3650% A description of each parameter follows:
3651%
3652% o image: the image.
3653%
3654*/
3655MagickExport const PixelPacket *GetVirtualPixelQueue(const Image *image)
3656{
3657 CacheInfo
3658 *cache_info;
3659
3660 assert(image != (const Image *) NULL);
3661 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003662 assert(image->cache != (Cache) NULL);
3663 cache_info=(CacheInfo *) image->cache;
3664 assert(cache_info->signature == MagickSignature);
3665 if (cache_info->methods.get_virtual_pixels_handler ==
3666 (GetVirtualPixelsHandler) NULL)
3667 return((PixelPacket *) NULL);
3668 return(cache_info->methods.get_virtual_pixels_handler(image));
3669}
3670
3671/*
3672%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3673% %
3674% %
3675% %
3676% G e t V i r t u a l P i x e l s %
3677% %
3678% %
3679% %
3680%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3681%
3682% GetVirtualPixels() returns an immutable pixel region. If the
3683% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003684% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003685% copy of the pixels or it may point to the original pixels in memory.
3686% Performance is maximized if the selected region is part of one row, or one
3687% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003688% (without a copy) if the image is in memory, or in a memory-mapped file. The
3689% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003690%
3691% Pixels accessed via the returned pointer represent a simple array of type
3692% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
3693% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access
3694% the black color component or to obtain the colormap indexes (of type
3695% IndexPacket) corresponding to the region.
3696%
3697% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3698%
3699% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3700% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3701% GetCacheViewAuthenticPixels() instead.
3702%
3703% The format of the GetVirtualPixels() method is:
3704%
cristybb503372010-05-27 20:51:26 +00003705% const PixelPacket *GetVirtualPixels(const Image *image,const ssize_t x,
3706% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003707% ExceptionInfo *exception)
3708%
3709% A description of each parameter follows:
3710%
3711% o image: the image.
3712%
3713% o x,y,columns,rows: These values define the perimeter of a region of
3714% pixels.
3715%
3716% o exception: return any errors or warnings in this structure.
3717%
3718*/
3719MagickExport const PixelPacket *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003720 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3721 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003722{
3723 CacheInfo
3724 *cache_info;
3725
3726 const PixelPacket
3727 *pixels;
3728
3729 assert(image != (const Image *) NULL);
3730 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003731 assert(image->cache != (Cache) NULL);
3732 cache_info=(CacheInfo *) image->cache;
3733 assert(cache_info->signature == MagickSignature);
3734 if (cache_info->methods.get_virtual_pixel_handler ==
3735 (GetVirtualPixelHandler) NULL)
3736 return((const PixelPacket *) NULL);
3737 pixels=cache_info->methods.get_virtual_pixel_handler(image,
3738 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception);
3739 return(pixels);
3740}
3741
3742/*
3743%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3744% %
3745% %
3746% %
3747+ 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 %
3748% %
3749% %
3750% %
3751%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3752%
3753% GetVirtualPixelsCache() returns the pixels associated with the last call
3754% to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3755%
3756% The format of the GetVirtualPixelsCache() method is:
3757%
3758% PixelPacket *GetVirtualPixelsCache(const Image *image)
3759%
3760% A description of each parameter follows:
3761%
3762% o image: the image.
3763%
3764*/
3765static const PixelPacket *GetVirtualPixelsCache(const Image *image)
3766{
3767 CacheInfo
3768 *cache_info;
3769
3770 const PixelPacket
3771 *pixels;
3772
cristy6ebe97c2010-07-03 01:17:28 +00003773 int
cristy3ed852e2009-09-05 21:47:34 +00003774 id;
3775
cristy3ed852e2009-09-05 21:47:34 +00003776 cache_info=(CacheInfo *) image->cache;
3777 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00003778 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00003779 pixels=GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]);
3780 return(pixels);
3781}
3782
3783/*
3784%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3785% %
3786% %
3787% %
3788+ G e t V i r t u a l P i x e l s N e x u s %
3789% %
3790% %
3791% %
3792%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3793%
3794% GetVirtualPixelsNexus() returns the pixels associated with the specified
3795% cache nexus.
3796%
3797% The format of the GetVirtualPixelsNexus() method is:
3798%
3799% const IndexPacket *GetVirtualPixelsNexus(const Cache cache,
3800% NexusInfo *nexus_info)
3801%
3802% A description of each parameter follows:
3803%
3804% o cache: the pixel cache.
3805%
3806% o nexus_info: the cache nexus to return the colormap pixels.
3807%
3808*/
3809MagickExport const PixelPacket *GetVirtualPixelsNexus(const Cache cache,
3810 NexusInfo *nexus_info)
3811{
3812 CacheInfo
3813 *cache_info;
3814
3815 if (cache == (Cache) NULL)
3816 return((PixelPacket *) NULL);
3817 cache_info=(CacheInfo *) cache;
3818 assert(cache_info->signature == MagickSignature);
3819 if (cache_info->storage_class == UndefinedClass)
3820 return((PixelPacket *) NULL);
3821 return((const PixelPacket *) nexus_info->pixels);
3822}
3823
3824/*
3825%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3826% %
3827% %
3828% %
3829+ M a s k P i x e l C a c h e N e x u s %
3830% %
3831% %
3832% %
3833%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3834%
3835% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3836% The method returns MagickTrue if the pixel region is masked, otherwise
3837% MagickFalse.
3838%
3839% The format of the MaskPixelCacheNexus() method is:
3840%
3841% MagickBooleanType MaskPixelCacheNexus(Image *image,
3842% NexusInfo *nexus_info,ExceptionInfo *exception)
3843%
3844% A description of each parameter follows:
3845%
3846% o image: the image.
3847%
3848% o nexus_info: the cache nexus to clip.
3849%
3850% o exception: return any errors or warnings in this structure.
3851%
3852*/
3853
3854static inline void MagickPixelCompositeMask(const MagickPixelPacket *p,
3855 const MagickRealType alpha,const MagickPixelPacket *q,
3856 const MagickRealType beta,MagickPixelPacket *composite)
3857{
3858 MagickRealType
3859 gamma;
3860
3861 if (alpha == TransparentOpacity)
3862 {
3863 *composite=(*q);
3864 return;
3865 }
3866 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3867 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3868 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3869 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3870 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3871 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3872 composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
3873}
3874
3875static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3876 ExceptionInfo *exception)
3877{
3878 CacheInfo
3879 *cache_info;
3880
3881 MagickPixelPacket
3882 alpha,
3883 beta;
3884
3885 MagickSizeType
3886 number_pixels;
3887
3888 NexusInfo
3889 **clip_nexus,
3890 **image_nexus;
3891
3892 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003893 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003894
3895 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003896 *restrict nexus_indexes,
3897 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003898
cristy3ed852e2009-09-05 21:47:34 +00003899 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003900 *restrict p,
3901 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003902
cristye076a6e2010-08-15 19:59:43 +00003903 register ssize_t
3904 i;
3905
cristy3ed852e2009-09-05 21:47:34 +00003906 /*
3907 Apply clip mask.
3908 */
3909 if (image->debug != MagickFalse)
3910 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3911 if (image->mask == (Image *) NULL)
3912 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +00003913 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00003914 if (cache_info == (Cache) NULL)
3915 return(MagickFalse);
3916 image_nexus=AcquirePixelCacheNexus(1);
3917 clip_nexus=AcquirePixelCacheNexus(1);
3918 if ((image_nexus == (NexusInfo **) NULL) ||
3919 (clip_nexus == (NexusInfo **) NULL))
3920 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy09449f72010-01-23 03:08:36 +00003921 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,
3922 nexus_info->region.y,nexus_info->region.width,nexus_info->region.height,
3923 image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003924 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
3925 q=nexus_info->pixels;
3926 nexus_indexes=nexus_info->indexes;
3927 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3928 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3929 nexus_info->region.height,clip_nexus[0],&image->exception);
3930 GetMagickPixelPacket(image,&alpha);
3931 GetMagickPixelPacket(image,&beta);
3932 number_pixels=(MagickSizeType) nexus_info->region.width*
3933 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +00003934 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +00003935 {
3936 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
3937 break;
3938 SetMagickPixelPacket(image,p,indexes+i,&alpha);
3939 SetMagickPixelPacket(image,q,nexus_indexes+i,&beta);
3940 MagickPixelCompositeMask(&beta,(MagickRealType) PixelIntensityToQuantum(r),
3941 &alpha,alpha.opacity,&beta);
cristyce70c172010-01-07 17:15:30 +00003942 q->red=ClampToQuantum(beta.red);
3943 q->green=ClampToQuantum(beta.green);
3944 q->blue=ClampToQuantum(beta.blue);
3945 q->opacity=ClampToQuantum(beta.opacity);
cristy3ed852e2009-09-05 21:47:34 +00003946 if (cache_info->active_index_channel != MagickFalse)
3947 nexus_indexes[i]=indexes[i];
3948 p++;
3949 q++;
3950 r++;
3951 }
3952 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3953 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +00003954 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003955 return(MagickFalse);
3956 return(MagickTrue);
3957}
3958
3959/*
3960%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3961% %
3962% %
3963% %
3964+ O p e n P i x e l C a c h e %
3965% %
3966% %
3967% %
3968%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3969%
3970% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3971% dimensions, allocating space for the image pixels and optionally the
3972% colormap indexes, and memory mapping the cache if it is disk based. The
3973% cache nexus array is initialized as well.
3974%
3975% The format of the OpenPixelCache() method is:
3976%
3977% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3978% ExceptionInfo *exception)
3979%
3980% A description of each parameter follows:
3981%
3982% o image: the image.
3983%
3984% o mode: ReadMode, WriteMode, or IOMode.
3985%
3986% o exception: return any errors or warnings in this structure.
3987%
3988*/
3989
cristyd43a46b2010-01-21 02:13:41 +00003990static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003991{
3992 cache_info->mapped=MagickFalse;
3993 cache_info->pixels=(PixelPacket *) AcquireMagickMemory((size_t)
3994 cache_info->length);
3995 if (cache_info->pixels == (PixelPacket *) NULL)
3996 {
3997 cache_info->mapped=MagickTrue;
3998 cache_info->pixels=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
3999 cache_info->length);
4000 }
4001}
4002
4003static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
4004{
4005 CacheInfo
4006 *cache_info;
4007
4008 MagickOffsetType
4009 count,
4010 extent,
4011 offset;
4012
4013 cache_info=(CacheInfo *) image->cache;
4014 if (image->debug != MagickFalse)
4015 {
4016 char
4017 format[MaxTextExtent],
4018 message[MaxTextExtent];
4019
cristyb9080c92009-12-01 20:13:26 +00004020 (void) FormatMagickSize(length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00004021 (void) FormatMagickString(message,MaxTextExtent,
cristy2ce15c92010-03-12 14:03:41 +00004022 "extend %s (%s[%d], disk, %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00004023 cache_info->cache_filename,cache_info->file,format);
4024 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4025 }
4026 if (length != (MagickSizeType) ((MagickOffsetType) length))
4027 return(MagickFalse);
4028 extent=(MagickOffsetType) MagickSeek(cache_info->file,0,SEEK_END);
4029 if (extent < 0)
4030 return(MagickFalse);
4031 if ((MagickSizeType) extent >= length)
4032 return(MagickTrue);
4033 offset=(MagickOffsetType) length-1;
4034 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
4035 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
4036}
4037
4038static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
4039 ExceptionInfo *exception)
4040{
4041 char
4042 format[MaxTextExtent],
4043 message[MaxTextExtent];
4044
4045 CacheInfo
4046 *cache_info,
4047 source_info;
4048
4049 MagickSizeType
4050 length,
4051 number_pixels;
4052
4053 MagickStatusType
4054 status;
4055
4056 size_t
cristye076a6e2010-08-15 19:59:43 +00004057 columns,
cristy3ed852e2009-09-05 21:47:34 +00004058 packet_size;
4059
cristy3ed852e2009-09-05 21:47:34 +00004060 if (image->debug != MagickFalse)
4061 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4062 if ((image->columns == 0) || (image->rows == 0))
4063 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
4064 cache_info=(CacheInfo *) image->cache;
4065 source_info=(*cache_info);
4066 source_info.file=(-1);
cristye8c25f92010-06-03 00:53:06 +00004067 (void) FormatMagickString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
4068 image->filename,(double) GetImageIndexInList(image));
cristy87528ea2009-09-10 14:53:56 +00004069 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +00004070 cache_info->rows=image->rows;
4071 cache_info->columns=image->columns;
4072 cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
4073 (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
cristy73724512010-04-12 14:43:14 +00004074 if (image->ping != MagickFalse)
4075 {
4076 cache_info->storage_class=image->storage_class;
4077 cache_info->colorspace=image->colorspace;
4078 cache_info->type=PingCache;
4079 cache_info->pixels=(PixelPacket *) NULL;
4080 cache_info->indexes=(IndexPacket *) NULL;
4081 cache_info->length=0;
4082 return(MagickTrue);
4083 }
cristy3ed852e2009-09-05 21:47:34 +00004084 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4085 packet_size=sizeof(PixelPacket);
4086 if (cache_info->active_index_channel != MagickFalse)
4087 packet_size+=sizeof(IndexPacket);
4088 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00004089 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00004090 if (cache_info->columns != columns)
4091 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4092 image->filename);
4093 cache_info->length=length;
4094 status=AcquireMagickResource(AreaResource,cache_info->length);
4095 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4096 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4097 {
4098 status=AcquireMagickResource(MemoryResource,cache_info->length);
4099 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4100 (cache_info->type == MemoryCache))
4101 {
cristyd43a46b2010-01-21 02:13:41 +00004102 AllocatePixelCachePixels(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004103 if (cache_info->pixels == (PixelPacket *) NULL)
4104 cache_info->pixels=source_info.pixels;
4105 else
4106 {
4107 /*
4108 Create memory pixel cache.
4109 */
4110 if (image->debug != MagickFalse)
4111 {
cristy97e7a572009-12-05 15:07:53 +00004112 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004113 format);
cristy3ed852e2009-09-05 21:47:34 +00004114 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004115 "open %s (%s memory, %.20gx%.20g %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00004116 cache_info->mapped != MagickFalse ? "anonymous" : "heap",
cristye8c25f92010-06-03 00:53:06 +00004117 (double) cache_info->columns,(double) cache_info->rows,
4118 format);
cristy3ed852e2009-09-05 21:47:34 +00004119 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4120 message);
4121 }
4122 cache_info->storage_class=image->storage_class;
4123 cache_info->colorspace=image->colorspace;
4124 cache_info->type=MemoryCache;
4125 cache_info->indexes=(IndexPacket *) NULL;
4126 if (cache_info->active_index_channel != MagickFalse)
4127 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4128 number_pixels);
4129 if (source_info.storage_class != UndefinedClass)
4130 {
4131 status|=ClonePixelCachePixels(cache_info,&source_info,
4132 exception);
4133 RelinquishPixelCachePixels(&source_info);
4134 }
4135 return(MagickTrue);
4136 }
4137 }
4138 RelinquishMagickResource(MemoryResource,cache_info->length);
4139 }
4140 /*
4141 Create pixel cache on disk.
4142 */
4143 status=AcquireMagickResource(DiskResource,cache_info->length);
4144 if (status == MagickFalse)
4145 {
4146 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4147 "CacheResourcesExhausted","`%s'",image->filename);
4148 return(MagickFalse);
4149 }
4150 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4151 {
4152 RelinquishMagickResource(DiskResource,cache_info->length);
4153 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4154 image->filename);
4155 return(MagickFalse);
4156 }
4157 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4158 cache_info->length);
4159 if (status == MagickFalse)
4160 {
4161 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4162 image->filename);
4163 return(MagickFalse);
4164 }
4165 cache_info->storage_class=image->storage_class;
4166 cache_info->colorspace=image->colorspace;
4167 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4168 status=AcquireMagickResource(AreaResource,cache_info->length);
4169 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4170 cache_info->type=DiskCache;
4171 else
4172 {
4173 status=AcquireMagickResource(MapResource,cache_info->length);
4174 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4175 (cache_info->type != MemoryCache))
4176 cache_info->type=DiskCache;
4177 else
4178 {
4179 cache_info->pixels=(PixelPacket *) MapBlob(cache_info->file,mode,
4180 cache_info->offset,(size_t) cache_info->length);
4181 if (cache_info->pixels == (PixelPacket *) NULL)
4182 {
4183 cache_info->pixels=source_info.pixels;
4184 cache_info->type=DiskCache;
4185 }
4186 else
4187 {
4188 /*
4189 Create file-backed memory-mapped pixel cache.
4190 */
4191 (void) ClosePixelCacheOnDisk(cache_info);
4192 cache_info->type=MapCache;
4193 cache_info->mapped=MagickTrue;
4194 cache_info->indexes=(IndexPacket *) NULL;
4195 if (cache_info->active_index_channel != MagickFalse)
4196 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4197 number_pixels);
4198 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4199 {
4200 status=ClonePixelCachePixels(cache_info,&source_info,
4201 exception);
4202 RelinquishPixelCachePixels(&source_info);
4203 }
4204 if (image->debug != MagickFalse)
4205 {
cristy97e7a572009-12-05 15:07:53 +00004206 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004207 format);
cristy3ed852e2009-09-05 21:47:34 +00004208 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004209 "open %s (%s[%d], memory-mapped, %.20gx%.20g %sB)",
cristy3ed852e2009-09-05 21:47:34 +00004210 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004211 cache_info->file,(double) cache_info->columns,(double)
4212 cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004213 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4214 message);
4215 }
4216 return(MagickTrue);
4217 }
4218 }
4219 RelinquishMagickResource(MapResource,cache_info->length);
4220 }
4221 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4222 {
4223 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4224 RelinquishPixelCachePixels(&source_info);
4225 }
4226 if (image->debug != MagickFalse)
4227 {
cristyb9080c92009-12-01 20:13:26 +00004228 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00004229 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004230 "open %s (%s[%d], disk, %.20gx%.20g %sB)",cache_info->filename,
4231 cache_info->cache_filename,cache_info->file,(double)
4232 cache_info->columns,(double) cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004233 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4234 }
4235 return(MagickTrue);
4236}
4237
4238/*
4239%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4240% %
4241% %
4242% %
4243+ P e r s i s t P i x e l C a c h e %
4244% %
4245% %
4246% %
4247%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4248%
4249% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4250% persistent pixel cache is one that resides on disk and is not destroyed
4251% when the program exits.
4252%
4253% The format of the PersistPixelCache() method is:
4254%
4255% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4256% const MagickBooleanType attach,MagickOffsetType *offset,
4257% ExceptionInfo *exception)
4258%
4259% A description of each parameter follows:
4260%
4261% o image: the image.
4262%
4263% o filename: the persistent pixel cache filename.
4264%
cristy01b7eb02009-09-10 23:10:14 +00004265% o attach: A value other than zero initializes the persistent pixel
4266% cache.
4267%
cristy3ed852e2009-09-05 21:47:34 +00004268% o initialize: A value other than zero initializes the persistent pixel
4269% cache.
4270%
4271% o offset: the offset in the persistent cache to store pixels.
4272%
4273% o exception: return any errors or warnings in this structure.
4274%
4275*/
4276MagickExport MagickBooleanType PersistPixelCache(Image *image,
4277 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4278 ExceptionInfo *exception)
4279{
4280 CacheInfo
4281 *cache_info,
4282 *clone_info;
4283
4284 Image
4285 clone_image;
4286
cristy3ed852e2009-09-05 21:47:34 +00004287 MagickBooleanType
4288 status;
4289
cristye076a6e2010-08-15 19:59:43 +00004290 ssize_t
4291 page_size;
4292
cristy3ed852e2009-09-05 21:47:34 +00004293 assert(image != (Image *) NULL);
4294 assert(image->signature == MagickSignature);
4295 if (image->debug != MagickFalse)
4296 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4297 assert(image->cache != (void *) NULL);
4298 assert(filename != (const char *) NULL);
4299 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004300 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004301 cache_info=(CacheInfo *) image->cache;
4302 assert(cache_info->signature == MagickSignature);
4303 if (attach != MagickFalse)
4304 {
4305 /*
cristy01b7eb02009-09-10 23:10:14 +00004306 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004307 */
4308 if (image->debug != MagickFalse)
4309 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4310 "attach persistent cache");
4311 (void) CopyMagickString(cache_info->cache_filename,filename,
4312 MaxTextExtent);
4313 cache_info->type=DiskCache;
4314 cache_info->offset=(*offset);
4315 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4316 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004317 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004318 return(MagickTrue);
4319 }
cristy01b7eb02009-09-10 23:10:14 +00004320 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4321 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004322 {
cristyf84a1932010-01-03 18:00:18 +00004323 LockSemaphoreInfo(cache_info->semaphore);
cristy09449f72010-01-23 03:08:36 +00004324 if ((cache_info->mode != ReadMode) &&
4325 (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004326 (cache_info->reference_count == 1))
4327 {
4328 int
4329 status;
4330
4331 /*
cristy01b7eb02009-09-10 23:10:14 +00004332 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004333 */
4334 status=rename(cache_info->cache_filename,filename);
4335 if (status == 0)
4336 {
4337 (void) CopyMagickString(cache_info->cache_filename,filename,
4338 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004339 *offset+=cache_info->length+page_size-(cache_info->length %
4340 page_size);
cristyf84a1932010-01-03 18:00:18 +00004341 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004342 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004343 if (image->debug != MagickFalse)
4344 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4345 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004346 return(MagickTrue);
4347 }
4348 }
cristyf84a1932010-01-03 18:00:18 +00004349 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004350 }
4351 /*
cristy01b7eb02009-09-10 23:10:14 +00004352 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004353 */
4354 clone_image=(*image);
4355 clone_info=(CacheInfo *) clone_image.cache;
4356 image->cache=ClonePixelCache(cache_info);
4357 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4358 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4359 cache_info->type=DiskCache;
4360 cache_info->offset=(*offset);
4361 cache_info=(CacheInfo *) image->cache;
4362 status=ClonePixelCacheNexus(cache_info,clone_info,exception);
4363 if (status != MagickFalse)
4364 {
4365 status=OpenPixelCache(image,IOMode,exception);
4366 if (status != MagickFalse)
4367 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
4368 }
cristy688f07b2009-09-27 15:19:13 +00004369 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004370 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4371 return(status);
4372}
4373
4374/*
4375%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4376% %
4377% %
4378% %
4379+ Q u e u e A u t h e n t i c N e x u s %
4380% %
4381% %
4382% %
4383%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4384%
4385% QueueAuthenticNexus() allocates an region to store image pixels as defined
4386% by the region rectangle and returns a pointer to the region. This region is
4387% subsequently transferred from the pixel cache with
4388% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4389% pixels are transferred, otherwise a NULL is returned.
4390%
4391% The format of the QueueAuthenticNexus() method is:
4392%
cristy5f959472010-05-27 22:19:46 +00004393% PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
4394% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004395% NexusInfo *nexus_info,ExceptionInfo *exception)
4396%
4397% A description of each parameter follows:
4398%
4399% o image: the image.
4400%
4401% o x,y,columns,rows: These values define the perimeter of a region of
4402% pixels.
4403%
4404% o nexus_info: the cache nexus to set.
4405%
4406% o exception: return any errors or warnings in this structure.
4407%
4408*/
cristybb503372010-05-27 20:51:26 +00004409MagickExport PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy30097232010-07-01 02:16:30 +00004410 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
4411 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004412{
4413 CacheInfo
4414 *cache_info;
4415
4416 MagickOffsetType
4417 offset;
4418
4419 MagickSizeType
4420 number_pixels;
4421
4422 RectangleInfo
4423 region;
4424
4425 /*
4426 Validate pixel cache geometry.
4427 */
cristy77ff0282010-09-13 00:51:10 +00004428 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
4429 if (cache_info == (Cache) NULL)
4430 return((PixelPacket *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004431 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4432 {
4433 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4434 "NoPixelsDefinedInCache","`%s'",image->filename);
4435 return((PixelPacket *) NULL);
4436 }
cristybb503372010-05-27 20:51:26 +00004437 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4438 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004439 {
4440 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4441 "PixelsAreNotAuthentic","`%s'",image->filename);
4442 return((PixelPacket *) NULL);
4443 }
4444 offset=(MagickOffsetType) y*cache_info->columns+x;
4445 if (offset < 0)
4446 return((PixelPacket *) NULL);
4447 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4448 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4449 if ((MagickSizeType) offset >= number_pixels)
4450 return((PixelPacket *) NULL);
4451 /*
4452 Return pixel cache.
4453 */
4454 region.x=x;
4455 region.y=y;
4456 region.width=columns;
4457 region.height=rows;
4458 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4459}
4460
4461/*
4462%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4463% %
4464% %
4465% %
4466+ 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 %
4467% %
4468% %
4469% %
4470%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4471%
4472% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4473% defined by the region rectangle and returns a pointer to the region. This
4474% region is subsequently transferred from the pixel cache with
4475% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4476% pixels are transferred, otherwise a NULL is returned.
4477%
4478% The format of the QueueAuthenticPixelsCache() method is:
4479%
cristybb503372010-05-27 20:51:26 +00004480% PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4481% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004482% ExceptionInfo *exception)
4483%
4484% A description of each parameter follows:
4485%
4486% o image: the image.
4487%
4488% o x,y,columns,rows: These values define the perimeter of a region of
4489% pixels.
4490%
4491% o exception: return any errors or warnings in this structure.
4492%
4493*/
cristybb503372010-05-27 20:51:26 +00004494static PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4495 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004496 ExceptionInfo *exception)
4497{
4498 CacheInfo
4499 *cache_info;
4500
cristy6ebe97c2010-07-03 01:17:28 +00004501 int
cristy3ed852e2009-09-05 21:47:34 +00004502 id;
4503
4504 PixelPacket
4505 *pixels;
4506
cristy77ff0282010-09-13 00:51:10 +00004507 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00004508 if (cache_info == (Cache) NULL)
4509 return((PixelPacket *) NULL);
4510 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00004511 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00004512 pixels=QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4513 exception);
4514 return(pixels);
4515}
4516
4517/*
4518%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4519% %
4520% %
4521% %
4522% Q u e u e A u t h e n t i c P i x e l s %
4523% %
4524% %
4525% %
4526%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4527%
4528% QueueAuthenticPixels() queues a mutable pixel region. If the region is
4529% successfully intialized a pointer to a PixelPacket array representing the
4530% region is returned, otherwise NULL is returned. The returned pointer may
4531% point to a temporary working buffer for the pixels or it may point to the
4532% final location of the pixels in memory.
4533%
4534% Write-only access means that any existing pixel values corresponding to
4535% the region are ignored. This is useful if the initial image is being
4536% created from scratch, or if the existing pixel values are to be
4537% completely replaced without need to refer to their pre-existing values.
4538% The application is free to read and write the pixel buffer returned by
4539% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4540% initialize the pixel array values. Initializing pixel array values is the
4541% application's responsibility.
4542%
4543% Performance is maximized if the selected region is part of one row, or
4544% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004545% pixels in-place (without a copy) if the image is in memory, or in a
4546% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004547% by the user.
4548%
4549% Pixels accessed via the returned pointer represent a simple array of type
4550% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
4551% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
4552% the black color component or the colormap indexes (of type IndexPacket)
4553% corresponding to the region. Once the PixelPacket (and/or IndexPacket)
4554% array has been updated, the changes must be saved back to the underlying
4555% image using SyncAuthenticPixels() or they may be lost.
4556%
4557% The format of the QueueAuthenticPixels() method is:
4558%
cristy5f959472010-05-27 22:19:46 +00004559% PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4560% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004561% ExceptionInfo *exception)
4562%
4563% A description of each parameter follows:
4564%
4565% o image: the image.
4566%
4567% o x,y,columns,rows: These values define the perimeter of a region of
4568% pixels.
4569%
4570% o exception: return any errors or warnings in this structure.
4571%
4572*/
cristybb503372010-05-27 20:51:26 +00004573MagickExport PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4574 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004575 ExceptionInfo *exception)
4576{
4577 CacheInfo
4578 *cache_info;
4579
4580 PixelPacket
4581 *pixels;
4582
4583 assert(image != (Image *) NULL);
4584 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004585 assert(image->cache != (Cache) NULL);
4586 cache_info=(CacheInfo *) image->cache;
4587 assert(cache_info->signature == MagickSignature);
4588 if (cache_info->methods.queue_authentic_pixels_handler ==
4589 (QueueAuthenticPixelsHandler) NULL)
4590 return((PixelPacket *) NULL);
4591 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4592 rows,exception);
4593 return(pixels);
4594}
4595
4596/*
4597%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4598% %
4599% %
4600% %
4601+ R e a d P i x e l C a c h e I n d e x e s %
4602% %
4603% %
4604% %
4605%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4606%
4607% ReadPixelCacheIndexes() reads colormap indexes from the specified region of
4608% the pixel cache.
4609%
4610% The format of the ReadPixelCacheIndexes() method is:
4611%
4612% MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4613% NexusInfo *nexus_info,ExceptionInfo *exception)
4614%
4615% A description of each parameter follows:
4616%
4617% o cache_info: the pixel cache.
4618%
4619% o nexus_info: the cache nexus to read the colormap indexes.
4620%
4621% o exception: return any errors or warnings in this structure.
4622%
4623*/
4624static MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4625 NexusInfo *nexus_info,ExceptionInfo *exception)
4626{
4627 MagickOffsetType
4628 count,
4629 offset;
4630
4631 MagickSizeType
4632 length,
4633 number_pixels;
4634
4635 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004636 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004637
cristybb503372010-05-27 20:51:26 +00004638 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004639 y;
4640
cristybb503372010-05-27 20:51:26 +00004641 size_t
cristy3ed852e2009-09-05 21:47:34 +00004642 rows;
4643
cristy3ed852e2009-09-05 21:47:34 +00004644 if (cache_info->active_index_channel == MagickFalse)
4645 return(MagickFalse);
4646 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4647 return(MagickTrue);
4648 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4649 nexus_info->region.x;
4650 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
4651 rows=nexus_info->region.height;
4652 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004653 q=nexus_info->indexes;
4654 switch (cache_info->type)
4655 {
4656 case MemoryCache:
4657 case MapCache:
4658 {
4659 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004660 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004661
4662 /*
4663 Read indexes from memory.
4664 */
cristydd341db2010-03-04 19:06:38 +00004665 if ((cache_info->columns == nexus_info->region.width) &&
4666 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4667 {
4668 length=number_pixels;
4669 rows=1UL;
4670 }
cristy3ed852e2009-09-05 21:47:34 +00004671 p=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00004672 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004673 {
4674 (void) CopyMagickMemory(q,p,(size_t) length);
4675 p+=cache_info->columns;
4676 q+=nexus_info->region.width;
4677 }
4678 break;
4679 }
4680 case DiskCache:
4681 {
4682 /*
4683 Read indexes from disk.
4684 */
4685 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4686 {
4687 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4688 cache_info->cache_filename);
4689 return(MagickFalse);
4690 }
cristydd341db2010-03-04 19:06:38 +00004691 if ((cache_info->columns == nexus_info->region.width) &&
4692 (number_pixels < MagickMaxBufferExtent))
4693 {
4694 length=number_pixels;
4695 rows=1UL;
4696 }
cristy3ed852e2009-09-05 21:47:34 +00004697 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004698 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004699 {
4700 count=ReadPixelCacheRegion(cache_info,cache_info->offset+number_pixels*
4701 sizeof(PixelPacket)+offset*sizeof(*q),length,(unsigned char *) q);
4702 if ((MagickSizeType) count < length)
4703 break;
4704 offset+=cache_info->columns;
4705 q+=nexus_info->region.width;
4706 }
cristybb503372010-05-27 20:51:26 +00004707 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004708 {
4709 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4710 cache_info->cache_filename);
4711 return(MagickFalse);
4712 }
4713 break;
4714 }
4715 default:
4716 break;
4717 }
4718 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004719 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004720 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004721 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004722 nexus_info->region.width,(double) nexus_info->region.height,(double)
4723 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004724 return(MagickTrue);
4725}
4726
4727/*
4728%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4729% %
4730% %
4731% %
4732+ R e a d P i x e l C a c h e P i x e l s %
4733% %
4734% %
4735% %
4736%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4737%
4738% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4739% cache.
4740%
4741% The format of the ReadPixelCachePixels() method is:
4742%
4743% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4744% NexusInfo *nexus_info,ExceptionInfo *exception)
4745%
4746% A description of each parameter follows:
4747%
4748% o cache_info: the pixel cache.
4749%
4750% o nexus_info: the cache nexus to read the pixels.
4751%
4752% o exception: return any errors or warnings in this structure.
4753%
4754*/
4755static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4756 NexusInfo *nexus_info,ExceptionInfo *exception)
4757{
4758 MagickOffsetType
4759 count,
4760 offset;
4761
4762 MagickSizeType
4763 length,
4764 number_pixels;
4765
cristy3ed852e2009-09-05 21:47:34 +00004766 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004767 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004768
cristye076a6e2010-08-15 19:59:43 +00004769 register ssize_t
4770 y;
4771
cristybb503372010-05-27 20:51:26 +00004772 size_t
cristy3ed852e2009-09-05 21:47:34 +00004773 rows;
4774
cristy3ed852e2009-09-05 21:47:34 +00004775 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4776 return(MagickTrue);
4777 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4778 nexus_info->region.x;
4779 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
4780 rows=nexus_info->region.height;
4781 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004782 q=nexus_info->pixels;
4783 switch (cache_info->type)
4784 {
4785 case MemoryCache:
4786 case MapCache:
4787 {
4788 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004789 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004790
4791 /*
4792 Read pixels from memory.
4793 */
cristydd341db2010-03-04 19:06:38 +00004794 if ((cache_info->columns == nexus_info->region.width) &&
4795 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4796 {
4797 length=number_pixels;
4798 rows=1UL;
4799 }
cristy3ed852e2009-09-05 21:47:34 +00004800 p=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00004801 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004802 {
4803 (void) CopyMagickMemory(q,p,(size_t) length);
4804 p+=cache_info->columns;
4805 q+=nexus_info->region.width;
4806 }
4807 break;
4808 }
4809 case DiskCache:
4810 {
4811 /*
4812 Read pixels from disk.
4813 */
4814 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4815 {
4816 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4817 cache_info->cache_filename);
4818 return(MagickFalse);
4819 }
cristydd341db2010-03-04 19:06:38 +00004820 if ((cache_info->columns == nexus_info->region.width) &&
4821 (number_pixels < MagickMaxBufferExtent))
4822 {
4823 length=number_pixels;
4824 rows=1UL;
4825 }
cristybb503372010-05-27 20:51:26 +00004826 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004827 {
4828 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4829 sizeof(*q),length,(unsigned char *) q);
4830 if ((MagickSizeType) count < length)
4831 break;
4832 offset+=cache_info->columns;
4833 q+=nexus_info->region.width;
4834 }
cristybb503372010-05-27 20:51:26 +00004835 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004836 {
4837 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4838 cache_info->cache_filename);
4839 return(MagickFalse);
4840 }
4841 break;
4842 }
4843 default:
4844 break;
4845 }
4846 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004847 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004848 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004849 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004850 nexus_info->region.width,(double) nexus_info->region.height,(double)
4851 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004852 return(MagickTrue);
4853}
4854
4855/*
4856%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4857% %
4858% %
4859% %
4860+ R e f e r e n c e P i x e l C a c h e %
4861% %
4862% %
4863% %
4864%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4865%
4866% ReferencePixelCache() increments the reference count associated with the
4867% pixel cache returning a pointer to the cache.
4868%
4869% The format of the ReferencePixelCache method is:
4870%
4871% Cache ReferencePixelCache(Cache cache_info)
4872%
4873% A description of each parameter follows:
4874%
4875% o cache_info: the pixel cache.
4876%
4877*/
4878MagickExport Cache ReferencePixelCache(Cache cache)
4879{
4880 CacheInfo
4881 *cache_info;
4882
4883 assert(cache != (Cache *) NULL);
4884 cache_info=(CacheInfo *) cache;
4885 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004886 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004887 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004888 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004889 return(cache_info);
4890}
4891
4892/*
4893%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4894% %
4895% %
4896% %
4897+ S e t P i x e l C a c h e M e t h o d s %
4898% %
4899% %
4900% %
4901%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4902%
4903% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4904%
4905% The format of the SetPixelCacheMethods() method is:
4906%
4907% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4908%
4909% A description of each parameter follows:
4910%
4911% o cache: the pixel cache.
4912%
4913% o cache_methods: Specifies a pointer to a CacheMethods structure.
4914%
4915*/
4916MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4917{
4918 CacheInfo
4919 *cache_info;
4920
4921 GetOneAuthenticPixelFromHandler
4922 get_one_authentic_pixel_from_handler;
4923
4924 GetOneVirtualPixelFromHandler
4925 get_one_virtual_pixel_from_handler;
4926
4927 /*
4928 Set cache pixel methods.
4929 */
4930 assert(cache != (Cache) NULL);
4931 assert(cache_methods != (CacheMethods *) NULL);
4932 cache_info=(CacheInfo *) cache;
4933 assert(cache_info->signature == MagickSignature);
4934 if (cache_info->debug != MagickFalse)
4935 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4936 cache_info->filename);
4937 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4938 cache_info->methods.get_virtual_pixel_handler=
4939 cache_methods->get_virtual_pixel_handler;
4940 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4941 cache_info->methods.destroy_pixel_handler=
4942 cache_methods->destroy_pixel_handler;
4943 if (cache_methods->get_virtual_indexes_from_handler !=
4944 (GetVirtualIndexesFromHandler) NULL)
4945 cache_info->methods.get_virtual_indexes_from_handler=
4946 cache_methods->get_virtual_indexes_from_handler;
4947 if (cache_methods->get_authentic_pixels_handler !=
4948 (GetAuthenticPixelsHandler) NULL)
4949 cache_info->methods.get_authentic_pixels_handler=
4950 cache_methods->get_authentic_pixels_handler;
4951 if (cache_methods->queue_authentic_pixels_handler !=
4952 (QueueAuthenticPixelsHandler) NULL)
4953 cache_info->methods.queue_authentic_pixels_handler=
4954 cache_methods->queue_authentic_pixels_handler;
4955 if (cache_methods->sync_authentic_pixels_handler !=
4956 (SyncAuthenticPixelsHandler) NULL)
4957 cache_info->methods.sync_authentic_pixels_handler=
4958 cache_methods->sync_authentic_pixels_handler;
4959 if (cache_methods->get_authentic_pixels_from_handler !=
4960 (GetAuthenticPixelsFromHandler) NULL)
4961 cache_info->methods.get_authentic_pixels_from_handler=
4962 cache_methods->get_authentic_pixels_from_handler;
4963 if (cache_methods->get_authentic_indexes_from_handler !=
4964 (GetAuthenticIndexesFromHandler) NULL)
4965 cache_info->methods.get_authentic_indexes_from_handler=
4966 cache_methods->get_authentic_indexes_from_handler;
4967 get_one_virtual_pixel_from_handler=
4968 cache_info->methods.get_one_virtual_pixel_from_handler;
4969 if (get_one_virtual_pixel_from_handler !=
4970 (GetOneVirtualPixelFromHandler) NULL)
4971 cache_info->methods.get_one_virtual_pixel_from_handler=
4972 cache_methods->get_one_virtual_pixel_from_handler;
4973 get_one_authentic_pixel_from_handler=
4974 cache_methods->get_one_authentic_pixel_from_handler;
4975 if (get_one_authentic_pixel_from_handler !=
4976 (GetOneAuthenticPixelFromHandler) NULL)
4977 cache_info->methods.get_one_authentic_pixel_from_handler=
4978 cache_methods->get_one_authentic_pixel_from_handler;
4979}
4980
4981/*
4982%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4983% %
4984% %
4985% %
4986+ S e t P i x e l C a c h e N e x u s P i x e l s %
4987% %
4988% %
4989% %
4990%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4991%
4992% SetPixelCacheNexusPixels() defines the region of the cache for the
4993% specified cache nexus.
4994%
4995% The format of the SetPixelCacheNexusPixels() method is:
4996%
4997% PixelPacket SetPixelCacheNexusPixels(const Image *image,
4998% const RectangleInfo *region,NexusInfo *nexus_info,
4999% ExceptionInfo *exception)
5000%
5001% A description of each parameter follows:
5002%
5003% o image: the image.
5004%
5005% o region: A pointer to the RectangleInfo structure that defines the
5006% region of this particular cache nexus.
5007%
5008% o nexus_info: the cache nexus to set.
5009%
5010% o exception: return any errors or warnings in this structure.
5011%
5012*/
5013static PixelPacket *SetPixelCacheNexusPixels(const Image *image,
5014 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
5015{
5016 CacheInfo
5017 *cache_info;
5018
5019 MagickBooleanType
5020 status;
5021
cristy3ed852e2009-09-05 21:47:34 +00005022 MagickSizeType
5023 length,
5024 number_pixels;
5025
cristy3ed852e2009-09-05 21:47:34 +00005026 cache_info=(CacheInfo *) image->cache;
5027 assert(cache_info->signature == MagickSignature);
5028 if (cache_info->type == UndefinedCache)
5029 return((PixelPacket *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00005030 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00005031 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
5032 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00005033 {
cristybb503372010-05-27 20:51:26 +00005034 ssize_t
cristybad067a2010-02-15 17:20:55 +00005035 x,
5036 y;
cristy3ed852e2009-09-05 21:47:34 +00005037
cristyeaedf062010-05-29 22:36:02 +00005038 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
5039 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00005040 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5041 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristy731c3532010-02-15 15:40:03 +00005042 ((nexus_info->region.height == 1UL) ||
5043 ((nexus_info->region.x == 0) &&
5044 ((nexus_info->region.width == cache_info->columns) ||
5045 ((nexus_info->region.width % cache_info->columns) == 0)))))
5046 {
5047 MagickOffsetType
5048 offset;
5049
5050 /*
5051 Pixels are accessed directly from memory.
5052 */
5053 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5054 nexus_info->region.x;
5055 nexus_info->pixels=cache_info->pixels+offset;
5056 nexus_info->indexes=(IndexPacket *) NULL;
5057 if (cache_info->active_index_channel != MagickFalse)
5058 nexus_info->indexes=cache_info->indexes+offset;
5059 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00005060 }
5061 }
5062 /*
5063 Pixels are stored in a cache region until they are synced to the cache.
5064 */
5065 number_pixels=(MagickSizeType) nexus_info->region.width*
5066 nexus_info->region.height;
5067 length=number_pixels*sizeof(PixelPacket);
5068 if (cache_info->active_index_channel != MagickFalse)
5069 length+=number_pixels*sizeof(IndexPacket);
5070 if (nexus_info->cache == (PixelPacket *) NULL)
5071 {
5072 nexus_info->length=length;
5073 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5074 if (status == MagickFalse)
5075 return((PixelPacket *) NULL);
5076 }
5077 else
5078 if (nexus_info->length != length)
5079 {
5080 RelinquishCacheNexusPixels(nexus_info);
5081 nexus_info->length=length;
5082 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5083 if (status == MagickFalse)
5084 return((PixelPacket *) NULL);
5085 }
5086 nexus_info->pixels=nexus_info->cache;
5087 nexus_info->indexes=(IndexPacket *) NULL;
5088 if (cache_info->active_index_channel != MagickFalse)
5089 nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
5090 return(nexus_info->pixels);
5091}
5092
5093/*
5094%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5095% %
5096% %
5097% %
5098% 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 %
5099% %
5100% %
5101% %
5102%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5103%
5104% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5105% pixel cache and returns the previous setting. A virtual pixel is any pixel
5106% access that is outside the boundaries of the image cache.
5107%
5108% The format of the SetPixelCacheVirtualMethod() method is:
5109%
5110% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5111% const VirtualPixelMethod virtual_pixel_method)
5112%
5113% A description of each parameter follows:
5114%
5115% o image: the image.
5116%
5117% o virtual_pixel_method: choose the type of virtual pixel.
5118%
5119*/
5120MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5121 const VirtualPixelMethod virtual_pixel_method)
5122{
5123 CacheInfo
5124 *cache_info;
5125
5126 VirtualPixelMethod
5127 method;
5128
5129 assert(image != (Image *) NULL);
5130 assert(image->signature == MagickSignature);
5131 if (image->debug != MagickFalse)
5132 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5133 assert(image->cache != (Cache) NULL);
5134 cache_info=(CacheInfo *) image->cache;
5135 assert(cache_info->signature == MagickSignature);
5136 method=cache_info->virtual_pixel_method;
5137 cache_info->virtual_pixel_method=virtual_pixel_method;
5138 return(method);
5139}
5140
5141/*
5142%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5143% %
5144% %
5145% %
5146+ 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 %
5147% %
5148% %
5149% %
5150%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5151%
5152% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5153% in-memory or disk cache. The method returns MagickTrue if the pixel region
5154% is synced, otherwise MagickFalse.
5155%
5156% The format of the SyncAuthenticPixelCacheNexus() method is:
5157%
5158% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5159% NexusInfo *nexus_info,ExceptionInfo *exception)
5160%
5161% A description of each parameter follows:
5162%
5163% o image: the image.
5164%
5165% o nexus_info: the cache nexus to sync.
5166%
5167% o exception: return any errors or warnings in this structure.
5168%
5169*/
5170MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5171 NexusInfo *nexus_info,ExceptionInfo *exception)
5172{
5173 CacheInfo
5174 *cache_info;
5175
5176 MagickBooleanType
5177 status;
5178
5179 /*
5180 Transfer pixels to the cache.
5181 */
5182 assert(image != (Image *) NULL);
5183 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005184 if (image->cache == (Cache) NULL)
5185 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5186 cache_info=(CacheInfo *) image->cache;
5187 if (cache_info->type == UndefinedCache)
5188 return(MagickFalse);
5189 if ((image->clip_mask != (Image *) NULL) &&
5190 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5191 return(MagickFalse);
5192 if ((image->mask != (Image *) NULL) &&
5193 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5194 return(MagickFalse);
5195 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5196 return(MagickTrue);
5197 assert(cache_info->signature == MagickSignature);
5198 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5199 if ((cache_info->active_index_channel != MagickFalse) &&
5200 (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
5201 return(MagickFalse);
5202 return(status);
5203}
5204
5205/*
5206%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5207% %
5208% %
5209% %
5210+ S y n c A u t h e n t i c P i x e l C a c h e %
5211% %
5212% %
5213% %
5214%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5215%
5216% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5217% or disk cache. The method returns MagickTrue if the pixel region is synced,
5218% otherwise MagickFalse.
5219%
5220% The format of the SyncAuthenticPixelsCache() method is:
5221%
5222% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5223% ExceptionInfo *exception)
5224%
5225% A description of each parameter follows:
5226%
5227% o image: the image.
5228%
5229% o exception: return any errors or warnings in this structure.
5230%
5231*/
5232static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5233 ExceptionInfo *exception)
5234{
5235 CacheInfo
5236 *cache_info;
5237
cristy6ebe97c2010-07-03 01:17:28 +00005238 int
cristy3ed852e2009-09-05 21:47:34 +00005239 id;
5240
5241 MagickBooleanType
5242 status;
5243
5244 cache_info=(CacheInfo *) image->cache;
5245 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00005246 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00005247 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5248 exception);
5249 return(status);
5250}
5251
5252/*
5253%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5254% %
5255% %
5256% %
5257% S y n c A u t h e n t i c P i x e l s %
5258% %
5259% %
5260% %
5261%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5262%
5263% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5264% The method returns MagickTrue if the pixel region is flushed, otherwise
5265% MagickFalse.
5266%
5267% The format of the SyncAuthenticPixels() method is:
5268%
5269% MagickBooleanType SyncAuthenticPixels(Image *image,
5270% ExceptionInfo *exception)
5271%
5272% A description of each parameter follows:
5273%
5274% o image: the image.
5275%
5276% o exception: return any errors or warnings in this structure.
5277%
5278*/
5279MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5280 ExceptionInfo *exception)
5281{
5282 CacheInfo
5283 *cache_info;
5284
5285 assert(image != (Image *) NULL);
5286 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005287 assert(image->cache != (Cache) NULL);
5288 cache_info=(CacheInfo *) image->cache;
5289 assert(cache_info->signature == MagickSignature);
5290 if (cache_info->methods.sync_authentic_pixels_handler ==
5291 (SyncAuthenticPixelsHandler) NULL)
5292 return(MagickFalse);
5293 return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
5294}
5295
5296/*
5297%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5298% %
5299% %
5300% %
5301+ W r i t e P i x e l C a c h e I n d e x e s %
5302% %
5303% %
5304% %
5305%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5306%
5307% WritePixelCacheIndexes() writes the colormap indexes to the specified
5308% region of the pixel cache.
5309%
5310% The format of the WritePixelCacheIndexes() method is:
5311%
5312% MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5313% NexusInfo *nexus_info,ExceptionInfo *exception)
5314%
5315% A description of each parameter follows:
5316%
5317% o cache_info: the pixel cache.
5318%
5319% o nexus_info: the cache nexus to write the colormap indexes.
5320%
5321% o exception: return any errors or warnings in this structure.
5322%
5323*/
5324static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5325 NexusInfo *nexus_info,ExceptionInfo *exception)
5326{
5327 MagickOffsetType
5328 count,
5329 offset;
5330
5331 MagickSizeType
5332 length,
5333 number_pixels;
5334
5335 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005336 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005337
cristybb503372010-05-27 20:51:26 +00005338 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005339 y;
5340
cristybb503372010-05-27 20:51:26 +00005341 size_t
cristy3ed852e2009-09-05 21:47:34 +00005342 rows;
5343
cristy3ed852e2009-09-05 21:47:34 +00005344 if (cache_info->active_index_channel == MagickFalse)
5345 return(MagickFalse);
5346 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5347 return(MagickTrue);
5348 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5349 nexus_info->region.x;
5350 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
5351 rows=nexus_info->region.height;
5352 number_pixels=(MagickSizeType) length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005353 p=nexus_info->indexes;
5354 switch (cache_info->type)
5355 {
5356 case MemoryCache:
5357 case MapCache:
5358 {
5359 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005360 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005361
5362 /*
5363 Write indexes to memory.
5364 */
cristydd341db2010-03-04 19:06:38 +00005365 if ((cache_info->columns == nexus_info->region.width) &&
5366 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5367 {
5368 length=number_pixels;
5369 rows=1UL;
5370 }
cristy3ed852e2009-09-05 21:47:34 +00005371 q=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00005372 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005373 {
5374 (void) CopyMagickMemory(q,p,(size_t) length);
5375 p+=nexus_info->region.width;
5376 q+=cache_info->columns;
5377 }
5378 break;
5379 }
5380 case DiskCache:
5381 {
5382 /*
5383 Write indexes to disk.
5384 */
5385 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5386 {
5387 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5388 cache_info->cache_filename);
5389 return(MagickFalse);
5390 }
cristydd341db2010-03-04 19:06:38 +00005391 if ((cache_info->columns == nexus_info->region.width) &&
5392 (number_pixels < MagickMaxBufferExtent))
5393 {
5394 length=number_pixels;
5395 rows=1UL;
5396 }
cristy3ed852e2009-09-05 21:47:34 +00005397 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005398 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005399 {
5400 count=WritePixelCacheRegion(cache_info,cache_info->offset+number_pixels*
5401 sizeof(PixelPacket)+offset*sizeof(*p),length,
5402 (const unsigned char *) p);
5403 if ((MagickSizeType) count < length)
5404 break;
5405 p+=nexus_info->region.width;
5406 offset+=cache_info->columns;
5407 }
cristybb503372010-05-27 20:51:26 +00005408 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005409 {
5410 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5411 cache_info->cache_filename);
5412 return(MagickFalse);
5413 }
5414 break;
5415 }
5416 default:
5417 break;
5418 }
5419 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005420 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005421 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005422 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005423 nexus_info->region.width,(double) nexus_info->region.height,(double)
5424 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005425 return(MagickTrue);
5426}
5427
5428/*
5429%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5430% %
5431% %
5432% %
5433+ W r i t e C a c h e P i x e l s %
5434% %
5435% %
5436% %
5437%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5438%
5439% WritePixelCachePixels() writes image pixels to the specified region of the
5440% pixel cache.
5441%
5442% The format of the WritePixelCachePixels() method is:
5443%
5444% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5445% NexusInfo *nexus_info,ExceptionInfo *exception)
5446%
5447% A description of each parameter follows:
5448%
5449% o cache_info: the pixel cache.
5450%
5451% o nexus_info: the cache nexus to write the pixels.
5452%
5453% o exception: return any errors or warnings in this structure.
5454%
5455*/
5456static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5457 NexusInfo *nexus_info,ExceptionInfo *exception)
5458{
5459 MagickOffsetType
5460 count,
5461 offset;
5462
5463 MagickSizeType
5464 length,
5465 number_pixels;
5466
cristy3ed852e2009-09-05 21:47:34 +00005467 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005468 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005469
cristybb503372010-05-27 20:51:26 +00005470 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005471 y;
5472
cristybb503372010-05-27 20:51:26 +00005473 size_t
cristy3ed852e2009-09-05 21:47:34 +00005474 rows;
5475
cristy3ed852e2009-09-05 21:47:34 +00005476 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5477 return(MagickTrue);
5478 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5479 nexus_info->region.x;
5480 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
5481 rows=nexus_info->region.height;
5482 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005483 p=nexus_info->pixels;
5484 switch (cache_info->type)
5485 {
5486 case MemoryCache:
5487 case MapCache:
5488 {
5489 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005490 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005491
5492 /*
5493 Write pixels to memory.
5494 */
cristydd341db2010-03-04 19:06:38 +00005495 if ((cache_info->columns == nexus_info->region.width) &&
5496 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5497 {
5498 length=number_pixels;
5499 rows=1UL;
5500 }
cristy3ed852e2009-09-05 21:47:34 +00005501 q=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00005502 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005503 {
5504 (void) CopyMagickMemory(q,p,(size_t) length);
5505 p+=nexus_info->region.width;
5506 q+=cache_info->columns;
5507 }
5508 break;
5509 }
5510 case DiskCache:
5511 {
5512 /*
5513 Write pixels to disk.
5514 */
5515 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5516 {
5517 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5518 cache_info->cache_filename);
5519 return(MagickFalse);
5520 }
cristydd341db2010-03-04 19:06:38 +00005521 if ((cache_info->columns == nexus_info->region.width) &&
5522 (number_pixels < MagickMaxBufferExtent))
5523 {
5524 length=number_pixels;
5525 rows=1UL;
5526 }
cristybb503372010-05-27 20:51:26 +00005527 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005528 {
5529 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5530 sizeof(*p),length,(const unsigned char *) p);
5531 if ((MagickSizeType) count < length)
5532 break;
5533 p+=nexus_info->region.width;
5534 offset+=cache_info->columns;
5535 }
cristybb503372010-05-27 20:51:26 +00005536 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005537 {
5538 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5539 cache_info->cache_filename);
5540 return(MagickFalse);
5541 }
5542 break;
5543 }
5544 default:
5545 break;
5546 }
5547 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005548 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005549 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005550 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005551 nexus_info->region.width,(double) nexus_info->region.height,(double)
5552 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005553 return(MagickTrue);
5554}