blob: 0af1ded3d4a7b79e44b1062dd859f1cd2af5098c [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*/
250MagickExport NexusInfo **AcquirePixelCacheNexus(
cristybb503372010-05-27 20:51:26 +0000251 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000252{
cristybb503372010-05-27 20:51:26 +0000253 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000254 i;
255
256 NexusInfo
257 **nexus_info;
258
259 nexus_info=(NexusInfo **) AcquireAlignedMemory(number_threads,
260 sizeof(*nexus_info));
261 if (nexus_info == (NexusInfo **) NULL)
262 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristybb503372010-05-27 20:51:26 +0000263 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000264 {
265 nexus_info[i]=(NexusInfo *) AcquireAlignedMemory(1,sizeof(**nexus_info));
266 if (nexus_info[i] == (NexusInfo *) NULL)
267 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
268 (void) ResetMagickMemory(nexus_info[i],0,sizeof(*nexus_info[i]));
269 nexus_info[i]->signature=MagickSignature;
270 }
271 return(nexus_info);
272}
273
274/*
275%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
276% %
277% %
278% %
cristyd43a46b2010-01-21 02:13:41 +0000279+ A c q u i r e P i x e l C a c h e P i x e l s %
280% %
281% %
282% %
283%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
284%
285% AcquirePixelCachePixels() returns the pixels associated with the specified
286% image.
287%
288% The format of the AcquirePixelCachePixels() method is:
289%
290% const void *AcquirePixelCachePixels(const Image *image,
291% MagickSizeType *length,ExceptionInfo *exception)
292%
293% A description of each parameter follows:
294%
295% o image: the image.
296%
297% o length: the pixel cache length.
298%
299% o exception: return any errors or warnings in this structure.
300%
301*/
302MagickExport const void *AcquirePixelCachePixels(const Image *image,
303 MagickSizeType *length,ExceptionInfo *exception)
304{
305 CacheInfo
306 *cache_info;
307
308 assert(image != (const Image *) NULL);
309 assert(image->signature == MagickSignature);
cristyd43a46b2010-01-21 02:13:41 +0000310 assert(exception != (ExceptionInfo *) NULL);
311 assert(exception->signature == MagickSignature);
312 assert(image->cache != (Cache) NULL);
313 cache_info=(CacheInfo *) image->cache;
314 assert(cache_info->signature == MagickSignature);
315 *length=0;
316 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
317 return((const void *) NULL);
318 *length=cache_info->length;
319 return((const void *) cache_info->pixels);
320}
321
322/*
323%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
324% %
325% %
326% %
cristyf34a1452009-10-24 22:29:27 +0000327+ C a c h e C o m p o n e n t G e n e s i s %
328% %
329% %
330% %
331%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
332%
333% CacheComponentGenesis() instantiates the cache component.
334%
335% The format of the CacheComponentGenesis method is:
336%
337% MagickBooleanType CacheComponentGenesis(void)
338%
339*/
340MagickExport MagickBooleanType CacheComponentGenesis(void)
341{
cristy165b6092009-10-26 13:52:10 +0000342 AcquireSemaphoreInfo(&cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000343 return(MagickTrue);
344}
345
346/*
347%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
348% %
349% %
350% %
351+ C a c h e C o m p o n e n t T e r m i n u s %
352% %
353% %
354% %
355%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
356%
357% CacheComponentTerminus() destroys the cache component.
358%
359% The format of the CacheComponentTerminus() method is:
360%
361% CacheComponentTerminus(void)
362%
363*/
364MagickExport void CacheComponentTerminus(void)
365{
cristy18b17442009-10-25 18:36:48 +0000366 if (cache_semaphore == (SemaphoreInfo *) NULL)
367 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000368 LockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000369 if (cache_resources != (SplayTreeInfo *) NULL)
370 cache_resources=DestroySplayTree(cache_resources);
371 instantiate_cache=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +0000372 UnlockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000373 DestroySemaphoreInfo(&cache_semaphore);
374}
375
376/*
377%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
378% %
379% %
380% %
cristy3ed852e2009-09-05 21:47:34 +0000381+ C l i p P i x e l C a c h e N e x u s %
382% %
383% %
384% %
385%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
386%
387% ClipPixelCacheNexus() clips the cache nexus as defined by the image clip
388% mask. The method returns MagickTrue if the pixel region is clipped,
389% otherwise MagickFalse.
390%
391% The format of the ClipPixelCacheNexus() method is:
392%
393% MagickBooleanType ClipPixelCacheNexus(Image *image,NexusInfo *nexus_info,
394% ExceptionInfo *exception)
395%
396% A description of each parameter follows:
397%
398% o image: the image.
399%
400% o nexus_info: the cache nexus to clip.
401%
402% o exception: return any errors or warnings in this structure.
403%
404*/
405static MagickBooleanType ClipPixelCacheNexus(Image *image,
406 NexusInfo *nexus_info,ExceptionInfo *exception)
407{
408 CacheInfo
409 *cache_info;
410
411 MagickSizeType
412 number_pixels;
413
414 NexusInfo
415 **clip_nexus,
416 **image_nexus;
417
418 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000419 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +0000420
421 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +0000422 *restrict nexus_indexes,
423 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +0000424
cristybb503372010-05-27 20:51:26 +0000425 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000426 i;
427
428 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000429 *restrict p,
430 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000431
432 /*
433 Apply clip mask.
434 */
435 if (image->debug != MagickFalse)
436 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
437 if (image->clip_mask == (Image *) NULL)
438 return(MagickFalse);
439 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
440 if (cache_info == (Cache) NULL)
441 return(MagickFalse);
442 image_nexus=AcquirePixelCacheNexus(1);
443 clip_nexus=AcquirePixelCacheNexus(1);
444 if ((image_nexus == (NexusInfo **) NULL) ||
445 (clip_nexus == (NexusInfo **) NULL))
446 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
447 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,nexus_info->region.y,
448 nexus_info->region.width,nexus_info->region.height,image_nexus[0],
449 exception);
450 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
451 q=nexus_info->pixels;
452 nexus_indexes=nexus_info->indexes;
453 r=GetVirtualPixelsFromNexus(image->clip_mask,MaskVirtualPixelMethod,
454 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
455 nexus_info->region.height,clip_nexus[0],exception);
456 number_pixels=(MagickSizeType) nexus_info->region.width*
457 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +0000458 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000459 {
460 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
461 break;
462 if (PixelIntensityToQuantum(r) > ((Quantum) QuantumRange/2))
463 {
cristyce70c172010-01-07 17:15:30 +0000464 SetRedPixelComponent(q,GetRedPixelComponent(p));
465 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
466 SetBluePixelComponent(q,GetBluePixelComponent(p));
467 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
cristy3ed852e2009-09-05 21:47:34 +0000468 if (cache_info->active_index_channel != MagickFalse)
469 nexus_indexes[i]=indexes[i];
470 }
471 p++;
472 q++;
473 r++;
474 }
475 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
476 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +0000477 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +0000478 return(MagickFalse);
479 return(MagickTrue);
480}
481
482/*
483%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
484% %
485% %
486% %
487+ C l o n e P i x e l C a c h e %
488% %
489% %
490% %
491%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
492%
493% ClonePixelCache() clones a pixel cache.
494%
495% The format of the ClonePixelCache() method is:
496%
497% Cache ClonePixelCache(const Cache cache)
498%
499% A description of each parameter follows:
500%
501% o cache: the pixel cache.
502%
503*/
504MagickExport Cache ClonePixelCache(const Cache cache)
505{
506 CacheInfo
507 *clone_info;
508
509 const CacheInfo
510 *cache_info;
511
512 assert(cache != (const Cache) NULL);
513 cache_info=(const CacheInfo *) cache;
514 assert(cache_info->signature == MagickSignature);
515 if (cache_info->debug != MagickFalse)
516 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
517 cache_info->filename);
518 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
519 if (clone_info == (Cache) NULL)
520 return((Cache) NULL);
521 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
522 return((Cache ) clone_info);
523}
524
525/*
526%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
527% %
528% %
529% %
530+ C l o n e P i x e l C a c h e N e x u s %
531% %
532% %
533% %
534%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
535%
536% ClonePixelCacheNexus() clones the source cache nexus to the destination
537% nexus.
538%
539% The format of the ClonePixelCacheNexus() method is:
540%
541% MagickBooleanType ClonePixelCacheNexus(CacheInfo *destination,
542% CacheInfo *source,ExceptionInfo *exception)
543%
544% A description of each parameter follows:
545%
546% o destination: the destination cache nexus.
547%
548% o source: the source cache nexus.
549%
550% o exception: return any errors or warnings in this structure.
551%
552*/
553
554static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
555 NexusInfo *nexus_info,ExceptionInfo *exception)
556{
557 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
558 return(MagickFalse);
559 nexus_info->mapped=MagickFalse;
560 nexus_info->cache=(PixelPacket *) AcquireMagickMemory((size_t)
561 nexus_info->length);
562 if (nexus_info->cache == (PixelPacket *) NULL)
563 {
564 nexus_info->mapped=MagickTrue;
565 nexus_info->cache=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
566 nexus_info->length);
567 }
568 if (nexus_info->cache == (PixelPacket *) NULL)
569 {
570 (void) ThrowMagickException(exception,GetMagickModule(),
571 ResourceLimitError,"MemoryAllocationFailed","`%s'",
572 cache_info->filename);
573 return(MagickFalse);
574 }
575 return(MagickTrue);
576}
577
578static MagickBooleanType ClonePixelCacheNexus(CacheInfo *destination,
579 CacheInfo *source,ExceptionInfo *exception)
580{
581 MagickBooleanType
582 status;
583
584 MagickSizeType
585 number_pixels;
586
cristybb503372010-05-27 20:51:26 +0000587 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000588 i;
589
590 register const NexusInfo
591 *p;
592
593 register NexusInfo
594 *q;
595
596 status=MagickTrue;
cristybb503372010-05-27 20:51:26 +0000597 for (i=0; i < (ssize_t) source->number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000598 {
599 p=source->nexus_info[i];
600 q=destination->nexus_info[i];
601 q->mapped=p->mapped;
602 q->region=p->region;
603 q->length=p->length;
604 q->cache=p->cache;
605 q->pixels=p->pixels;
606 q->indexes=p->indexes;
607 if (p->cache != (PixelPacket *) NULL)
608 {
609 status=AcquireCacheNexusPixels(source,q,exception);
610 if (status != MagickFalse)
611 {
612 (void) CopyMagickMemory(q->cache,p->cache,(size_t) p->length);
613 q->pixels=q->cache;
614 q->indexes=(IndexPacket *) NULL;
615 number_pixels=(MagickSizeType) q->region.width*q->region.height;
616 if (p->indexes != (IndexPacket *) NULL)
617 q->indexes=(IndexPacket *) (q->pixels+number_pixels);
618 }
619 }
620 }
621 return(status);
622}
623
624/*
625%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
626% %
627% %
628% %
cristy60c44a82009-10-07 00:58:49 +0000629+ C l o n e P i x e l C a c h e P i x e l s %
cristy3ed852e2009-09-05 21:47:34 +0000630% %
631% %
632% %
633%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
634% ClonePixelCachePixels() clones the source pixel cache to the destination
635% cache.
636%
637% The format of the ClonePixelCachePixels() method is:
638%
639% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
640% CacheInfo *source_info,ExceptionInfo *exception)
641%
642% A description of each parameter follows:
643%
644% o cache_info: the pixel cache.
645%
646% o source_info: the source pixel cache.
647%
648% o exception: return any errors or warnings in this structure.
649%
650*/
651
652static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
653{
654 int
655 status;
656
cristy5ee247a2010-02-12 15:42:34 +0000657 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000658 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000659 if (cache_info->file != -1)
660 status=close(cache_info->file);
cristy3ed852e2009-09-05 21:47:34 +0000661 cache_info->file=(-1);
662 RelinquishMagickResource(FileResource,1);
cristyf84a1932010-01-03 18:00:18 +0000663 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000664 return(status == -1 ? MagickFalse : MagickTrue);
665}
666
667static void LimitPixelCacheDescriptors(void)
668{
669 register CacheInfo
670 *p,
671 *q;
672
673 /*
674 Limit # of open file descriptors.
675 */
676 if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
677 return;
cristyf84a1932010-01-03 18:00:18 +0000678 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000679 if (cache_resources == (SplayTreeInfo *) NULL)
680 {
cristyf84a1932010-01-03 18:00:18 +0000681 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000682 return;
683 }
684 ResetSplayTreeIterator(cache_resources);
685 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
686 while (p != (CacheInfo *) NULL)
687 {
688 if ((p->type == DiskCache) && (p->file != -1))
cristy508d9312010-02-10 21:10:30 +0000689 break;
cristy3ed852e2009-09-05 21:47:34 +0000690 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
691 }
692 for (q=p; p != (CacheInfo *) NULL; )
693 {
694 if ((p->type == DiskCache) && (p->file != -1) &&
695 (p->timestamp < q->timestamp))
cristy508d9312010-02-10 21:10:30 +0000696 q=p;
cristy3ed852e2009-09-05 21:47:34 +0000697 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
698 }
699 if (q != (CacheInfo *) NULL)
cristy9e116922010-02-12 20:58:13 +0000700 {
701 /*
702 Close least recently used cache.
703 */
704 (void) close(q->file);
705 q->file=(-1);
706 }
cristyf84a1932010-01-03 18:00:18 +0000707 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000708}
709
710static inline MagickSizeType MagickMax(const MagickSizeType x,
711 const MagickSizeType y)
712{
713 if (x > y)
714 return(x);
715 return(y);
716}
717
718static inline MagickSizeType MagickMin(const MagickSizeType x,
719 const MagickSizeType y)
720{
721 if (x < y)
722 return(x);
723 return(y);
724}
725
726static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
727 const MapMode mode)
728{
729 int
730 file;
731
732 /*
733 Open pixel cache on disk.
734 */
cristyf84a1932010-01-03 18:00:18 +0000735 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000736 if (cache_info->file != -1)
737 {
cristyf84a1932010-01-03 18:00:18 +0000738 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000739 return(MagickTrue); /* cache already open */
740 }
741 LimitPixelCacheDescriptors();
742 if (*cache_info->cache_filename == '\0')
743 file=AcquireUniqueFileResource(cache_info->cache_filename);
744 else
745 switch (mode)
746 {
747 case ReadMode:
748 {
749 file=open(cache_info->cache_filename,O_RDONLY | O_BINARY);
750 break;
751 }
752 case WriteMode:
753 {
754 file=open(cache_info->cache_filename,O_WRONLY | O_CREAT | O_BINARY |
755 O_EXCL,S_MODE);
756 if (file == -1)
757 file=open(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
758 break;
759 }
760 case IOMode:
761 default:
762 {
763 file=open(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
764 O_EXCL,S_MODE);
765 if (file == -1)
766 file=open(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
767 break;
768 }
769 }
770 if (file == -1)
771 {
cristyf84a1932010-01-03 18:00:18 +0000772 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000773 return(MagickFalse);
774 }
775 (void) AcquireMagickResource(FileResource,1);
776 cache_info->file=file;
777 cache_info->timestamp=time(0);
cristyf84a1932010-01-03 18:00:18 +0000778 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000779 return(MagickTrue);
780}
781
782static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
783 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000784 unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000785{
786 register MagickOffsetType
787 i;
788
789 ssize_t
790 count;
791
cristy08a88202010-03-04 19:18:05 +0000792 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000793#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000794 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000795 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
796 {
cristyf84a1932010-01-03 18:00:18 +0000797 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000798 return((MagickOffsetType) -1);
799 }
800#endif
801 count=0;
802 for (i=0; i < (MagickOffsetType) length; i+=count)
803 {
804#if !defined(MAGICKCORE_HAVE_PREAD)
805 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
806 (MagickSizeType) SSIZE_MAX));
807#else
808 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
809 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
810#endif
811 if (count > 0)
812 continue;
813 count=0;
814 if (errno != EINTR)
815 {
816 i=(-1);
817 break;
818 }
819 }
820#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000821 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000822#endif
823 return(i);
824}
825
826static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
827 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000828 const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000829{
830 register MagickOffsetType
831 i;
832
833 ssize_t
834 count;
835
cristy08a88202010-03-04 19:18:05 +0000836 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000837#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000838 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000839 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
840 {
cristyf84a1932010-01-03 18:00:18 +0000841 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000842 return((MagickOffsetType) -1);
843 }
844#endif
845 count=0;
846 for (i=0; i < (MagickOffsetType) length; i+=count)
847 {
848#if !defined(MAGICKCORE_HAVE_PWRITE)
849 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
850 (MagickSizeType) SSIZE_MAX));
851#else
852 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
853 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
854#endif
855 if (count > 0)
856 continue;
857 count=0;
858 if (errno != EINTR)
859 {
860 i=(-1);
861 break;
862 }
863 }
864#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000865 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000866#endif
867 return(i);
868}
869
870static MagickBooleanType CloneDiskToDiskPixelCache(CacheInfo *clone_info,
871 CacheInfo *cache_info,ExceptionInfo *exception)
872{
873 MagickOffsetType
874 count,
875 offset,
876 source_offset;
877
878 MagickSizeType
879 length;
880
cristybb503372010-05-27 20:51:26 +0000881 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000882 y;
883
884 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000885 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +0000886
cristybb503372010-05-27 20:51:26 +0000887 size_t
cristy3ed852e2009-09-05 21:47:34 +0000888 columns,
889 rows;
890
891 if (cache_info->debug != MagickFalse)
892 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
893 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
894 {
895 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
896 clone_info->cache_filename);
897 return(MagickFalse);
898 }
899 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
900 {
901 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
902 cache_info->cache_filename);
903 return(MagickFalse);
904 }
cristybb503372010-05-27 20:51:26 +0000905 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
906 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +0000907 if ((clone_info->active_index_channel != MagickFalse) &&
908 (cache_info->active_index_channel != MagickFalse))
909 {
910 register IndexPacket
911 *indexes;
912
913 /*
914 Clone cache indexes.
915 */
916 length=MagickMax(clone_info->columns,cache_info->columns)*
917 sizeof(*indexes);
918 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
919 if (indexes == (IndexPacket *) NULL)
920 {
921 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
922 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
923 return(MagickFalse);
924 }
925 (void) ResetMagickMemory(indexes,0,(size_t) length);
926 length=columns*sizeof(*indexes);
927 source_offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
928 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
929 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
930 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +0000931 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000932 {
933 source_offset-=cache_info->columns*sizeof(*indexes);
934 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
935 length,(unsigned char *) indexes);
936 if ((MagickSizeType) count != length)
937 break;
938 offset-=clone_info->columns*sizeof(*indexes);
939 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
940 (unsigned char *) indexes);
941 if ((MagickSizeType) count != length)
942 break;
943 }
cristybb503372010-05-27 20:51:26 +0000944 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000945 {
946 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
947 ThrowFileException(exception,CacheError,"UnableToCloneCache",
948 cache_info->cache_filename);
949 return(MagickFalse);
950 }
951 if (clone_info->columns > cache_info->columns)
952 {
953 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
954 (void) ResetMagickMemory(indexes,0,(size_t) length);
955 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
956 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +0000957 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000958 {
959 offset-=clone_info->columns*sizeof(*indexes);
960 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
961 length,(unsigned char *) indexes);
962 if ((MagickSizeType) count != length)
963 break;
964 }
cristybb503372010-05-27 20:51:26 +0000965 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000966 {
967 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
968 ThrowFileException(exception,CacheError,"UnableToCloneCache",
969 cache_info->cache_filename);
970 return(MagickFalse);
971 }
972 }
973 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
974 }
975 /*
976 Clone cache pixels.
977 */
978 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
979 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
980 if (pixels == (PixelPacket *) NULL)
981 {
982 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
983 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
984 return(MagickFalse);
985 }
986 (void) ResetMagickMemory(pixels,0,(size_t) length);
987 length=columns*sizeof(*pixels);
988 source_offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
989 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +0000990 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000991 {
992 source_offset-=cache_info->columns*sizeof(*pixels);
993 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
994 length,(unsigned char *) pixels);
995 if ((MagickSizeType) count != length)
996 break;
997 offset-=clone_info->columns*sizeof(*pixels);
998 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
999 (unsigned char *) pixels);
1000 if ((MagickSizeType) count != length)
1001 break;
1002 }
cristybb503372010-05-27 20:51:26 +00001003 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001004 {
1005 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1006 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1007 cache_info->cache_filename);
1008 return(MagickFalse);
1009 }
1010 if (clone_info->columns > cache_info->columns)
1011 {
1012 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
1013 sizeof(*pixels);
1014 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1015 (void) ResetMagickMemory(pixels,0,(size_t) length);
cristybb503372010-05-27 20:51:26 +00001016 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001017 {
1018 offset-=clone_info->columns*sizeof(*pixels);
1019 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1020 (unsigned char *) pixels);
1021 if ((MagickSizeType) count != length)
1022 break;
1023 }
cristybb503372010-05-27 20:51:26 +00001024 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001025 {
1026 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1027 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1028 cache_info->cache_filename);
1029 return(MagickFalse);
1030 }
1031 }
1032 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1033 return(MagickTrue);
1034}
1035
1036static MagickBooleanType CloneDiskToMemoryPixelCache(CacheInfo *clone_info,
1037 CacheInfo *cache_info,ExceptionInfo *exception)
1038{
1039 MagickOffsetType
1040 count,
1041 offset;
1042
1043 MagickSizeType
1044 length;
1045
cristybb503372010-05-27 20:51:26 +00001046 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001047 y;
1048
1049 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001050 *restrict pixels,
1051 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00001052
cristybb503372010-05-27 20:51:26 +00001053 size_t
cristy3ed852e2009-09-05 21:47:34 +00001054 columns,
1055 rows;
1056
1057 if (cache_info->debug != MagickFalse)
1058 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
1059 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
1060 {
1061 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1062 cache_info->cache_filename);
1063 return(MagickFalse);
1064 }
cristybb503372010-05-27 20:51:26 +00001065 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1066 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001067 if ((clone_info->active_index_channel != MagickFalse) &&
1068 (cache_info->active_index_channel != MagickFalse))
1069 {
1070 register IndexPacket
1071 *indexes,
1072 *q;
1073
1074 /*
1075 Clone cache indexes.
1076 */
1077 length=MagickMax(clone_info->columns,cache_info->columns)*
1078 sizeof(*indexes);
1079 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1080 if (indexes == (IndexPacket *) NULL)
1081 {
1082 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1083 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1084 return(MagickFalse);
1085 }
1086 (void) ResetMagickMemory(indexes,0,(size_t) length);
1087 length=columns*sizeof(IndexPacket);
1088 offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
1089 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
1090 q=clone_info->indexes+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001091 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001092 {
1093 offset-=cache_info->columns*sizeof(IndexPacket);
1094 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,
1095 length,(unsigned char *) indexes);
1096 if ((MagickSizeType) count != length)
1097 break;
1098 q-=clone_info->columns;
1099 (void) CopyMagickMemory(q,indexes,(size_t) length);
1100 if ((MagickSizeType) count != length)
1101 break;
1102 }
cristybb503372010-05-27 20:51:26 +00001103 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001104 {
1105 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1106 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1107 cache_info->cache_filename);
1108 return(MagickFalse);
1109 }
1110 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1111 }
1112 /*
1113 Clone cache pixels.
1114 */
1115 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1116 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1117 if (pixels == (PixelPacket *) NULL)
1118 {
1119 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1120 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1121 return(MagickFalse);
1122 }
1123 (void) ResetMagickMemory(pixels,0,(size_t) length);
1124 length=columns*sizeof(*pixels);
1125 offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
1126 q=clone_info->pixels+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001127 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001128 {
1129 offset-=cache_info->columns*sizeof(*pixels);
1130 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,length,
1131 (unsigned char *) pixels);
1132 if ((MagickSizeType) count != length)
1133 break;
1134 q-=clone_info->columns;
1135 (void) CopyMagickMemory(q,pixels,(size_t) length);
1136 }
cristybb503372010-05-27 20:51:26 +00001137 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001138 {
1139 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1140 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1141 cache_info->cache_filename);
1142 return(MagickFalse);
1143 }
1144 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1145 return(MagickTrue);
1146}
1147
1148static MagickBooleanType CloneMemoryToDiskPixelCache(CacheInfo *clone_info,
1149 CacheInfo *cache_info,ExceptionInfo *exception)
1150{
1151 MagickOffsetType
1152 count,
1153 offset;
1154
1155 MagickSizeType
1156 length;
1157
cristybb503372010-05-27 20:51:26 +00001158 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001159 y;
1160
1161 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001162 *restrict p,
1163 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +00001164
cristybb503372010-05-27 20:51:26 +00001165 size_t
cristy3ed852e2009-09-05 21:47:34 +00001166 columns,
1167 rows;
1168
1169 if (cache_info->debug != MagickFalse)
1170 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
1171 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
1172 {
1173 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1174 clone_info->cache_filename);
1175 return(MagickFalse);
1176 }
cristybb503372010-05-27 20:51:26 +00001177 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1178 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001179 if ((clone_info->active_index_channel != MagickFalse) &&
1180 (cache_info->active_index_channel != MagickFalse))
1181 {
1182 register IndexPacket
1183 *p,
1184 *indexes;
1185
1186 /*
1187 Clone cache indexes.
1188 */
1189 length=MagickMax(clone_info->columns,cache_info->columns)*
1190 sizeof(*indexes);
1191 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1192 if (indexes == (IndexPacket *) NULL)
1193 {
1194 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1195 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1196 return(MagickFalse);
1197 }
1198 (void) ResetMagickMemory(indexes,0,(size_t) length);
1199 length=columns*sizeof(*indexes);
1200 p=cache_info->indexes+cache_info->columns*rows;
1201 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1202 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +00001203 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001204 {
1205 p-=cache_info->columns;
1206 (void) CopyMagickMemory(indexes,p,(size_t) length);
1207 offset-=clone_info->columns*sizeof(*indexes);
1208 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1209 (unsigned char *) indexes);
1210 if ((MagickSizeType) count != length)
1211 break;
1212 }
cristybb503372010-05-27 20:51:26 +00001213 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001214 {
1215 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1216 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1217 cache_info->cache_filename);
1218 return(MagickFalse);
1219 }
1220 if (clone_info->columns > cache_info->columns)
1221 {
1222 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
1223 (void) ResetMagickMemory(indexes,0,(size_t) length);
1224 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1225 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +00001226 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001227 {
1228 offset-=clone_info->columns*sizeof(*indexes);
1229 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
1230 length,(unsigned char *) indexes);
1231 if ((MagickSizeType) count != length)
1232 break;
1233 }
cristybb503372010-05-27 20:51:26 +00001234 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001235 {
1236 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1237 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1238 cache_info->cache_filename);
1239 return(MagickFalse);
1240 }
1241 }
1242 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1243 }
1244 /*
1245 Clone cache pixels.
1246 */
1247 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1248 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1249 if (pixels == (PixelPacket *) NULL)
1250 {
1251 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1252 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1253 return(MagickFalse);
1254 }
1255 (void) ResetMagickMemory(pixels,0,(size_t) length);
1256 length=columns*sizeof(*pixels);
1257 p=cache_info->pixels+cache_info->columns*rows;
1258 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +00001259 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001260 {
1261 p-=cache_info->columns;
1262 (void) CopyMagickMemory(pixels,p,(size_t) length);
1263 offset-=clone_info->columns*sizeof(*pixels);
1264 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1265 (unsigned char *) pixels);
1266 if ((MagickSizeType) count != length)
1267 break;
1268 }
cristybb503372010-05-27 20:51:26 +00001269 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001270 {
1271 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1272 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1273 cache_info->cache_filename);
1274 return(MagickFalse);
1275 }
1276 if (clone_info->columns > cache_info->columns)
1277 {
1278 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
1279 sizeof(*pixels);
1280 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1281 (void) ResetMagickMemory(pixels,0,(size_t) length);
cristybb503372010-05-27 20:51:26 +00001282 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001283 {
1284 offset-=clone_info->columns*sizeof(*pixels);
1285 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1286 (unsigned char *) pixels);
1287 if ((MagickSizeType) count != length)
1288 break;
1289 }
cristybb503372010-05-27 20:51:26 +00001290 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001291 {
1292 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1293 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1294 cache_info->cache_filename);
1295 return(MagickFalse);
1296 }
1297 }
1298 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1299 return(MagickTrue);
1300}
1301
1302static MagickBooleanType CloneMemoryToMemoryPixelCache(CacheInfo *clone_info,
1303 CacheInfo *cache_info,ExceptionInfo *magick_unused(exception))
1304{
cristybb503372010-05-27 20:51:26 +00001305 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001306 y;
1307
1308 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001309 *restrict pixels,
1310 *restrict source_pixels;
cristy3ed852e2009-09-05 21:47:34 +00001311
1312 size_t
1313 length;
1314
cristybb503372010-05-27 20:51:26 +00001315 size_t
cristy3ed852e2009-09-05 21:47:34 +00001316 columns,
1317 rows;
1318
1319 if (cache_info->debug != MagickFalse)
1320 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
cristybb503372010-05-27 20:51:26 +00001321 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1322 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001323 if ((clone_info->active_index_channel != MagickFalse) &&
1324 (cache_info->active_index_channel != MagickFalse))
1325 {
1326 register IndexPacket
1327 *indexes,
1328 *source_indexes;
1329
1330 /*
1331 Clone cache indexes.
1332 */
1333 length=columns*sizeof(*indexes);
1334 if (clone_info->columns == cache_info->columns)
1335 (void) CopyMagickMemory(clone_info->indexes,cache_info->indexes,
1336 length*rows);
1337 else
1338 {
1339 source_indexes=cache_info->indexes+cache_info->columns*rows;
1340 indexes=clone_info->indexes+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001341 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001342 {
1343 source_indexes-=cache_info->columns;
1344 indexes-=clone_info->columns;
1345 (void) CopyMagickMemory(indexes,source_indexes,length);
1346 }
1347 if (clone_info->columns > cache_info->columns)
1348 {
1349 length=(clone_info->columns-cache_info->columns)*
1350 sizeof(*indexes);
1351 indexes=clone_info->indexes+clone_info->columns*rows+
1352 cache_info->columns;
cristybb503372010-05-27 20:51:26 +00001353 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001354 {
1355 indexes-=clone_info->columns;
1356 (void) ResetMagickMemory(indexes,0,length);
1357 }
1358 }
1359 }
1360 }
1361 /*
1362 Clone cache pixels.
1363 */
1364 length=columns*sizeof(*pixels);
1365 if (clone_info->columns == cache_info->columns)
1366 (void) CopyMagickMemory(clone_info->pixels,cache_info->pixels,length*rows);
1367 else
1368 {
1369 source_pixels=cache_info->pixels+cache_info->columns*rows;
1370 pixels=clone_info->pixels+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001371 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001372 {
1373 source_pixels-=cache_info->columns;
1374 pixels-=clone_info->columns;
1375 (void) CopyMagickMemory(pixels,source_pixels,length);
1376 }
1377 if (clone_info->columns > cache_info->columns)
1378 {
1379 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1380 pixels=clone_info->pixels+clone_info->columns*rows+
1381 cache_info->columns;
cristybb503372010-05-27 20:51:26 +00001382 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001383 {
1384 pixels-=clone_info->columns;
1385 (void) ResetMagickMemory(pixels,0,length);
1386 }
1387 }
1388 }
1389 return(MagickTrue);
1390}
1391
1392static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1393 CacheInfo *cache_info,ExceptionInfo *exception)
1394{
1395 if ((clone_info->type != DiskCache) && (cache_info->type != DiskCache))
1396 return(CloneMemoryToMemoryPixelCache(clone_info,cache_info,exception));
1397 if ((clone_info->type == DiskCache) && (cache_info->type == DiskCache))
1398 return(CloneDiskToDiskPixelCache(clone_info,cache_info,exception));
1399 if (cache_info->type == DiskCache)
1400 return(CloneDiskToMemoryPixelCache(clone_info,cache_info,exception));
1401 return(CloneMemoryToDiskPixelCache(clone_info,cache_info,exception));
1402}
1403
1404/*
1405%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1406% %
1407% %
1408% %
1409+ C l o n e P i x e l C a c h e M e t h o d s %
1410% %
1411% %
1412% %
1413%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1414%
1415% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1416% another.
1417%
1418% The format of the ClonePixelCacheMethods() method is:
1419%
1420% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1421%
1422% A description of each parameter follows:
1423%
1424% o clone: Specifies a pointer to a Cache structure.
1425%
1426% o cache: the pixel cache.
1427%
1428*/
1429MagickExport void ClonePixelCacheMethods(Cache clone,const Cache cache)
1430{
1431 CacheInfo
1432 *cache_info,
1433 *source_info;
1434
1435 assert(clone != (Cache) NULL);
1436 source_info=(CacheInfo *) clone;
1437 assert(source_info->signature == MagickSignature);
1438 if (source_info->debug != MagickFalse)
1439 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1440 source_info->filename);
1441 assert(cache != (Cache) NULL);
1442 cache_info=(CacheInfo *) cache;
1443 assert(cache_info->signature == MagickSignature);
1444 source_info->methods=cache_info->methods;
1445}
1446
1447/*
1448%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1449% %
1450% %
1451% %
1452+ D e s t r o y I m a g e P i x e l C a c h e %
1453% %
1454% %
1455% %
1456%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1457%
1458% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1459%
1460% The format of the DestroyImagePixelCache() method is:
1461%
1462% void DestroyImagePixelCache(Image *image)
1463%
1464% A description of each parameter follows:
1465%
1466% o image: the image.
1467%
1468*/
1469static void DestroyImagePixelCache(Image *image)
1470{
1471 assert(image != (Image *) NULL);
1472 assert(image->signature == MagickSignature);
1473 if (image->debug != MagickFalse)
1474 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1475 if (image->cache == (void *) NULL)
1476 return;
1477 image->cache=DestroyPixelCache(image->cache);
1478}
1479
1480/*
1481%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1482% %
1483% %
1484% %
1485+ D e s t r o y I m a g e P i x e l s %
1486% %
1487% %
1488% %
1489%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1490%
1491% DestroyImagePixels() deallocates memory associated with the pixel cache.
1492%
1493% The format of the DestroyImagePixels() method is:
1494%
1495% void DestroyImagePixels(Image *image)
1496%
1497% A description of each parameter follows:
1498%
1499% o image: the image.
1500%
1501*/
1502MagickExport void DestroyImagePixels(Image *image)
1503{
1504 CacheInfo
1505 *cache_info;
1506
1507 assert(image != (const Image *) NULL);
1508 assert(image->signature == MagickSignature);
1509 if (image->debug != MagickFalse)
1510 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1511 assert(image->cache != (Cache) NULL);
1512 cache_info=(CacheInfo *) image->cache;
1513 assert(cache_info->signature == MagickSignature);
1514 if (cache_info->methods.destroy_pixel_handler == (DestroyPixelHandler) NULL)
1515 return;
1516 cache_info->methods.destroy_pixel_handler(image);
1517}
1518
1519/*
1520%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1521% %
1522% %
1523% %
1524+ D e s t r o y P i x e l C a c h e %
1525% %
1526% %
1527% %
1528%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1529%
1530% DestroyPixelCache() deallocates memory associated with the pixel cache.
1531%
1532% The format of the DestroyPixelCache() method is:
1533%
1534% Cache DestroyPixelCache(Cache cache)
1535%
1536% A description of each parameter follows:
1537%
1538% o cache: the pixel cache.
1539%
1540*/
1541
1542static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1543{
1544 switch (cache_info->type)
1545 {
1546 case MemoryCache:
1547 {
1548 if (cache_info->mapped == MagickFalse)
1549 cache_info->pixels=(PixelPacket *) RelinquishMagickMemory(
1550 cache_info->pixels);
1551 else
1552 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,
1553 (size_t) cache_info->length);
1554 RelinquishMagickResource(MemoryResource,cache_info->length);
1555 break;
1556 }
1557 case MapCache:
1558 {
1559 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,(size_t)
1560 cache_info->length);
1561 RelinquishMagickResource(MapResource,cache_info->length);
1562 }
1563 case DiskCache:
1564 {
1565 if (cache_info->file != -1)
1566 (void) ClosePixelCacheOnDisk(cache_info);
1567 RelinquishMagickResource(DiskResource,cache_info->length);
1568 break;
1569 }
1570 default:
1571 break;
1572 }
1573 cache_info->type=UndefinedCache;
1574 cache_info->mapped=MagickFalse;
1575 cache_info->indexes=(IndexPacket *) NULL;
1576}
1577
1578MagickExport Cache DestroyPixelCache(Cache cache)
1579{
1580 CacheInfo
1581 *cache_info;
1582
cristy3ed852e2009-09-05 21:47:34 +00001583 assert(cache != (Cache) NULL);
1584 cache_info=(CacheInfo *) cache;
1585 assert(cache_info->signature == MagickSignature);
1586 if (cache_info->debug != MagickFalse)
1587 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1588 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001589 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001590 cache_info->reference_count--;
1591 if (cache_info->reference_count != 0)
1592 {
cristyf84a1932010-01-03 18:00:18 +00001593 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001594 return((Cache) NULL);
1595 }
cristyf84a1932010-01-03 18:00:18 +00001596 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001597 if (cache_resources != (SplayTreeInfo *) NULL)
1598 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
cristy5b8de732009-09-10 23:50:40 +00001599 if (cache_info->debug != MagickFalse)
1600 {
1601 char
1602 message[MaxTextExtent];
1603
1604 (void) FormatMagickString(message,MaxTextExtent,"destroy %s",
1605 cache_info->filename);
1606 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1607 }
cristyc2e1bdd2009-09-10 23:43:34 +00001608 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1609 (cache_info->type != DiskCache)))
1610 RelinquishPixelCachePixels(cache_info);
1611 else
1612 {
1613 RelinquishPixelCachePixels(cache_info);
1614 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1615 }
cristy3ed852e2009-09-05 21:47:34 +00001616 *cache_info->cache_filename='\0';
1617 if (cache_info->nexus_info != (NexusInfo **) NULL)
1618 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1619 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001620 if (cache_info->random_info != (RandomInfo *) NULL)
1621 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001622 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1623 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1624 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1625 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001626 cache_info->signature=(~MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001627 cache_info=(CacheInfo *) RelinquishAlignedMemory(cache_info);
1628 cache=(Cache) NULL;
1629 return(cache);
1630}
1631
1632/*
1633%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1634% %
1635% %
1636% %
1637+ D e s t r o y P i x e l C a c h e N e x u s %
1638% %
1639% %
1640% %
1641%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1642%
1643% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1644%
1645% The format of the DestroyPixelCacheNexus() method is:
1646%
1647% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001648% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001649%
1650% A description of each parameter follows:
1651%
1652% o nexus_info: the nexus to destroy.
1653%
1654% o number_threads: the number of nexus threads.
1655%
1656*/
1657
1658static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1659{
1660 if (nexus_info->mapped == MagickFalse)
1661 (void) RelinquishMagickMemory(nexus_info->cache);
1662 else
1663 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1664 nexus_info->cache=(PixelPacket *) NULL;
1665 nexus_info->pixels=(PixelPacket *) NULL;
1666 nexus_info->indexes=(IndexPacket *) NULL;
1667 nexus_info->length=0;
1668 nexus_info->mapped=MagickFalse;
1669}
1670
1671MagickExport NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001672 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001673{
cristybb503372010-05-27 20:51:26 +00001674 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001675 i;
1676
1677 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001678 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001679 {
1680 if (nexus_info[i]->cache != (PixelPacket *) NULL)
1681 RelinquishCacheNexusPixels(nexus_info[i]);
1682 nexus_info[i]->signature=(~MagickSignature);
1683 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
1684 }
1685 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
1686 return(nexus_info);
1687}
1688
1689/*
1690%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1691% %
1692% %
1693% %
cristy3ed852e2009-09-05 21:47:34 +00001694+ 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 %
1695% %
1696% %
1697% %
1698%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1699%
1700% GetAuthenticIndexesFromCache() returns the indexes associated with the last
1701% call to QueueAuthenticPixelsCache() or GetAuthenticPixelsCache().
1702%
1703% The format of the GetAuthenticIndexesFromCache() method is:
1704%
1705% IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1706%
1707% A description of each parameter follows:
1708%
1709% o image: the image.
1710%
1711*/
1712static IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1713{
1714 CacheInfo
1715 *cache_info;
1716
1717 IndexPacket
1718 *indexes;
1719
cristy6ebe97c2010-07-03 01:17:28 +00001720 int
cristy3ed852e2009-09-05 21:47:34 +00001721 id;
1722
cristy3ed852e2009-09-05 21:47:34 +00001723 cache_info=(CacheInfo *) image->cache;
1724 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00001725 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001726 indexes=GetPixelCacheNexusIndexes(image->cache,cache_info->nexus_info[id]);
1727 return(indexes);
1728}
1729
1730/*
1731%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1732% %
1733% %
1734% %
1735% G e t A u t h e n t i c I n d e x Q u e u e %
1736% %
1737% %
1738% %
1739%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1740%
1741% GetAuthenticIndexQueue() returns the authentic black channel or the colormap
1742% indexes associated with the last call to QueueAuthenticPixels() or
1743% GetVirtualPixels(). NULL is returned if the black channel or colormap
1744% indexes are not available.
1745%
1746% The format of the GetAuthenticIndexQueue() method is:
1747%
1748% IndexPacket *GetAuthenticIndexQueue(const Image *image)
1749%
1750% A description of each parameter follows:
1751%
1752% o image: the image.
1753%
1754*/
1755MagickExport IndexPacket *GetAuthenticIndexQueue(const Image *image)
1756{
1757 CacheInfo
1758 *cache_info;
1759
1760 assert(image != (const Image *) NULL);
1761 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001762 assert(image->cache != (Cache) NULL);
1763 cache_info=(CacheInfo *) image->cache;
1764 assert(cache_info->signature == MagickSignature);
1765 if (cache_info->methods.get_authentic_indexes_from_handler ==
1766 (GetAuthenticIndexesFromHandler) NULL)
1767 return((IndexPacket *) NULL);
1768 return(cache_info->methods.get_authentic_indexes_from_handler(image));
1769}
1770
1771/*
1772%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1773% %
1774% %
1775% %
1776+ 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 %
1777% %
1778% %
1779% %
1780%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1781%
1782% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1783% disk pixel cache as defined by the geometry parameters. A pointer to the
1784% pixels is returned if the pixels are transferred, otherwise a NULL is
1785% returned.
1786%
1787% The format of the GetAuthenticPixelCacheNexus() method is:
1788%
cristybb503372010-05-27 20:51:26 +00001789% PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1790% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001791% NexusInfo *nexus_info,ExceptionInfo *exception)
1792%
1793% A description of each parameter follows:
1794%
1795% o image: the image.
1796%
1797% o x,y,columns,rows: These values define the perimeter of a region of
1798% pixels.
1799%
1800% o nexus_info: the cache nexus to return.
1801%
1802% o exception: return any errors or warnings in this structure.
1803%
1804*/
1805
1806static inline MagickBooleanType IsNexusInCore(const CacheInfo *cache_info,
1807 NexusInfo *nexus_info)
1808{
1809 MagickOffsetType
1810 offset;
1811
cristy73724512010-04-12 14:43:14 +00001812 if (cache_info->type == PingCache)
1813 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001814 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1815 nexus_info->region.x;
1816 if (nexus_info->pixels != (cache_info->pixels+offset))
1817 return(MagickFalse);
1818 return(MagickTrue);
1819}
1820
cristybb503372010-05-27 20:51:26 +00001821MagickExport PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1822 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001823 NexusInfo *nexus_info,ExceptionInfo *exception)
1824{
1825 CacheInfo
1826 *cache_info;
1827
1828 PixelPacket
1829 *pixels;
1830
1831 /*
1832 Transfer pixels from the cache.
1833 */
1834 assert(image != (Image *) NULL);
1835 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001836 pixels=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
1837 if (pixels == (PixelPacket *) NULL)
1838 return((PixelPacket *) NULL);
1839 cache_info=(CacheInfo *) image->cache;
1840 assert(cache_info->signature == MagickSignature);
1841 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
1842 return(pixels);
1843 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1844 return((PixelPacket *) NULL);
1845 if (cache_info->active_index_channel != MagickFalse)
1846 if (ReadPixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse)
1847 return((PixelPacket *) NULL);
1848 return(pixels);
1849}
1850
1851/*
1852%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1853% %
1854% %
1855% %
1856+ 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 %
1857% %
1858% %
1859% %
1860%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1861%
1862% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1863% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1864%
1865% The format of the GetAuthenticPixelsFromCache() method is:
1866%
1867% PixelPacket *GetAuthenticPixelsFromCache(const Image image)
1868%
1869% A description of each parameter follows:
1870%
1871% o image: the image.
1872%
1873*/
1874static PixelPacket *GetAuthenticPixelsFromCache(const Image *image)
1875{
1876 CacheInfo
1877 *cache_info;
1878
cristy6ebe97c2010-07-03 01:17:28 +00001879 int
cristy3ed852e2009-09-05 21:47:34 +00001880 id;
1881
1882 PixelPacket
1883 *pixels;
1884
cristy3ed852e2009-09-05 21:47:34 +00001885 cache_info=(CacheInfo *) image->cache;
1886 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00001887 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001888 pixels=GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]);
1889 return(pixels);
1890}
1891
1892/*
1893%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1894% %
1895% %
1896% %
1897% G e t A u t h e n t i c P i x e l Q u e u e %
1898% %
1899% %
1900% %
1901%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1902%
1903% GetAuthenticPixelQueue() returns the authentic pixels associated with the
1904% last call to QueueAuthenticPixels() or GetAuthenticPixels().
1905%
1906% The format of the GetAuthenticPixelQueue() method is:
1907%
1908% PixelPacket *GetAuthenticPixelQueue(const Image image)
1909%
1910% A description of each parameter follows:
1911%
1912% o image: the image.
1913%
1914*/
1915MagickExport PixelPacket *GetAuthenticPixelQueue(const Image *image)
1916{
1917 CacheInfo
1918 *cache_info;
1919
1920 assert(image != (const Image *) NULL);
1921 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001922 assert(image->cache != (Cache) NULL);
1923 cache_info=(CacheInfo *) image->cache;
1924 assert(cache_info->signature == MagickSignature);
1925 if (cache_info->methods.get_authentic_pixels_from_handler ==
1926 (GetAuthenticPixelsFromHandler) NULL)
1927 return((PixelPacket *) NULL);
1928 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1929}
1930
1931/*
1932%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1933% %
1934% %
1935% %
1936% G e t A u t h e n t i c P i x e l s %
1937% %
1938% %
1939% %
1940%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1941%
1942% GetAuthenticPixels() obtains a pixel region for read/write access. If the
1943% region is successfully accessed, a pointer to a PixelPacket array
1944% representing the region is returned, otherwise NULL is returned.
1945%
1946% The returned pointer may point to a temporary working copy of the pixels
1947% or it may point to the original pixels in memory. Performance is maximized
1948% if the selected region is part of one row, or one or more full rows, since
1949% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001950% if the image is in memory, or in a memory-mapped file. The returned pointer
1951% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001952%
1953% Pixels accessed via the returned pointer represent a simple array of type
1954% PixelPacket. If the image type is CMYK or if the storage class is
1955% PseduoClass, call GetAuthenticIndexQueue() after invoking
1956% GetAuthenticPixels() to obtain the black color component or colormap indexes
1957% (of type IndexPacket) corresponding to the region. Once the PixelPacket
1958% (and/or IndexPacket) array has been updated, the changes must be saved back
1959% to the underlying image using SyncAuthenticPixels() or they may be lost.
1960%
1961% The format of the GetAuthenticPixels() method is:
1962%
cristy5f959472010-05-27 22:19:46 +00001963% PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1964% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001965% ExceptionInfo *exception)
1966%
1967% A description of each parameter follows:
1968%
1969% o image: the image.
1970%
1971% o x,y,columns,rows: These values define the perimeter of a region of
1972% pixels.
1973%
1974% o exception: return any errors or warnings in this structure.
1975%
1976*/
cristybb503372010-05-27 20:51:26 +00001977MagickExport PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1978 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001979 ExceptionInfo *exception)
1980{
1981 CacheInfo
1982 *cache_info;
1983
1984 PixelPacket
1985 *pixels;
1986
1987 assert(image != (Image *) NULL);
1988 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001989 assert(image->cache != (Cache) NULL);
1990 cache_info=(CacheInfo *) image->cache;
1991 assert(cache_info->signature == MagickSignature);
1992 if (cache_info->methods.get_authentic_pixels_handler ==
1993 (GetAuthenticPixelsHandler) NULL)
1994 return((PixelPacket *) NULL);
1995 pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1996 rows,exception);
1997 return(pixels);
1998}
1999
2000/*
2001%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2002% %
2003% %
2004% %
2005+ G e t A u t h e n t i c P i x e l s C a c h e %
2006% %
2007% %
2008% %
2009%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2010%
2011% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
2012% as defined by the geometry parameters. A pointer to the pixels is returned
2013% if the pixels are transferred, otherwise a NULL is returned.
2014%
2015% The format of the GetAuthenticPixelsCache() method is:
2016%
cristybb503372010-05-27 20:51:26 +00002017% PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
2018% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00002019% ExceptionInfo *exception)
2020%
2021% A description of each parameter follows:
2022%
2023% o image: the image.
2024%
2025% o x,y,columns,rows: These values define the perimeter of a region of
2026% pixels.
2027%
2028% o exception: return any errors or warnings in this structure.
2029%
2030*/
cristybb503372010-05-27 20:51:26 +00002031static PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
2032 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00002033 ExceptionInfo *exception)
2034{
2035 CacheInfo
2036 *cache_info;
2037
cristy6ebe97c2010-07-03 01:17:28 +00002038 int
cristy3ed852e2009-09-05 21:47:34 +00002039 id;
2040
2041 PixelPacket
2042 *pixels;
2043
2044 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
2045 if (cache_info == (Cache) NULL)
2046 return((PixelPacket *) NULL);
2047 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00002048 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00002049 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
2050 cache_info->nexus_info[id],exception);
2051 return(pixels);
2052}
2053
2054/*
2055%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2056% %
2057% %
2058% %
2059+ G e t I m a g e E x t e n t %
2060% %
2061% %
2062% %
2063%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2064%
2065% GetImageExtent() returns the extent of the pixels associated with the
2066% last call to QueueAuthenticPixels() or GetAuthenticPixels().
2067%
2068% The format of the GetImageExtent() method is:
2069%
2070% MagickSizeType GetImageExtent(const Image *image)
2071%
2072% A description of each parameter follows:
2073%
2074% o image: the image.
2075%
2076*/
2077MagickExport MagickSizeType GetImageExtent(const Image *image)
2078{
2079 CacheInfo
2080 *cache_info;
2081
cristy6ebe97c2010-07-03 01:17:28 +00002082 int
cristy3ed852e2009-09-05 21:47:34 +00002083 id;
2084
2085 MagickSizeType
2086 extent;
2087
2088 assert(image != (Image *) NULL);
2089 assert(image->signature == MagickSignature);
2090 if (image->debug != MagickFalse)
2091 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2092 assert(image->cache != (Cache) NULL);
2093 cache_info=(CacheInfo *) image->cache;
2094 assert(cache_info->signature == MagickSignature);
2095 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00002096 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00002097 extent=GetPixelCacheNexusExtent(image->cache,cache_info->nexus_info[id]);
2098 return(extent);
2099}
2100
2101/*
2102%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2103% %
2104% %
2105% %
2106+ G e t I m a g e P i x e l C a c h e %
2107% %
2108% %
2109% %
2110%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2111%
2112% GetImagePixelCache() ensures that there is only a single reference to the
2113% pixel cache to be modified, updating the provided cache pointer to point to
2114% a clone of the original pixel cache if necessary.
2115%
2116% The format of the GetImagePixelCache method is:
2117%
2118% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2119% ExceptionInfo *exception)
2120%
2121% A description of each parameter follows:
2122%
2123% o image: the image.
2124%
2125% o clone: any value other than MagickFalse clones the cache pixels.
2126%
2127% o exception: return any errors or warnings in this structure.
2128%
2129*/
cristy3ed852e2009-09-05 21:47:34 +00002130static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
2131{
2132 CacheInfo
2133 *cache_info;
2134
2135 /*
2136 Does the image match the pixel cache morphology?
2137 */
2138 cache_info=(CacheInfo *) image->cache;
2139 if ((image->storage_class != cache_info->storage_class) ||
2140 (image->colorspace != cache_info->colorspace) ||
2141 (image->columns != cache_info->columns) ||
2142 (image->rows != cache_info->rows) ||
2143 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2144 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2145 return(MagickFalse);
2146 return(MagickTrue);
2147}
2148
2149MagickExport Cache GetImagePixelCache(Image *image,
2150 const MagickBooleanType clone,ExceptionInfo *exception)
2151{
2152 CacheInfo
2153 *cache_info;
2154
cristy3ed852e2009-09-05 21:47:34 +00002155 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00002156 destroy,
cristy3ed852e2009-09-05 21:47:34 +00002157 status;
2158
cristy50a10922010-02-15 18:35:25 +00002159 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00002160 cpu_throttle = 0,
2161 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00002162 time_limit = 0;
2163
cristy1ea34962010-07-01 19:49:21 +00002164 static time_t
cristya21afde2010-07-02 00:45:40 +00002165 cache_genesis = 0;
cristy1ea34962010-07-01 19:49:21 +00002166
cristyc4f9f132010-03-04 18:50:01 +00002167 status=MagickTrue;
2168 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00002169 if (cpu_throttle == 0)
2170 {
2171 char
2172 *limit;
2173
2174 /*
2175 Set CPU throttle in milleseconds.
2176 */
2177 cpu_throttle=MagickResourceInfinity;
2178 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2179 if (limit == (char *) NULL)
2180 limit=GetPolicyValue("throttle");
2181 if (limit != (char *) NULL)
2182 {
2183 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2184 limit=DestroyString(limit);
2185 }
2186 }
2187 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2188 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00002189 if (time_limit == 0)
2190 {
cristy6ebe97c2010-07-03 01:17:28 +00002191 /*
2192 Set the exire time in seconds.
2193 */
cristy1ea34962010-07-01 19:49:21 +00002194 time_limit=GetMagickResourceLimit(TimeResource);
cristya21afde2010-07-02 00:45:40 +00002195 cache_genesis=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00002196 }
2197 if ((time_limit != MagickResourceInfinity) &&
cristya21afde2010-07-02 00:45:40 +00002198 ((MagickSizeType) (time((time_t *) NULL)-cache_genesis) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00002199 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00002200 assert(image->cache != (Cache) NULL);
2201 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002202 destroy=MagickFalse;
cristy01b7eb02009-09-10 23:10:14 +00002203 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002204 {
cristyaaa0cb62010-02-15 17:47:27 +00002205 LockSemaphoreInfo(cache_info->semaphore);
2206 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002207 {
cristyaaa0cb62010-02-15 17:47:27 +00002208 Image
2209 clone_image;
2210
2211 CacheInfo
2212 *clone_info;
2213
2214 /*
2215 Clone pixel cache.
2216 */
2217 clone_image=(*image);
cristy93505cf2010-08-10 21:37:49 +00002218 clone_image.semaphore=AllocateSemaphoreInfo();
2219 clone_image.reference_count=1;
cristyaaa0cb62010-02-15 17:47:27 +00002220 clone_image.cache=ClonePixelCache(cache_info);
2221 clone_info=(CacheInfo *) clone_image.cache;
2222 status=ClonePixelCacheNexus(cache_info,clone_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002223 if (status != MagickFalse)
2224 {
cristyaaa0cb62010-02-15 17:47:27 +00002225 status=OpenPixelCache(&clone_image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00002226 if (status != MagickFalse)
2227 {
cristyaaa0cb62010-02-15 17:47:27 +00002228 if (clone != MagickFalse)
2229 status=ClonePixelCachePixels(clone_info,cache_info,
2230 exception);
2231 if (status != MagickFalse)
2232 {
2233 destroy=MagickTrue;
2234 image->cache=clone_image.cache;
2235 }
cristy3ed852e2009-09-05 21:47:34 +00002236 }
2237 }
cristy93505cf2010-08-10 21:37:49 +00002238 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002239 }
cristyaaa0cb62010-02-15 17:47:27 +00002240 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002241 }
cristy4320e0e2009-09-10 15:00:08 +00002242 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002243 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002244 if (status != MagickFalse)
2245 {
2246 /*
2247 Ensure the image matches the pixel cache morphology.
2248 */
2249 image->taint=MagickTrue;
2250 image->type=UndefinedType;
cristydd438462010-05-06 13:44:04 +00002251 if (image->colorspace == GRAYColorspace)
2252 image->colorspace=RGBColorspace;
cristy3ed852e2009-09-05 21:47:34 +00002253 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2254 status=OpenPixelCache(image,IOMode,exception);
2255 }
cristyf84a1932010-01-03 18:00:18 +00002256 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002257 if (status == MagickFalse)
2258 return((Cache) NULL);
2259 return(image->cache);
2260}
2261
2262/*
2263%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2264% %
2265% %
2266% %
2267% G e t O n e A u t h e n t i c P i x e l %
2268% %
2269% %
2270% %
2271%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2272%
2273% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2274% location. The image background color is returned if an error occurs.
2275%
2276% The format of the GetOneAuthenticPixel() method is:
2277%
cristybb503372010-05-27 20:51:26 +00002278% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2279% const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002280%
2281% A description of each parameter follows:
2282%
2283% o image: the image.
2284%
2285% o x,y: These values define the location of the pixel to return.
2286%
2287% o pixel: return a pixel at the specified (x,y) location.
2288%
2289% o exception: return any errors or warnings in this structure.
2290%
2291*/
cristyacbbb7c2010-06-30 18:56:48 +00002292MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2293 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002294{
2295 CacheInfo
2296 *cache_info;
2297
2298 GetOneAuthenticPixelFromHandler
2299 get_one_authentic_pixel_from_handler;
2300
2301 MagickBooleanType
2302 status;
2303
2304 assert(image != (Image *) NULL);
2305 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002306 assert(image->cache != (Cache) NULL);
2307 cache_info=(CacheInfo *) image->cache;
2308 assert(cache_info->signature == MagickSignature);
2309 *pixel=image->background_color;
2310 get_one_authentic_pixel_from_handler=
2311 cache_info->methods.get_one_authentic_pixel_from_handler;
2312 if (get_one_authentic_pixel_from_handler ==
2313 (GetOneAuthenticPixelFromHandler) NULL)
2314 return(MagickFalse);
2315 status=cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2316 pixel,exception);
2317 return(status);
2318}
2319
2320/*
2321%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2322% %
2323% %
2324% %
2325+ 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 %
2326% %
2327% %
2328% %
2329%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2330%
2331% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2332% location. The image background color is returned if an error occurs.
2333%
2334% The format of the GetOneAuthenticPixelFromCache() method is:
2335%
2336% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy5f959472010-05-27 22:19:46 +00002337% const ssize_t x,const ssize_t y,PixelPacket *pixel,
2338% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002339%
2340% A description of each parameter follows:
2341%
2342% o image: the image.
2343%
2344% o x,y: These values define the location of the pixel to return.
2345%
2346% o pixel: return a pixel at the specified (x,y) location.
2347%
2348% o exception: return any errors or warnings in this structure.
2349%
2350*/
2351static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristybb503372010-05-27 20:51:26 +00002352 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002353{
2354 PixelPacket
2355 *pixels;
2356
cristy3ed852e2009-09-05 21:47:34 +00002357 *pixel=image->background_color;
2358 pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2359 if (pixels == (PixelPacket *) NULL)
2360 return(MagickFalse);
2361 *pixel=(*pixels);
2362 return(MagickTrue);
2363}
2364
2365/*
2366%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2367% %
2368% %
2369% %
2370% G e t O n e V i r t u a l M a g i c k P i x e l %
2371% %
2372% %
2373% %
2374%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2375%
2376% GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2377% location. The image background color is returned if an error occurs. If
2378% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2379%
2380% The format of the GetOneVirtualMagickPixel() method is:
2381%
2382% MagickBooleanType GetOneVirtualMagickPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002383% const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
cristy3ed852e2009-09-05 21:47:34 +00002384% ExceptionInfo exception)
2385%
2386% A description of each parameter follows:
2387%
2388% o image: the image.
2389%
2390% o x,y: these values define the location of the pixel to return.
2391%
2392% o pixel: return a pixel at the specified (x,y) location.
2393%
2394% o exception: return any errors or warnings in this structure.
2395%
2396*/
2397MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
cristyacbbb7c2010-06-30 18:56:48 +00002398 const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
2399 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002400{
2401 CacheInfo
2402 *cache_info;
2403
2404 register const IndexPacket
2405 *indexes;
2406
2407 register const PixelPacket
2408 *p;
2409
2410 assert(image != (const Image *) NULL);
2411 assert(image->signature == MagickSignature);
2412 assert(image->cache != (Cache) NULL);
2413 cache_info=(CacheInfo *) image->cache;
2414 assert(cache_info->signature == MagickSignature);
2415 GetMagickPixelPacket(image,pixel);
2416 p=GetVirtualPixelCache(image,GetPixelCacheVirtualMethod(image),x,y,1,1,
2417 exception);
2418 if (p == (const PixelPacket *) NULL)
2419 return(MagickFalse);
2420 indexes=GetVirtualIndexQueue(image);
2421 SetMagickPixelPacket(image,p,indexes,pixel);
2422 return(MagickTrue);
2423}
2424
2425/*
2426%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2427% %
2428% %
2429% %
2430% G e t O n e V i r t u a l M e t h o d P i x e l %
2431% %
2432% %
2433% %
2434%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2435%
2436% GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2437% location as defined by specified pixel method. The image background color
2438% is returned if an error occurs. If you plan to modify the pixel, use
2439% GetOneAuthenticPixel() instead.
2440%
2441% The format of the GetOneVirtualMethodPixel() method is:
2442%
2443% MagickBooleanType GetOneVirtualMethodPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002444% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2445% const ssize_t y,Pixelpacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002446%
2447% A description of each parameter follows:
2448%
2449% o image: the image.
2450%
2451% o virtual_pixel_method: the virtual pixel method.
2452%
2453% o x,y: These values define the location of the pixel to return.
2454%
2455% o pixel: return a pixel at the specified (x,y) location.
2456%
2457% o exception: return any errors or warnings in this structure.
2458%
2459*/
2460MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002461 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002462 PixelPacket *pixel,ExceptionInfo *exception)
2463{
2464 GetOneVirtualPixelFromHandler
2465 get_one_virtual_pixel_from_handler;
2466
2467 CacheInfo
2468 *cache_info;
2469
2470 MagickBooleanType
2471 status;
2472
2473 assert(image != (const Image *) NULL);
2474 assert(image->signature == MagickSignature);
2475 assert(image->cache != (Cache) NULL);
2476 cache_info=(CacheInfo *) image->cache;
2477 assert(cache_info->signature == MagickSignature);
2478 *pixel=image->background_color;
2479 get_one_virtual_pixel_from_handler=
2480 cache_info->methods.get_one_virtual_pixel_from_handler;
2481 if (get_one_virtual_pixel_from_handler ==
2482 (GetOneVirtualPixelFromHandler) NULL)
2483 return(MagickFalse);
2484 status=get_one_virtual_pixel_from_handler(image,virtual_pixel_method,x,y,
2485 pixel,exception);
2486 return(status);
2487}
2488
2489/*
2490%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2491% %
2492% %
2493% %
2494% G e t O n e V i r t u a l P i x e l %
2495% %
2496% %
2497% %
2498%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2499%
2500% GetOneVirtualPixel() returns a single virtual pixel at the specified
2501% (x,y) location. The image background color is returned if an error occurs.
2502% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2503%
2504% The format of the GetOneVirtualPixel() method is:
2505%
cristybb503372010-05-27 20:51:26 +00002506% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2507% const ssize_t y,PixelPacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002508%
2509% A description of each parameter follows:
2510%
2511% o image: the image.
2512%
2513% o x,y: These values define the location of the pixel to return.
2514%
2515% o pixel: return a pixel at the specified (x,y) location.
2516%
2517% o exception: return any errors or warnings in this structure.
2518%
2519*/
2520MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002521 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002522{
2523 GetOneVirtualPixelFromHandler
2524 get_one_virtual_pixel_from_handler;
2525
2526 CacheInfo
2527 *cache_info;
2528
2529 MagickBooleanType
2530 status;
2531
2532 assert(image != (const Image *) NULL);
2533 assert(image->signature == MagickSignature);
2534 assert(image->cache != (Cache) NULL);
2535 cache_info=(CacheInfo *) image->cache;
2536 assert(cache_info->signature == MagickSignature);
2537 *pixel=image->background_color;
2538 get_one_virtual_pixel_from_handler=
2539 cache_info->methods.get_one_virtual_pixel_from_handler;
2540 if (get_one_virtual_pixel_from_handler ==
2541 (GetOneVirtualPixelFromHandler) NULL)
2542 return(MagickFalse);
2543 status=get_one_virtual_pixel_from_handler(image,GetPixelCacheVirtualMethod(
2544 image),x,y,pixel,exception);
2545 return(status);
2546}
2547
2548/*
2549%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2550% %
2551% %
2552% %
2553+ 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 %
2554% %
2555% %
2556% %
2557%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2558%
2559% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2560% specified (x,y) location. The image background color is returned if an
2561% error occurs.
2562%
2563% The format of the GetOneVirtualPixelFromCache() method is:
2564%
2565% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristybb503372010-05-27 20:51:26 +00002566% const VirtualPixelPacket method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002567% PixelPacket *pixel,ExceptionInfo *exception)
2568%
2569% A description of each parameter follows:
2570%
2571% o image: the image.
2572%
2573% o virtual_pixel_method: the virtual pixel method.
2574%
2575% o x,y: These values define the location of the pixel to return.
2576%
2577% o pixel: return a pixel at the specified (x,y) location.
2578%
2579% o exception: return any errors or warnings in this structure.
2580%
2581*/
2582static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002583 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002584 PixelPacket *pixel,ExceptionInfo *exception)
2585{
2586 const PixelPacket
2587 *pixels;
2588
2589 *pixel=image->background_color;
2590 pixels=GetVirtualPixelCache(image,virtual_pixel_method,x,y,1UL,1UL,exception);
2591 if (pixels == (const PixelPacket *) NULL)
2592 return(MagickFalse);
2593 *pixel=(*pixels);
2594 return(MagickTrue);
2595}
2596
2597/*
2598%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2599% %
2600% %
2601% %
2602+ G e t P i x e l C a c h e C o l o r s p a c e %
2603% %
2604% %
2605% %
2606%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2607%
2608% GetPixelCacheColorspace() returns the class type of the pixel cache.
2609%
2610% The format of the GetPixelCacheColorspace() method is:
2611%
2612% Colorspace GetPixelCacheColorspace(Cache cache)
2613%
2614% A description of each parameter follows:
2615%
2616% o cache: the pixel cache.
2617%
2618*/
2619MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
2620{
2621 CacheInfo
2622 *cache_info;
2623
2624 assert(cache != (Cache) NULL);
2625 cache_info=(CacheInfo *) cache;
2626 assert(cache_info->signature == MagickSignature);
2627 if (cache_info->debug != MagickFalse)
2628 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2629 cache_info->filename);
2630 return(cache_info->colorspace);
2631}
2632
2633/*
2634%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2635% %
2636% %
2637% %
2638+ G e t P i x e l C a c h e M e t h o d s %
2639% %
2640% %
2641% %
2642%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2643%
2644% GetPixelCacheMethods() initializes the CacheMethods structure.
2645%
2646% The format of the GetPixelCacheMethods() method is:
2647%
2648% void GetPixelCacheMethods(CacheMethods *cache_methods)
2649%
2650% A description of each parameter follows:
2651%
2652% o cache_methods: Specifies a pointer to a CacheMethods structure.
2653%
2654*/
2655MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
2656{
2657 assert(cache_methods != (CacheMethods *) NULL);
2658 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2659 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2660 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2661 cache_methods->get_virtual_indexes_from_handler=GetVirtualIndexesFromCache;
2662 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2663 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2664 cache_methods->get_authentic_indexes_from_handler=
2665 GetAuthenticIndexesFromCache;
2666 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2667 cache_methods->get_one_authentic_pixel_from_handler=
2668 GetOneAuthenticPixelFromCache;
2669 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2670 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2671 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2672}
2673
2674/*
2675%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2676% %
2677% %
2678% %
2679+ G e t P i x e l C a c h e N e x u s E x t e n t %
2680% %
2681% %
2682% %
2683%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2684%
2685% GetPixelCacheNexusExtent() returns the extent of the pixels associated with
2686% the last call to SetPixelCacheNexusPixels() or GetPixelCacheNexusPixels().
2687%
2688% The format of the GetPixelCacheNexusExtent() method is:
2689%
2690% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2691% NexusInfo *nexus_info)
2692%
2693% A description of each parameter follows:
2694%
2695% o nexus_info: the nexus info.
2696%
2697*/
2698MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2699 NexusInfo *nexus_info)
2700{
2701 CacheInfo
2702 *cache_info;
2703
2704 MagickSizeType
2705 extent;
2706
2707 if (cache == (Cache) NULL)
2708 return(0);
2709 cache_info=(CacheInfo *) cache;
2710 assert(cache_info->signature == MagickSignature);
2711 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2712 if (extent == 0)
2713 return((MagickSizeType) cache_info->columns*cache_info->rows);
2714 return(extent);
2715}
2716
2717/*
2718%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2719% %
2720% %
2721% %
2722+ 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 %
2723% %
2724% %
2725% %
2726%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2727%
2728% GetPixelCacheNexusIndexes() returns the indexes associated with the
2729% specified cache nexus.
2730%
2731% The format of the GetPixelCacheNexusIndexes() method is:
2732%
2733% IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2734% NexusInfo *nexus_info)
2735%
2736% A description of each parameter follows:
2737%
2738% o cache: the pixel cache.
2739%
2740% o nexus_info: the cache nexus to return the colormap indexes.
2741%
2742*/
2743MagickExport IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2744 NexusInfo *nexus_info)
2745{
2746 CacheInfo
2747 *cache_info;
2748
2749 if (cache == (Cache) NULL)
2750 return((IndexPacket *) NULL);
2751 cache_info=(CacheInfo *) cache;
2752 assert(cache_info->signature == MagickSignature);
2753 if (cache_info->storage_class == UndefinedClass)
2754 return((IndexPacket *) NULL);
2755 return(nexus_info->indexes);
2756}
2757
2758/*
2759%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2760% %
2761% %
2762% %
2763+ G e t P i x e l C a c h e N e x u s P i x e l s %
2764% %
2765% %
2766% %
2767%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2768%
2769% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2770% cache nexus.
2771%
2772% The format of the GetPixelCacheNexusPixels() method is:
2773%
2774% PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2775% NexusInfo *nexus_info)
2776%
2777% A description of each parameter follows:
2778%
2779% o cache: the pixel cache.
2780%
2781% o nexus_info: the cache nexus to return the pixels.
2782%
2783*/
2784MagickExport PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2785 NexusInfo *nexus_info)
2786{
2787 CacheInfo
2788 *cache_info;
2789
2790 if (cache == (Cache) NULL)
2791 return((PixelPacket *) NULL);
2792 cache_info=(CacheInfo *) cache;
2793 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002794 if (cache_info->storage_class == UndefinedClass)
2795 return((PixelPacket *) NULL);
2796 return(nexus_info->pixels);
2797}
2798
2799/*
2800%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2801% %
2802% %
2803% %
cristy056ba772010-01-02 23:33:54 +00002804+ G e t P i x e l C a c h e P i x e l s %
2805% %
2806% %
2807% %
2808%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2809%
2810% GetPixelCachePixels() returns the pixels associated with the specified image.
2811%
2812% The format of the GetPixelCachePixels() method is:
2813%
cristyf84a1932010-01-03 18:00:18 +00002814% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2815% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002816%
2817% A description of each parameter follows:
2818%
2819% o image: the image.
2820%
2821% o length: the pixel cache length.
2822%
cristyf84a1932010-01-03 18:00:18 +00002823% o exception: return any errors or warnings in this structure.
2824%
cristy056ba772010-01-02 23:33:54 +00002825*/
cristyf84a1932010-01-03 18:00:18 +00002826MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2827 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002828{
2829 CacheInfo
2830 *cache_info;
2831
2832 assert(image != (const Image *) NULL);
2833 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002834 assert(image->cache != (Cache) NULL);
cristyc4c8d132010-01-07 01:58:38 +00002835 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
cristy056ba772010-01-02 23:33:54 +00002836 assert(cache_info->signature == MagickSignature);
2837 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002838 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002839 return((void *) NULL);
2840 *length=cache_info->length;
2841 return((void *) cache_info->pixels);
2842}
2843
2844/*
2845%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2846% %
2847% %
2848% %
cristyb32b90a2009-09-07 21:45:48 +00002849+ 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 +00002850% %
2851% %
2852% %
2853%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2854%
2855% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2856%
2857% The format of the GetPixelCacheStorageClass() method is:
2858%
2859% ClassType GetPixelCacheStorageClass(Cache cache)
2860%
2861% A description of each parameter follows:
2862%
2863% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2864%
2865% o cache: the pixel cache.
2866%
2867*/
2868MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
2869{
2870 CacheInfo
2871 *cache_info;
2872
2873 assert(cache != (Cache) NULL);
2874 cache_info=(CacheInfo *) cache;
2875 assert(cache_info->signature == MagickSignature);
2876 if (cache_info->debug != MagickFalse)
2877 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2878 cache_info->filename);
2879 return(cache_info->storage_class);
2880}
2881
2882/*
2883%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2884% %
2885% %
2886% %
cristyb32b90a2009-09-07 21:45:48 +00002887+ G e t P i x e l C a c h e T i l e S i z e %
2888% %
2889% %
2890% %
2891%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2892%
2893% GetPixelCacheTileSize() returns the pixel cache tile size.
2894%
2895% The format of the GetPixelCacheTileSize() method is:
2896%
cristybb503372010-05-27 20:51:26 +00002897% void GetPixelCacheTileSize(const Image *image,size_t *width,
2898% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002899%
2900% A description of each parameter follows:
2901%
2902% o image: the image.
2903%
2904% o width: the optimize cache tile width in pixels.
2905%
2906% o height: the optimize cache tile height in pixels.
2907%
2908*/
cristybb503372010-05-27 20:51:26 +00002909MagickExport void GetPixelCacheTileSize(const Image *image,size_t *width,
2910 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002911{
2912 CacheInfo
2913 *cache_info;
2914
2915 assert(image != (Image *) NULL);
2916 assert(image->signature == MagickSignature);
2917 if (image->debug != MagickFalse)
2918 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2919 assert(image->cache != (Cache) NULL);
2920 cache_info=(CacheInfo *) image->cache;
2921 assert(cache_info->signature == MagickSignature);
2922 *width=2048UL/sizeof(PixelPacket);
2923 if (GetPixelCacheType(image) == DiskCache)
cristydaa97692009-09-13 02:10:35 +00002924 *width=8192UL/sizeof(PixelPacket);
cristyb32b90a2009-09-07 21:45:48 +00002925 *height=(*width);
2926}
2927
2928/*
2929%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2930% %
2931% %
2932% %
2933+ G e t P i x e l C a c h e T y p e %
2934% %
2935% %
2936% %
2937%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2938%
2939% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2940%
2941% The format of the GetPixelCacheType() method is:
2942%
2943% CacheType GetPixelCacheType(const Image *image)
2944%
2945% A description of each parameter follows:
2946%
2947% o image: the image.
2948%
2949*/
2950MagickExport CacheType GetPixelCacheType(const Image *image)
2951{
2952 CacheInfo
2953 *cache_info;
2954
2955 assert(image != (Image *) NULL);
2956 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002957 assert(image->cache != (Cache) NULL);
2958 cache_info=(CacheInfo *) image->cache;
2959 assert(cache_info->signature == MagickSignature);
2960 return(cache_info->type);
2961}
2962
2963/*
2964%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2965% %
2966% %
2967% %
cristy3ed852e2009-09-05 21:47:34 +00002968+ 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 %
2969% %
2970% %
2971% %
2972%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2973%
2974% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2975% pixel cache. A virtual pixel is any pixel access that is outside the
2976% boundaries of the image cache.
2977%
2978% The format of the GetPixelCacheVirtualMethod() method is:
2979%
2980% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2981%
2982% A description of each parameter follows:
2983%
2984% o image: the image.
2985%
2986*/
2987MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2988{
2989 CacheInfo
2990 *cache_info;
2991
2992 assert(image != (Image *) NULL);
2993 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002994 assert(image->cache != (Cache) NULL);
2995 cache_info=(CacheInfo *) image->cache;
2996 assert(cache_info->signature == MagickSignature);
2997 return(cache_info->virtual_pixel_method);
2998}
2999
3000/*
3001%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3002% %
3003% %
3004% %
3005+ 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 %
3006% %
3007% %
3008% %
3009%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3010%
3011% GetVirtualIndexesFromCache() returns the indexes associated with the last
3012% call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3013%
3014% The format of the GetVirtualIndexesFromCache() method is:
3015%
3016% IndexPacket *GetVirtualIndexesFromCache(const Image *image)
3017%
3018% A description of each parameter follows:
3019%
3020% o image: the image.
3021%
3022*/
3023static const IndexPacket *GetVirtualIndexesFromCache(const Image *image)
3024{
3025 CacheInfo
3026 *cache_info;
3027
3028 const IndexPacket
3029 *indexes;
3030
cristy6ebe97c2010-07-03 01:17:28 +00003031 int
cristy3ed852e2009-09-05 21:47:34 +00003032 id;
3033
cristy3ed852e2009-09-05 21:47:34 +00003034 cache_info=(CacheInfo *) image->cache;
3035 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00003036 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00003037 indexes=GetVirtualIndexesFromNexus(image->cache,cache_info->nexus_info[id]);
3038 return(indexes);
3039}
3040
3041/*
3042%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3043% %
3044% %
3045% %
3046+ 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 %
3047% %
3048% %
3049% %
3050%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3051%
3052% GetVirtualIndexesFromNexus() returns the indexes associated with the
3053% specified cache nexus.
3054%
3055% The format of the GetVirtualIndexesFromNexus() method is:
3056%
3057% const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
3058% NexusInfo *nexus_info)
3059%
3060% A description of each parameter follows:
3061%
3062% o cache: the pixel cache.
3063%
3064% o nexus_info: the cache nexus to return the colormap indexes.
3065%
3066*/
3067MagickExport const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
3068 NexusInfo *nexus_info)
3069{
3070 CacheInfo
3071 *cache_info;
3072
3073 if (cache == (Cache) NULL)
3074 return((IndexPacket *) NULL);
3075 cache_info=(CacheInfo *) cache;
3076 assert(cache_info->signature == MagickSignature);
3077 if (cache_info->storage_class == UndefinedClass)
3078 return((IndexPacket *) NULL);
3079 return(nexus_info->indexes);
3080}
3081
3082/*
3083%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3084% %
3085% %
3086% %
3087% G e t V i r t u a l I n d e x Q u e u e %
3088% %
3089% %
3090% %
3091%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3092%
3093% GetVirtualIndexQueue() returns the virtual black channel or the
3094% colormap indexes associated with the last call to QueueAuthenticPixels() or
3095% GetVirtualPixels(). NULL is returned if the black channel or colormap
3096% indexes are not available.
3097%
3098% The format of the GetVirtualIndexQueue() method is:
3099%
3100% const IndexPacket *GetVirtualIndexQueue(const Image *image)
3101%
3102% A description of each parameter follows:
3103%
3104% o image: the image.
3105%
3106*/
3107MagickExport const IndexPacket *GetVirtualIndexQueue(const Image *image)
3108{
3109 CacheInfo
3110 *cache_info;
3111
3112 assert(image != (const Image *) NULL);
3113 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003114 assert(image->cache != (Cache) NULL);
3115 cache_info=(CacheInfo *) image->cache;
3116 assert(cache_info->signature == MagickSignature);
3117 if (cache_info->methods.get_virtual_indexes_from_handler ==
3118 (GetVirtualIndexesFromHandler) NULL)
3119 return((IndexPacket *) NULL);
3120 return(cache_info->methods.get_virtual_indexes_from_handler(image));
3121}
3122
3123/*
3124%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3125% %
3126% %
3127% %
3128+ 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 %
3129% %
3130% %
3131% %
3132%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3133%
3134% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3135% pixel cache as defined by the geometry parameters. A pointer to the pixels
3136% is returned if the pixels are transferred, otherwise a NULL is returned.
3137%
3138% The format of the GetVirtualPixelsFromNexus() method is:
3139%
3140% PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003141% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00003142% const size_t columns,const size_t rows,NexusInfo *nexus_info,
3143% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003144%
3145% A description of each parameter follows:
3146%
3147% o image: the image.
3148%
3149% o virtual_pixel_method: the virtual pixel method.
3150%
3151% o x,y,columns,rows: These values define the perimeter of a region of
3152% pixels.
3153%
3154% o nexus_info: the cache nexus to acquire.
3155%
3156% o exception: return any errors or warnings in this structure.
3157%
3158*/
3159
cristybb503372010-05-27 20:51:26 +00003160static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003161 DitherMatrix[64] =
3162 {
3163 0, 48, 12, 60, 3, 51, 15, 63,
3164 32, 16, 44, 28, 35, 19, 47, 31,
3165 8, 56, 4, 52, 11, 59, 7, 55,
3166 40, 24, 36, 20, 43, 27, 39, 23,
3167 2, 50, 14, 62, 1, 49, 13, 61,
3168 34, 18, 46, 30, 33, 17, 45, 29,
3169 10, 58, 6, 54, 9, 57, 5, 53,
3170 42, 26, 38, 22, 41, 25, 37, 21
3171 };
3172
cristybb503372010-05-27 20:51:26 +00003173static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003174{
cristybb503372010-05-27 20:51:26 +00003175 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003176 index;
3177
3178 index=x+DitherMatrix[x & 0x07]-32L;
3179 if (index < 0L)
3180 return(0L);
cristybb503372010-05-27 20:51:26 +00003181 if (index >= (ssize_t) columns)
3182 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00003183 return(index);
3184}
3185
cristybb503372010-05-27 20:51:26 +00003186static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003187{
cristybb503372010-05-27 20:51:26 +00003188 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003189 index;
3190
3191 index=y+DitherMatrix[y & 0x07]-32L;
3192 if (index < 0L)
3193 return(0L);
cristybb503372010-05-27 20:51:26 +00003194 if (index >= (ssize_t) rows)
3195 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00003196 return(index);
3197}
3198
cristybb503372010-05-27 20:51:26 +00003199static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003200{
3201 if (x < 0L)
3202 return(0L);
cristybb503372010-05-27 20:51:26 +00003203 if (x >= (ssize_t) columns)
3204 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003205 return(x);
3206}
3207
cristybb503372010-05-27 20:51:26 +00003208static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003209{
3210 if (y < 0L)
3211 return(0L);
cristybb503372010-05-27 20:51:26 +00003212 if (y >= (ssize_t) rows)
3213 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003214 return(y);
3215}
3216
cristybb503372010-05-27 20:51:26 +00003217static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003218{
cristybb503372010-05-27 20:51:26 +00003219 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003220}
3221
cristybb503372010-05-27 20:51:26 +00003222static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003223{
cristybb503372010-05-27 20:51:26 +00003224 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003225}
3226
3227/*
3228 VirtualPixelModulo() computes the remainder of dividing offset by extent. It
3229 returns not only the quotient (tile the offset falls in) but also the positive
3230 remainer within that tile such that 0 <= remainder < extent. This method is
3231 essentially a ldiv() using a floored modulo division rather than the normal
3232 default truncated modulo division.
3233*/
cristybb503372010-05-27 20:51:26 +00003234static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3235 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003236{
3237 MagickModulo
3238 modulo;
3239
cristybb503372010-05-27 20:51:26 +00003240 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003241 if (offset < 0L)
3242 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003243 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003244 return(modulo);
3245}
3246
3247MagickExport const PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003248 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3249 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003250 ExceptionInfo *exception)
3251{
3252 CacheInfo
3253 *cache_info;
3254
cristyc3ec0d42010-04-07 01:18:08 +00003255 IndexPacket
3256 virtual_index;
3257
cristy3ed852e2009-09-05 21:47:34 +00003258 MagickOffsetType
3259 offset;
3260
3261 MagickSizeType
3262 length,
3263 number_pixels;
3264
3265 NexusInfo
3266 **virtual_nexus;
3267
3268 PixelPacket
3269 *pixels,
3270 virtual_pixel;
3271
3272 RectangleInfo
3273 region;
3274
3275 register const IndexPacket
cristyc3ec0d42010-04-07 01:18:08 +00003276 *restrict virtual_indexes;
cristy3ed852e2009-09-05 21:47:34 +00003277
3278 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003279 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003280
3281 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003282 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003283
cristybb503372010-05-27 20:51:26 +00003284 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003285 u,
3286 v;
3287
3288 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003289 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003290
3291 /*
3292 Acquire pixels.
3293 */
cristy3ed852e2009-09-05 21:47:34 +00003294 cache_info=(CacheInfo *) image->cache;
cristy4cfbb3f2010-03-14 20:40:23 +00003295 if (cache_info->type == UndefinedCache)
cristy3ed852e2009-09-05 21:47:34 +00003296 return((const PixelPacket *) NULL);
3297 region.x=x;
3298 region.y=y;
3299 region.width=columns;
3300 region.height=rows;
3301 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
3302 if (pixels == (PixelPacket *) NULL)
3303 return((const PixelPacket *) NULL);
cristydf415c82010-03-11 16:47:50 +00003304 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3305 nexus_info->region.x;
3306 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3307 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003308 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3309 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003310 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3311 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003312 {
3313 MagickBooleanType
3314 status;
3315
3316 /*
3317 Pixel request is inside cache extents.
3318 */
3319 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
3320 return(pixels);
3321 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3322 if (status == MagickFalse)
3323 return((const PixelPacket *) NULL);
3324 if ((cache_info->storage_class == PseudoClass) ||
3325 (cache_info->colorspace == CMYKColorspace))
3326 {
3327 status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
3328 if (status == MagickFalse)
3329 return((const PixelPacket *) NULL);
3330 }
3331 return(pixels);
3332 }
3333 /*
3334 Pixel request is outside cache extents.
3335 */
3336 q=pixels;
3337 indexes=GetPixelCacheNexusIndexes(cache_info,nexus_info);
3338 virtual_nexus=AcquirePixelCacheNexus(1);
3339 if (virtual_nexus == (NexusInfo **) NULL)
3340 {
3341 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3342 "UnableToGetCacheNexus","`%s'",image->filename);
3343 return((const PixelPacket *) NULL);
3344 }
3345 switch (virtual_pixel_method)
3346 {
3347 case BlackVirtualPixelMethod:
3348 {
cristy4789f0d2010-01-10 00:01:06 +00003349 SetRedPixelComponent(&virtual_pixel,0);
3350 SetGreenPixelComponent(&virtual_pixel,0);
3351 SetBluePixelComponent(&virtual_pixel,0);
3352 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003353 break;
3354 }
3355 case GrayVirtualPixelMethod:
3356 {
cristy4789f0d2010-01-10 00:01:06 +00003357 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3358 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3359 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3360 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003361 break;
3362 }
3363 case TransparentVirtualPixelMethod:
3364 {
cristy4789f0d2010-01-10 00:01:06 +00003365 SetRedPixelComponent(&virtual_pixel,0);
3366 SetGreenPixelComponent(&virtual_pixel,0);
3367 SetBluePixelComponent(&virtual_pixel,0);
3368 SetOpacityPixelComponent(&virtual_pixel,TransparentOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003369 break;
3370 }
3371 case MaskVirtualPixelMethod:
3372 case WhiteVirtualPixelMethod:
3373 {
cristy4789f0d2010-01-10 00:01:06 +00003374 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3375 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3376 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3377 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003378 break;
3379 }
3380 default:
3381 {
3382 virtual_pixel=image->background_color;
3383 break;
3384 }
3385 }
cristyc3ec0d42010-04-07 01:18:08 +00003386 virtual_index=0;
cristybb503372010-05-27 20:51:26 +00003387 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003388 {
cristybb503372010-05-27 20:51:26 +00003389 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003390 {
3391 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003392 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003393 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3394 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003395 {
3396 MagickModulo
3397 x_modulo,
3398 y_modulo;
3399
3400 /*
3401 Transfer a single pixel.
3402 */
3403 length=(MagickSizeType) 1;
3404 switch (virtual_pixel_method)
3405 {
3406 case BackgroundVirtualPixelMethod:
3407 case ConstantVirtualPixelMethod:
3408 case BlackVirtualPixelMethod:
3409 case GrayVirtualPixelMethod:
3410 case TransparentVirtualPixelMethod:
3411 case MaskVirtualPixelMethod:
3412 case WhiteVirtualPixelMethod:
3413 {
3414 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003415 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003416 break;
3417 }
3418 case EdgeVirtualPixelMethod:
3419 default:
3420 {
3421 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003422 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003423 1UL,1UL,virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003424 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3425 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003426 break;
3427 }
3428 case RandomVirtualPixelMethod:
3429 {
3430 if (cache_info->random_info == (RandomInfo *) NULL)
3431 cache_info->random_info=AcquireRandomInfo();
3432 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003433 RandomX(cache_info->random_info,cache_info->columns),
3434 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003435 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003436 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3437 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003438 break;
3439 }
3440 case DitherVirtualPixelMethod:
3441 {
3442 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003443 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003444 1UL,1UL,virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003445 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3446 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003447 break;
3448 }
3449 case TileVirtualPixelMethod:
3450 {
3451 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3452 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3453 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3454 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3455 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003456 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3457 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003458 break;
3459 }
3460 case MirrorVirtualPixelMethod:
3461 {
3462 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3463 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003464 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003465 x_modulo.remainder-1L;
3466 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3467 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003468 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003469 y_modulo.remainder-1L;
3470 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3471 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3472 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003473 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3474 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003475 break;
3476 }
3477 case CheckerTileVirtualPixelMethod:
3478 {
3479 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3480 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3481 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3482 {
3483 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003484 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003485 break;
3486 }
3487 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3488 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3489 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003490 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3491 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003492 break;
3493 }
3494 case HorizontalTileVirtualPixelMethod:
3495 {
cristybb503372010-05-27 20:51:26 +00003496 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003497 {
3498 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003499 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003500 break;
3501 }
3502 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3503 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3504 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3505 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3506 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003507 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3508 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003509 break;
3510 }
3511 case VerticalTileVirtualPixelMethod:
3512 {
cristybb503372010-05-27 20:51:26 +00003513 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
cristy3ed852e2009-09-05 21:47:34 +00003514 {
3515 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003516 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003517 break;
3518 }
3519 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3520 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3521 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3522 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3523 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003524 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3525 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003526 break;
3527 }
3528 case HorizontalTileEdgeVirtualPixelMethod:
3529 {
3530 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3531 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003532 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003533 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003534 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3535 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003536 break;
3537 }
3538 case VerticalTileEdgeVirtualPixelMethod:
3539 {
3540 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3541 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003542 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003543 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003544 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3545 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003546 break;
3547 }
3548 }
3549 if (p == (const PixelPacket *) NULL)
3550 break;
3551 *q++=(*p);
cristyc3ec0d42010-04-07 01:18:08 +00003552 if ((indexes != (IndexPacket *) NULL) &&
3553 (virtual_indexes != (const IndexPacket *) NULL))
3554 *indexes++=(*virtual_indexes);
cristy3ed852e2009-09-05 21:47:34 +00003555 continue;
3556 }
3557 /*
3558 Transfer a run of pixels.
3559 */
3560 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,
cristybb503372010-05-27 20:51:26 +00003561 (size_t) length,1UL,virtual_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003562 if (p == (const PixelPacket *) NULL)
3563 break;
cristyc3ec0d42010-04-07 01:18:08 +00003564 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003565 (void) CopyMagickMemory(q,p,(size_t) length*sizeof(*p));
3566 q+=length;
cristyc3ec0d42010-04-07 01:18:08 +00003567 if ((indexes != (IndexPacket *) NULL) &&
3568 (virtual_indexes != (const IndexPacket *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003569 {
cristyc3ec0d42010-04-07 01:18:08 +00003570 (void) CopyMagickMemory(indexes,virtual_indexes,(size_t) length*
3571 sizeof(*virtual_indexes));
3572 indexes+=length;
cristy3ed852e2009-09-05 21:47:34 +00003573 }
3574 }
3575 }
3576 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3577 return(pixels);
3578}
3579
3580/*
3581%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3582% %
3583% %
3584% %
3585+ G e t V i r t u a l P i x e l C a c h e %
3586% %
3587% %
3588% %
3589%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3590%
3591% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3592% cache as defined by the geometry parameters. A pointer to the pixels
3593% is returned if the pixels are transferred, otherwise a NULL is returned.
3594%
3595% The format of the GetVirtualPixelCache() method is:
3596%
3597% const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003598% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3599% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003600% ExceptionInfo *exception)
3601%
3602% A description of each parameter follows:
3603%
3604% o image: the image.
3605%
3606% o virtual_pixel_method: the virtual pixel method.
3607%
3608% o x,y,columns,rows: These values define the perimeter of a region of
3609% pixels.
3610%
3611% o exception: return any errors or warnings in this structure.
3612%
3613*/
3614static const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003615 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3616 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003617{
3618 CacheInfo
3619 *cache_info;
3620
3621 const PixelPacket
3622 *pixels;
3623
cristy6ebe97c2010-07-03 01:17:28 +00003624 int
cristy3ed852e2009-09-05 21:47:34 +00003625 id;
3626
cristy3ed852e2009-09-05 21:47:34 +00003627 cache_info=(CacheInfo *) image->cache;
3628 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00003629 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00003630 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3631 cache_info->nexus_info[id],exception);
3632 return(pixels);
3633}
3634
3635/*
3636%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3637% %
3638% %
3639% %
3640% G e t V i r t u a l P i x e l Q u e u e %
3641% %
3642% %
3643% %
3644%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3645%
3646% GetVirtualPixelQueue() returns the virtual pixels associated with the
3647% last call to QueueAuthenticPixels() or GetVirtualPixels().
3648%
3649% The format of the GetVirtualPixelQueue() method is:
3650%
3651% const PixelPacket *GetVirtualPixelQueue(const Image image)
3652%
3653% A description of each parameter follows:
3654%
3655% o image: the image.
3656%
3657*/
3658MagickExport const PixelPacket *GetVirtualPixelQueue(const Image *image)
3659{
3660 CacheInfo
3661 *cache_info;
3662
3663 assert(image != (const Image *) NULL);
3664 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003665 assert(image->cache != (Cache) NULL);
3666 cache_info=(CacheInfo *) image->cache;
3667 assert(cache_info->signature == MagickSignature);
3668 if (cache_info->methods.get_virtual_pixels_handler ==
3669 (GetVirtualPixelsHandler) NULL)
3670 return((PixelPacket *) NULL);
3671 return(cache_info->methods.get_virtual_pixels_handler(image));
3672}
3673
3674/*
3675%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3676% %
3677% %
3678% %
3679% G e t V i r t u a l P i x e l s %
3680% %
3681% %
3682% %
3683%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3684%
3685% GetVirtualPixels() returns an immutable pixel region. If the
3686% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003687% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003688% copy of the pixels or it may point to the original pixels in memory.
3689% Performance is maximized if the selected region is part of one row, or one
3690% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003691% (without a copy) if the image is in memory, or in a memory-mapped file. The
3692% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003693%
3694% Pixels accessed via the returned pointer represent a simple array of type
3695% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
3696% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access
3697% the black color component or to obtain the colormap indexes (of type
3698% IndexPacket) corresponding to the region.
3699%
3700% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3701%
3702% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3703% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3704% GetCacheViewAuthenticPixels() instead.
3705%
3706% The format of the GetVirtualPixels() method is:
3707%
cristybb503372010-05-27 20:51:26 +00003708% const PixelPacket *GetVirtualPixels(const Image *image,const ssize_t x,
3709% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003710% ExceptionInfo *exception)
3711%
3712% A description of each parameter follows:
3713%
3714% o image: the image.
3715%
3716% o x,y,columns,rows: These values define the perimeter of a region of
3717% pixels.
3718%
3719% o exception: return any errors or warnings in this structure.
3720%
3721*/
3722MagickExport const PixelPacket *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003723 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3724 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003725{
3726 CacheInfo
3727 *cache_info;
3728
3729 const PixelPacket
3730 *pixels;
3731
3732 assert(image != (const Image *) NULL);
3733 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003734 assert(image->cache != (Cache) NULL);
3735 cache_info=(CacheInfo *) image->cache;
3736 assert(cache_info->signature == MagickSignature);
3737 if (cache_info->methods.get_virtual_pixel_handler ==
3738 (GetVirtualPixelHandler) NULL)
3739 return((const PixelPacket *) NULL);
3740 pixels=cache_info->methods.get_virtual_pixel_handler(image,
3741 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception);
3742 return(pixels);
3743}
3744
3745/*
3746%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3747% %
3748% %
3749% %
3750+ 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 %
3751% %
3752% %
3753% %
3754%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3755%
3756% GetVirtualPixelsCache() returns the pixels associated with the last call
3757% to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3758%
3759% The format of the GetVirtualPixelsCache() method is:
3760%
3761% PixelPacket *GetVirtualPixelsCache(const Image *image)
3762%
3763% A description of each parameter follows:
3764%
3765% o image: the image.
3766%
3767*/
3768static const PixelPacket *GetVirtualPixelsCache(const Image *image)
3769{
3770 CacheInfo
3771 *cache_info;
3772
3773 const PixelPacket
3774 *pixels;
3775
cristy6ebe97c2010-07-03 01:17:28 +00003776 int
cristy3ed852e2009-09-05 21:47:34 +00003777 id;
3778
cristy3ed852e2009-09-05 21:47:34 +00003779 cache_info=(CacheInfo *) image->cache;
3780 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00003781 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00003782 pixels=GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]);
3783 return(pixels);
3784}
3785
3786/*
3787%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3788% %
3789% %
3790% %
3791+ G e t V i r t u a l P i x e l s N e x u s %
3792% %
3793% %
3794% %
3795%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3796%
3797% GetVirtualPixelsNexus() returns the pixels associated with the specified
3798% cache nexus.
3799%
3800% The format of the GetVirtualPixelsNexus() method is:
3801%
3802% const IndexPacket *GetVirtualPixelsNexus(const Cache cache,
3803% NexusInfo *nexus_info)
3804%
3805% A description of each parameter follows:
3806%
3807% o cache: the pixel cache.
3808%
3809% o nexus_info: the cache nexus to return the colormap pixels.
3810%
3811*/
3812MagickExport const PixelPacket *GetVirtualPixelsNexus(const Cache cache,
3813 NexusInfo *nexus_info)
3814{
3815 CacheInfo
3816 *cache_info;
3817
3818 if (cache == (Cache) NULL)
3819 return((PixelPacket *) NULL);
3820 cache_info=(CacheInfo *) cache;
3821 assert(cache_info->signature == MagickSignature);
3822 if (cache_info->storage_class == UndefinedClass)
3823 return((PixelPacket *) NULL);
3824 return((const PixelPacket *) nexus_info->pixels);
3825}
3826
3827/*
3828%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3829% %
3830% %
3831% %
3832+ M a s k P i x e l C a c h e N e x u s %
3833% %
3834% %
3835% %
3836%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3837%
3838% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3839% The method returns MagickTrue if the pixel region is masked, otherwise
3840% MagickFalse.
3841%
3842% The format of the MaskPixelCacheNexus() method is:
3843%
3844% MagickBooleanType MaskPixelCacheNexus(Image *image,
3845% NexusInfo *nexus_info,ExceptionInfo *exception)
3846%
3847% A description of each parameter follows:
3848%
3849% o image: the image.
3850%
3851% o nexus_info: the cache nexus to clip.
3852%
3853% o exception: return any errors or warnings in this structure.
3854%
3855*/
3856
3857static inline void MagickPixelCompositeMask(const MagickPixelPacket *p,
3858 const MagickRealType alpha,const MagickPixelPacket *q,
3859 const MagickRealType beta,MagickPixelPacket *composite)
3860{
3861 MagickRealType
3862 gamma;
3863
3864 if (alpha == TransparentOpacity)
3865 {
3866 *composite=(*q);
3867 return;
3868 }
3869 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3870 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3871 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3872 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3873 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3874 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3875 composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
3876}
3877
3878static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3879 ExceptionInfo *exception)
3880{
3881 CacheInfo
3882 *cache_info;
3883
3884 MagickPixelPacket
3885 alpha,
3886 beta;
3887
3888 MagickSizeType
3889 number_pixels;
3890
3891 NexusInfo
3892 **clip_nexus,
3893 **image_nexus;
3894
3895 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003896 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003897
3898 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003899 *restrict nexus_indexes,
3900 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003901
cristybb503372010-05-27 20:51:26 +00003902 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003903 i;
3904
3905 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003906 *restrict p,
3907 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003908
3909 /*
3910 Apply clip mask.
3911 */
3912 if (image->debug != MagickFalse)
3913 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3914 if (image->mask == (Image *) NULL)
3915 return(MagickFalse);
3916 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
3917 if (cache_info == (Cache) NULL)
3918 return(MagickFalse);
3919 image_nexus=AcquirePixelCacheNexus(1);
3920 clip_nexus=AcquirePixelCacheNexus(1);
3921 if ((image_nexus == (NexusInfo **) NULL) ||
3922 (clip_nexus == (NexusInfo **) NULL))
3923 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy09449f72010-01-23 03:08:36 +00003924 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,
3925 nexus_info->region.y,nexus_info->region.width,nexus_info->region.height,
3926 image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003927 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
3928 q=nexus_info->pixels;
3929 nexus_indexes=nexus_info->indexes;
3930 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3931 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3932 nexus_info->region.height,clip_nexus[0],&image->exception);
3933 GetMagickPixelPacket(image,&alpha);
3934 GetMagickPixelPacket(image,&beta);
3935 number_pixels=(MagickSizeType) nexus_info->region.width*
3936 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +00003937 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +00003938 {
3939 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
3940 break;
3941 SetMagickPixelPacket(image,p,indexes+i,&alpha);
3942 SetMagickPixelPacket(image,q,nexus_indexes+i,&beta);
3943 MagickPixelCompositeMask(&beta,(MagickRealType) PixelIntensityToQuantum(r),
3944 &alpha,alpha.opacity,&beta);
cristyce70c172010-01-07 17:15:30 +00003945 q->red=ClampToQuantum(beta.red);
3946 q->green=ClampToQuantum(beta.green);
3947 q->blue=ClampToQuantum(beta.blue);
3948 q->opacity=ClampToQuantum(beta.opacity);
cristy3ed852e2009-09-05 21:47:34 +00003949 if (cache_info->active_index_channel != MagickFalse)
3950 nexus_indexes[i]=indexes[i];
3951 p++;
3952 q++;
3953 r++;
3954 }
3955 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3956 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +00003957 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003958 return(MagickFalse);
3959 return(MagickTrue);
3960}
3961
3962/*
3963%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3964% %
3965% %
3966% %
3967+ O p e n P i x e l C a c h e %
3968% %
3969% %
3970% %
3971%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3972%
3973% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3974% dimensions, allocating space for the image pixels and optionally the
3975% colormap indexes, and memory mapping the cache if it is disk based. The
3976% cache nexus array is initialized as well.
3977%
3978% The format of the OpenPixelCache() method is:
3979%
3980% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3981% ExceptionInfo *exception)
3982%
3983% A description of each parameter follows:
3984%
3985% o image: the image.
3986%
3987% o mode: ReadMode, WriteMode, or IOMode.
3988%
3989% o exception: return any errors or warnings in this structure.
3990%
3991*/
3992
cristyd43a46b2010-01-21 02:13:41 +00003993static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003994{
3995 cache_info->mapped=MagickFalse;
3996 cache_info->pixels=(PixelPacket *) AcquireMagickMemory((size_t)
3997 cache_info->length);
3998 if (cache_info->pixels == (PixelPacket *) NULL)
3999 {
4000 cache_info->mapped=MagickTrue;
4001 cache_info->pixels=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
4002 cache_info->length);
4003 }
4004}
4005
4006static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
4007{
4008 CacheInfo
4009 *cache_info;
4010
4011 MagickOffsetType
4012 count,
4013 extent,
4014 offset;
4015
4016 cache_info=(CacheInfo *) image->cache;
4017 if (image->debug != MagickFalse)
4018 {
4019 char
4020 format[MaxTextExtent],
4021 message[MaxTextExtent];
4022
cristyb9080c92009-12-01 20:13:26 +00004023 (void) FormatMagickSize(length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00004024 (void) FormatMagickString(message,MaxTextExtent,
cristy2ce15c92010-03-12 14:03:41 +00004025 "extend %s (%s[%d], disk, %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00004026 cache_info->cache_filename,cache_info->file,format);
4027 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4028 }
4029 if (length != (MagickSizeType) ((MagickOffsetType) length))
4030 return(MagickFalse);
4031 extent=(MagickOffsetType) MagickSeek(cache_info->file,0,SEEK_END);
4032 if (extent < 0)
4033 return(MagickFalse);
4034 if ((MagickSizeType) extent >= length)
4035 return(MagickTrue);
4036 offset=(MagickOffsetType) length-1;
4037 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
4038 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
4039}
4040
4041static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
4042 ExceptionInfo *exception)
4043{
4044 char
4045 format[MaxTextExtent],
4046 message[MaxTextExtent];
4047
4048 CacheInfo
4049 *cache_info,
4050 source_info;
4051
4052 MagickSizeType
4053 length,
4054 number_pixels;
4055
4056 MagickStatusType
4057 status;
4058
4059 size_t
4060 packet_size;
4061
cristybb503372010-05-27 20:51:26 +00004062 size_t
cristy3ed852e2009-09-05 21:47:34 +00004063 columns;
4064
4065 if (image->debug != MagickFalse)
4066 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4067 if ((image->columns == 0) || (image->rows == 0))
4068 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
4069 cache_info=(CacheInfo *) image->cache;
4070 source_info=(*cache_info);
4071 source_info.file=(-1);
cristye8c25f92010-06-03 00:53:06 +00004072 (void) FormatMagickString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
4073 image->filename,(double) GetImageIndexInList(image));
cristy87528ea2009-09-10 14:53:56 +00004074 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +00004075 cache_info->rows=image->rows;
4076 cache_info->columns=image->columns;
4077 cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
4078 (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
cristy73724512010-04-12 14:43:14 +00004079 if (image->ping != MagickFalse)
4080 {
4081 cache_info->storage_class=image->storage_class;
4082 cache_info->colorspace=image->colorspace;
4083 cache_info->type=PingCache;
4084 cache_info->pixels=(PixelPacket *) NULL;
4085 cache_info->indexes=(IndexPacket *) NULL;
4086 cache_info->length=0;
4087 return(MagickTrue);
4088 }
cristy3ed852e2009-09-05 21:47:34 +00004089 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4090 packet_size=sizeof(PixelPacket);
4091 if (cache_info->active_index_channel != MagickFalse)
4092 packet_size+=sizeof(IndexPacket);
4093 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00004094 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00004095 if (cache_info->columns != columns)
4096 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4097 image->filename);
4098 cache_info->length=length;
4099 status=AcquireMagickResource(AreaResource,cache_info->length);
4100 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4101 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4102 {
4103 status=AcquireMagickResource(MemoryResource,cache_info->length);
4104 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4105 (cache_info->type == MemoryCache))
4106 {
cristyd43a46b2010-01-21 02:13:41 +00004107 AllocatePixelCachePixels(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004108 if (cache_info->pixels == (PixelPacket *) NULL)
4109 cache_info->pixels=source_info.pixels;
4110 else
4111 {
4112 /*
4113 Create memory pixel cache.
4114 */
4115 if (image->debug != MagickFalse)
4116 {
cristy97e7a572009-12-05 15:07:53 +00004117 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004118 format);
cristy3ed852e2009-09-05 21:47:34 +00004119 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004120 "open %s (%s memory, %.20gx%.20g %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00004121 cache_info->mapped != MagickFalse ? "anonymous" : "heap",
cristye8c25f92010-06-03 00:53:06 +00004122 (double) cache_info->columns,(double) cache_info->rows,
4123 format);
cristy3ed852e2009-09-05 21:47:34 +00004124 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4125 message);
4126 }
4127 cache_info->storage_class=image->storage_class;
4128 cache_info->colorspace=image->colorspace;
4129 cache_info->type=MemoryCache;
4130 cache_info->indexes=(IndexPacket *) NULL;
4131 if (cache_info->active_index_channel != MagickFalse)
4132 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4133 number_pixels);
4134 if (source_info.storage_class != UndefinedClass)
4135 {
4136 status|=ClonePixelCachePixels(cache_info,&source_info,
4137 exception);
4138 RelinquishPixelCachePixels(&source_info);
4139 }
4140 return(MagickTrue);
4141 }
4142 }
4143 RelinquishMagickResource(MemoryResource,cache_info->length);
4144 }
4145 /*
4146 Create pixel cache on disk.
4147 */
4148 status=AcquireMagickResource(DiskResource,cache_info->length);
4149 if (status == MagickFalse)
4150 {
4151 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4152 "CacheResourcesExhausted","`%s'",image->filename);
4153 return(MagickFalse);
4154 }
4155 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4156 {
4157 RelinquishMagickResource(DiskResource,cache_info->length);
4158 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4159 image->filename);
4160 return(MagickFalse);
4161 }
4162 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4163 cache_info->length);
4164 if (status == MagickFalse)
4165 {
4166 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4167 image->filename);
4168 return(MagickFalse);
4169 }
4170 cache_info->storage_class=image->storage_class;
4171 cache_info->colorspace=image->colorspace;
4172 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4173 status=AcquireMagickResource(AreaResource,cache_info->length);
4174 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4175 cache_info->type=DiskCache;
4176 else
4177 {
4178 status=AcquireMagickResource(MapResource,cache_info->length);
4179 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4180 (cache_info->type != MemoryCache))
4181 cache_info->type=DiskCache;
4182 else
4183 {
4184 cache_info->pixels=(PixelPacket *) MapBlob(cache_info->file,mode,
4185 cache_info->offset,(size_t) cache_info->length);
4186 if (cache_info->pixels == (PixelPacket *) NULL)
4187 {
4188 cache_info->pixels=source_info.pixels;
4189 cache_info->type=DiskCache;
4190 }
4191 else
4192 {
4193 /*
4194 Create file-backed memory-mapped pixel cache.
4195 */
4196 (void) ClosePixelCacheOnDisk(cache_info);
4197 cache_info->type=MapCache;
4198 cache_info->mapped=MagickTrue;
4199 cache_info->indexes=(IndexPacket *) NULL;
4200 if (cache_info->active_index_channel != MagickFalse)
4201 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4202 number_pixels);
4203 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4204 {
4205 status=ClonePixelCachePixels(cache_info,&source_info,
4206 exception);
4207 RelinquishPixelCachePixels(&source_info);
4208 }
4209 if (image->debug != MagickFalse)
4210 {
cristy97e7a572009-12-05 15:07:53 +00004211 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004212 format);
cristy3ed852e2009-09-05 21:47:34 +00004213 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004214 "open %s (%s[%d], memory-mapped, %.20gx%.20g %sB)",
cristy3ed852e2009-09-05 21:47:34 +00004215 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004216 cache_info->file,(double) cache_info->columns,(double)
4217 cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004218 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4219 message);
4220 }
4221 return(MagickTrue);
4222 }
4223 }
4224 RelinquishMagickResource(MapResource,cache_info->length);
4225 }
4226 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4227 {
4228 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4229 RelinquishPixelCachePixels(&source_info);
4230 }
4231 if (image->debug != MagickFalse)
4232 {
cristyb9080c92009-12-01 20:13:26 +00004233 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00004234 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004235 "open %s (%s[%d], disk, %.20gx%.20g %sB)",cache_info->filename,
4236 cache_info->cache_filename,cache_info->file,(double)
4237 cache_info->columns,(double) cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004238 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4239 }
4240 return(MagickTrue);
4241}
4242
4243/*
4244%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4245% %
4246% %
4247% %
4248+ P e r s i s t P i x e l C a c h e %
4249% %
4250% %
4251% %
4252%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4253%
4254% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4255% persistent pixel cache is one that resides on disk and is not destroyed
4256% when the program exits.
4257%
4258% The format of the PersistPixelCache() method is:
4259%
4260% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4261% const MagickBooleanType attach,MagickOffsetType *offset,
4262% ExceptionInfo *exception)
4263%
4264% A description of each parameter follows:
4265%
4266% o image: the image.
4267%
4268% o filename: the persistent pixel cache filename.
4269%
cristy01b7eb02009-09-10 23:10:14 +00004270% o attach: A value other than zero initializes the persistent pixel
4271% cache.
4272%
cristy3ed852e2009-09-05 21:47:34 +00004273% o initialize: A value other than zero initializes the persistent pixel
4274% cache.
4275%
4276% o offset: the offset in the persistent cache to store pixels.
4277%
4278% o exception: return any errors or warnings in this structure.
4279%
4280*/
4281MagickExport MagickBooleanType PersistPixelCache(Image *image,
4282 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4283 ExceptionInfo *exception)
4284{
4285 CacheInfo
4286 *cache_info,
4287 *clone_info;
4288
4289 Image
4290 clone_image;
4291
cristybb503372010-05-27 20:51:26 +00004292 ssize_t
cristy688f07b2009-09-27 15:19:13 +00004293 page_size;
cristy3ed852e2009-09-05 21:47:34 +00004294
4295 MagickBooleanType
4296 status;
4297
4298 assert(image != (Image *) NULL);
4299 assert(image->signature == MagickSignature);
4300 if (image->debug != MagickFalse)
4301 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4302 assert(image->cache != (void *) NULL);
4303 assert(filename != (const char *) NULL);
4304 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004305 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004306 cache_info=(CacheInfo *) image->cache;
4307 assert(cache_info->signature == MagickSignature);
4308 if (attach != MagickFalse)
4309 {
4310 /*
cristy01b7eb02009-09-10 23:10:14 +00004311 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004312 */
4313 if (image->debug != MagickFalse)
4314 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4315 "attach persistent cache");
4316 (void) CopyMagickString(cache_info->cache_filename,filename,
4317 MaxTextExtent);
4318 cache_info->type=DiskCache;
4319 cache_info->offset=(*offset);
4320 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4321 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004322 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004323 return(MagickTrue);
4324 }
cristy01b7eb02009-09-10 23:10:14 +00004325 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4326 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004327 {
cristyf84a1932010-01-03 18:00:18 +00004328 LockSemaphoreInfo(cache_info->semaphore);
cristy09449f72010-01-23 03:08:36 +00004329 if ((cache_info->mode != ReadMode) &&
4330 (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004331 (cache_info->reference_count == 1))
4332 {
4333 int
4334 status;
4335
4336 /*
cristy01b7eb02009-09-10 23:10:14 +00004337 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004338 */
4339 status=rename(cache_info->cache_filename,filename);
4340 if (status == 0)
4341 {
4342 (void) CopyMagickString(cache_info->cache_filename,filename,
4343 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004344 *offset+=cache_info->length+page_size-(cache_info->length %
4345 page_size);
cristyf84a1932010-01-03 18:00:18 +00004346 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004347 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004348 if (image->debug != MagickFalse)
4349 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4350 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004351 return(MagickTrue);
4352 }
4353 }
cristyf84a1932010-01-03 18:00:18 +00004354 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004355 }
4356 /*
cristy01b7eb02009-09-10 23:10:14 +00004357 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004358 */
4359 clone_image=(*image);
4360 clone_info=(CacheInfo *) clone_image.cache;
4361 image->cache=ClonePixelCache(cache_info);
4362 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4363 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4364 cache_info->type=DiskCache;
4365 cache_info->offset=(*offset);
4366 cache_info=(CacheInfo *) image->cache;
4367 status=ClonePixelCacheNexus(cache_info,clone_info,exception);
4368 if (status != MagickFalse)
4369 {
4370 status=OpenPixelCache(image,IOMode,exception);
4371 if (status != MagickFalse)
4372 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
4373 }
cristy688f07b2009-09-27 15:19:13 +00004374 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004375 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4376 return(status);
4377}
4378
4379/*
4380%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4381% %
4382% %
4383% %
4384+ Q u e u e A u t h e n t i c N e x u s %
4385% %
4386% %
4387% %
4388%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4389%
4390% QueueAuthenticNexus() allocates an region to store image pixels as defined
4391% by the region rectangle and returns a pointer to the region. This region is
4392% subsequently transferred from the pixel cache with
4393% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4394% pixels are transferred, otherwise a NULL is returned.
4395%
4396% The format of the QueueAuthenticNexus() method is:
4397%
cristy5f959472010-05-27 22:19:46 +00004398% PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
4399% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004400% NexusInfo *nexus_info,ExceptionInfo *exception)
4401%
4402% A description of each parameter follows:
4403%
4404% o image: the image.
4405%
4406% o x,y,columns,rows: These values define the perimeter of a region of
4407% pixels.
4408%
4409% o nexus_info: the cache nexus to set.
4410%
4411% o exception: return any errors or warnings in this structure.
4412%
4413*/
cristybb503372010-05-27 20:51:26 +00004414MagickExport PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy30097232010-07-01 02:16:30 +00004415 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
4416 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004417{
4418 CacheInfo
4419 *cache_info;
4420
4421 MagickOffsetType
4422 offset;
4423
4424 MagickSizeType
4425 number_pixels;
4426
4427 RectangleInfo
4428 region;
4429
4430 /*
4431 Validate pixel cache geometry.
4432 */
4433 cache_info=(CacheInfo *) image->cache;
4434 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4435 {
4436 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4437 "NoPixelsDefinedInCache","`%s'",image->filename);
4438 return((PixelPacket *) NULL);
4439 }
cristybb503372010-05-27 20:51:26 +00004440 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4441 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004442 {
4443 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4444 "PixelsAreNotAuthentic","`%s'",image->filename);
4445 return((PixelPacket *) NULL);
4446 }
4447 offset=(MagickOffsetType) y*cache_info->columns+x;
4448 if (offset < 0)
4449 return((PixelPacket *) NULL);
4450 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4451 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4452 if ((MagickSizeType) offset >= number_pixels)
4453 return((PixelPacket *) NULL);
4454 /*
4455 Return pixel cache.
4456 */
4457 region.x=x;
4458 region.y=y;
4459 region.width=columns;
4460 region.height=rows;
4461 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4462}
4463
4464/*
4465%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4466% %
4467% %
4468% %
4469+ 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 %
4470% %
4471% %
4472% %
4473%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4474%
4475% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4476% defined by the region rectangle and returns a pointer to the region. This
4477% region is subsequently transferred from the pixel cache with
4478% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4479% pixels are transferred, otherwise a NULL is returned.
4480%
4481% The format of the QueueAuthenticPixelsCache() method is:
4482%
cristybb503372010-05-27 20:51:26 +00004483% PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4484% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004485% ExceptionInfo *exception)
4486%
4487% A description of each parameter follows:
4488%
4489% o image: the image.
4490%
4491% o x,y,columns,rows: These values define the perimeter of a region of
4492% pixels.
4493%
4494% o exception: return any errors or warnings in this structure.
4495%
4496*/
cristybb503372010-05-27 20:51:26 +00004497static PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4498 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004499 ExceptionInfo *exception)
4500{
4501 CacheInfo
4502 *cache_info;
4503
cristy6ebe97c2010-07-03 01:17:28 +00004504 int
cristy3ed852e2009-09-05 21:47:34 +00004505 id;
4506
4507 PixelPacket
4508 *pixels;
4509
4510 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickFalse,exception);
4511 if (cache_info == (Cache) NULL)
4512 return((PixelPacket *) NULL);
4513 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00004514 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00004515 pixels=QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4516 exception);
4517 return(pixels);
4518}
4519
4520/*
4521%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4522% %
4523% %
4524% %
4525% Q u e u e A u t h e n t i c P i x e l s %
4526% %
4527% %
4528% %
4529%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4530%
4531% QueueAuthenticPixels() queues a mutable pixel region. If the region is
4532% successfully intialized a pointer to a PixelPacket array representing the
4533% region is returned, otherwise NULL is returned. The returned pointer may
4534% point to a temporary working buffer for the pixels or it may point to the
4535% final location of the pixels in memory.
4536%
4537% Write-only access means that any existing pixel values corresponding to
4538% the region are ignored. This is useful if the initial image is being
4539% created from scratch, or if the existing pixel values are to be
4540% completely replaced without need to refer to their pre-existing values.
4541% The application is free to read and write the pixel buffer returned by
4542% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4543% initialize the pixel array values. Initializing pixel array values is the
4544% application's responsibility.
4545%
4546% Performance is maximized if the selected region is part of one row, or
4547% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004548% pixels in-place (without a copy) if the image is in memory, or in a
4549% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004550% by the user.
4551%
4552% Pixels accessed via the returned pointer represent a simple array of type
4553% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
4554% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
4555% the black color component or the colormap indexes (of type IndexPacket)
4556% corresponding to the region. Once the PixelPacket (and/or IndexPacket)
4557% array has been updated, the changes must be saved back to the underlying
4558% image using SyncAuthenticPixels() or they may be lost.
4559%
4560% The format of the QueueAuthenticPixels() method is:
4561%
cristy5f959472010-05-27 22:19:46 +00004562% PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4563% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004564% ExceptionInfo *exception)
4565%
4566% A description of each parameter follows:
4567%
4568% o image: the image.
4569%
4570% o x,y,columns,rows: These values define the perimeter of a region of
4571% pixels.
4572%
4573% o exception: return any errors or warnings in this structure.
4574%
4575*/
cristybb503372010-05-27 20:51:26 +00004576MagickExport PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4577 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004578 ExceptionInfo *exception)
4579{
4580 CacheInfo
4581 *cache_info;
4582
4583 PixelPacket
4584 *pixels;
4585
4586 assert(image != (Image *) NULL);
4587 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004588 assert(image->cache != (Cache) NULL);
4589 cache_info=(CacheInfo *) image->cache;
4590 assert(cache_info->signature == MagickSignature);
4591 if (cache_info->methods.queue_authentic_pixels_handler ==
4592 (QueueAuthenticPixelsHandler) NULL)
4593 return((PixelPacket *) NULL);
4594 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4595 rows,exception);
4596 return(pixels);
4597}
4598
4599/*
4600%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4601% %
4602% %
4603% %
4604+ R e a d P i x e l C a c h e I n d e x e s %
4605% %
4606% %
4607% %
4608%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4609%
4610% ReadPixelCacheIndexes() reads colormap indexes from the specified region of
4611% the pixel cache.
4612%
4613% The format of the ReadPixelCacheIndexes() method is:
4614%
4615% MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4616% NexusInfo *nexus_info,ExceptionInfo *exception)
4617%
4618% A description of each parameter follows:
4619%
4620% o cache_info: the pixel cache.
4621%
4622% o nexus_info: the cache nexus to read the colormap indexes.
4623%
4624% o exception: return any errors or warnings in this structure.
4625%
4626*/
4627static MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4628 NexusInfo *nexus_info,ExceptionInfo *exception)
4629{
4630 MagickOffsetType
4631 count,
4632 offset;
4633
4634 MagickSizeType
4635 length,
4636 number_pixels;
4637
4638 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004639 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004640
cristybb503372010-05-27 20:51:26 +00004641 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004642 y;
4643
cristybb503372010-05-27 20:51:26 +00004644 size_t
cristy3ed852e2009-09-05 21:47:34 +00004645 rows;
4646
cristy3ed852e2009-09-05 21:47:34 +00004647 if (cache_info->active_index_channel == MagickFalse)
4648 return(MagickFalse);
4649 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4650 return(MagickTrue);
4651 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4652 nexus_info->region.x;
4653 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
4654 rows=nexus_info->region.height;
4655 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004656 q=nexus_info->indexes;
4657 switch (cache_info->type)
4658 {
4659 case MemoryCache:
4660 case MapCache:
4661 {
4662 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004663 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004664
4665 /*
4666 Read indexes from memory.
4667 */
cristydd341db2010-03-04 19:06:38 +00004668 if ((cache_info->columns == nexus_info->region.width) &&
4669 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4670 {
4671 length=number_pixels;
4672 rows=1UL;
4673 }
cristy3ed852e2009-09-05 21:47:34 +00004674 p=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00004675 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004676 {
4677 (void) CopyMagickMemory(q,p,(size_t) length);
4678 p+=cache_info->columns;
4679 q+=nexus_info->region.width;
4680 }
4681 break;
4682 }
4683 case DiskCache:
4684 {
4685 /*
4686 Read indexes from disk.
4687 */
4688 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4689 {
4690 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4691 cache_info->cache_filename);
4692 return(MagickFalse);
4693 }
cristydd341db2010-03-04 19:06:38 +00004694 if ((cache_info->columns == nexus_info->region.width) &&
4695 (number_pixels < MagickMaxBufferExtent))
4696 {
4697 length=number_pixels;
4698 rows=1UL;
4699 }
cristy3ed852e2009-09-05 21:47:34 +00004700 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004701 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004702 {
4703 count=ReadPixelCacheRegion(cache_info,cache_info->offset+number_pixels*
4704 sizeof(PixelPacket)+offset*sizeof(*q),length,(unsigned char *) q);
4705 if ((MagickSizeType) count < length)
4706 break;
4707 offset+=cache_info->columns;
4708 q+=nexus_info->region.width;
4709 }
cristybb503372010-05-27 20:51:26 +00004710 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004711 {
4712 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4713 cache_info->cache_filename);
4714 return(MagickFalse);
4715 }
4716 break;
4717 }
4718 default:
4719 break;
4720 }
4721 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004722 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004723 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004724 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004725 nexus_info->region.width,(double) nexus_info->region.height,(double)
4726 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004727 return(MagickTrue);
4728}
4729
4730/*
4731%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4732% %
4733% %
4734% %
4735+ R e a d P i x e l C a c h e P i x e l s %
4736% %
4737% %
4738% %
4739%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4740%
4741% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4742% cache.
4743%
4744% The format of the ReadPixelCachePixels() method is:
4745%
4746% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4747% NexusInfo *nexus_info,ExceptionInfo *exception)
4748%
4749% A description of each parameter follows:
4750%
4751% o cache_info: the pixel cache.
4752%
4753% o nexus_info: the cache nexus to read the pixels.
4754%
4755% o exception: return any errors or warnings in this structure.
4756%
4757*/
4758static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4759 NexusInfo *nexus_info,ExceptionInfo *exception)
4760{
4761 MagickOffsetType
4762 count,
4763 offset;
4764
4765 MagickSizeType
4766 length,
4767 number_pixels;
4768
cristybb503372010-05-27 20:51:26 +00004769 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004770 y;
4771
4772 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004773 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004774
cristybb503372010-05-27 20:51:26 +00004775 size_t
cristy3ed852e2009-09-05 21:47:34 +00004776 rows;
4777
cristy3ed852e2009-09-05 21:47:34 +00004778 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4779 return(MagickTrue);
4780 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4781 nexus_info->region.x;
4782 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
4783 rows=nexus_info->region.height;
4784 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004785 q=nexus_info->pixels;
4786 switch (cache_info->type)
4787 {
4788 case MemoryCache:
4789 case MapCache:
4790 {
4791 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004792 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004793
4794 /*
4795 Read pixels from memory.
4796 */
cristydd341db2010-03-04 19:06:38 +00004797 if ((cache_info->columns == nexus_info->region.width) &&
4798 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4799 {
4800 length=number_pixels;
4801 rows=1UL;
4802 }
cristy3ed852e2009-09-05 21:47:34 +00004803 p=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00004804 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004805 {
4806 (void) CopyMagickMemory(q,p,(size_t) length);
4807 p+=cache_info->columns;
4808 q+=nexus_info->region.width;
4809 }
4810 break;
4811 }
4812 case DiskCache:
4813 {
4814 /*
4815 Read pixels from disk.
4816 */
4817 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4818 {
4819 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4820 cache_info->cache_filename);
4821 return(MagickFalse);
4822 }
cristydd341db2010-03-04 19:06:38 +00004823 if ((cache_info->columns == nexus_info->region.width) &&
4824 (number_pixels < MagickMaxBufferExtent))
4825 {
4826 length=number_pixels;
4827 rows=1UL;
4828 }
cristybb503372010-05-27 20:51:26 +00004829 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004830 {
4831 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4832 sizeof(*q),length,(unsigned char *) q);
4833 if ((MagickSizeType) count < length)
4834 break;
4835 offset+=cache_info->columns;
4836 q+=nexus_info->region.width;
4837 }
cristybb503372010-05-27 20:51:26 +00004838 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004839 {
4840 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4841 cache_info->cache_filename);
4842 return(MagickFalse);
4843 }
4844 break;
4845 }
4846 default:
4847 break;
4848 }
4849 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004850 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004851 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004852 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004853 nexus_info->region.width,(double) nexus_info->region.height,(double)
4854 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004855 return(MagickTrue);
4856}
4857
4858/*
4859%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4860% %
4861% %
4862% %
4863+ R e f e r e n c e P i x e l C a c h e %
4864% %
4865% %
4866% %
4867%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4868%
4869% ReferencePixelCache() increments the reference count associated with the
4870% pixel cache returning a pointer to the cache.
4871%
4872% The format of the ReferencePixelCache method is:
4873%
4874% Cache ReferencePixelCache(Cache cache_info)
4875%
4876% A description of each parameter follows:
4877%
4878% o cache_info: the pixel cache.
4879%
4880*/
4881MagickExport Cache ReferencePixelCache(Cache cache)
4882{
4883 CacheInfo
4884 *cache_info;
4885
4886 assert(cache != (Cache *) NULL);
4887 cache_info=(CacheInfo *) cache;
4888 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004889 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004890 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004891 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004892 return(cache_info);
4893}
4894
4895/*
4896%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4897% %
4898% %
4899% %
4900+ S e t P i x e l C a c h e M e t h o d s %
4901% %
4902% %
4903% %
4904%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4905%
4906% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4907%
4908% The format of the SetPixelCacheMethods() method is:
4909%
4910% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4911%
4912% A description of each parameter follows:
4913%
4914% o cache: the pixel cache.
4915%
4916% o cache_methods: Specifies a pointer to a CacheMethods structure.
4917%
4918*/
4919MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4920{
4921 CacheInfo
4922 *cache_info;
4923
4924 GetOneAuthenticPixelFromHandler
4925 get_one_authentic_pixel_from_handler;
4926
4927 GetOneVirtualPixelFromHandler
4928 get_one_virtual_pixel_from_handler;
4929
4930 /*
4931 Set cache pixel methods.
4932 */
4933 assert(cache != (Cache) NULL);
4934 assert(cache_methods != (CacheMethods *) NULL);
4935 cache_info=(CacheInfo *) cache;
4936 assert(cache_info->signature == MagickSignature);
4937 if (cache_info->debug != MagickFalse)
4938 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4939 cache_info->filename);
4940 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4941 cache_info->methods.get_virtual_pixel_handler=
4942 cache_methods->get_virtual_pixel_handler;
4943 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4944 cache_info->methods.destroy_pixel_handler=
4945 cache_methods->destroy_pixel_handler;
4946 if (cache_methods->get_virtual_indexes_from_handler !=
4947 (GetVirtualIndexesFromHandler) NULL)
4948 cache_info->methods.get_virtual_indexes_from_handler=
4949 cache_methods->get_virtual_indexes_from_handler;
4950 if (cache_methods->get_authentic_pixels_handler !=
4951 (GetAuthenticPixelsHandler) NULL)
4952 cache_info->methods.get_authentic_pixels_handler=
4953 cache_methods->get_authentic_pixels_handler;
4954 if (cache_methods->queue_authentic_pixels_handler !=
4955 (QueueAuthenticPixelsHandler) NULL)
4956 cache_info->methods.queue_authentic_pixels_handler=
4957 cache_methods->queue_authentic_pixels_handler;
4958 if (cache_methods->sync_authentic_pixels_handler !=
4959 (SyncAuthenticPixelsHandler) NULL)
4960 cache_info->methods.sync_authentic_pixels_handler=
4961 cache_methods->sync_authentic_pixels_handler;
4962 if (cache_methods->get_authentic_pixels_from_handler !=
4963 (GetAuthenticPixelsFromHandler) NULL)
4964 cache_info->methods.get_authentic_pixels_from_handler=
4965 cache_methods->get_authentic_pixels_from_handler;
4966 if (cache_methods->get_authentic_indexes_from_handler !=
4967 (GetAuthenticIndexesFromHandler) NULL)
4968 cache_info->methods.get_authentic_indexes_from_handler=
4969 cache_methods->get_authentic_indexes_from_handler;
4970 get_one_virtual_pixel_from_handler=
4971 cache_info->methods.get_one_virtual_pixel_from_handler;
4972 if (get_one_virtual_pixel_from_handler !=
4973 (GetOneVirtualPixelFromHandler) NULL)
4974 cache_info->methods.get_one_virtual_pixel_from_handler=
4975 cache_methods->get_one_virtual_pixel_from_handler;
4976 get_one_authentic_pixel_from_handler=
4977 cache_methods->get_one_authentic_pixel_from_handler;
4978 if (get_one_authentic_pixel_from_handler !=
4979 (GetOneAuthenticPixelFromHandler) NULL)
4980 cache_info->methods.get_one_authentic_pixel_from_handler=
4981 cache_methods->get_one_authentic_pixel_from_handler;
4982}
4983
4984/*
4985%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4986% %
4987% %
4988% %
4989+ S e t P i x e l C a c h e N e x u s P i x e l s %
4990% %
4991% %
4992% %
4993%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4994%
4995% SetPixelCacheNexusPixels() defines the region of the cache for the
4996% specified cache nexus.
4997%
4998% The format of the SetPixelCacheNexusPixels() method is:
4999%
5000% PixelPacket SetPixelCacheNexusPixels(const Image *image,
5001% const RectangleInfo *region,NexusInfo *nexus_info,
5002% ExceptionInfo *exception)
5003%
5004% A description of each parameter follows:
5005%
5006% o image: the image.
5007%
5008% o region: A pointer to the RectangleInfo structure that defines the
5009% region of this particular cache nexus.
5010%
5011% o nexus_info: the cache nexus to set.
5012%
5013% o exception: return any errors or warnings in this structure.
5014%
5015*/
5016static PixelPacket *SetPixelCacheNexusPixels(const Image *image,
5017 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
5018{
5019 CacheInfo
5020 *cache_info;
5021
5022 MagickBooleanType
5023 status;
5024
cristy3ed852e2009-09-05 21:47:34 +00005025 MagickSizeType
5026 length,
5027 number_pixels;
5028
cristy3ed852e2009-09-05 21:47:34 +00005029 cache_info=(CacheInfo *) image->cache;
5030 assert(cache_info->signature == MagickSignature);
5031 if (cache_info->type == UndefinedCache)
5032 return((PixelPacket *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00005033 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00005034 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
5035 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00005036 {
cristybb503372010-05-27 20:51:26 +00005037 ssize_t
cristybad067a2010-02-15 17:20:55 +00005038 x,
5039 y;
cristy3ed852e2009-09-05 21:47:34 +00005040
cristyeaedf062010-05-29 22:36:02 +00005041 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
5042 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00005043 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5044 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristy731c3532010-02-15 15:40:03 +00005045 ((nexus_info->region.height == 1UL) ||
5046 ((nexus_info->region.x == 0) &&
5047 ((nexus_info->region.width == cache_info->columns) ||
5048 ((nexus_info->region.width % cache_info->columns) == 0)))))
5049 {
5050 MagickOffsetType
5051 offset;
5052
5053 /*
5054 Pixels are accessed directly from memory.
5055 */
5056 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5057 nexus_info->region.x;
5058 nexus_info->pixels=cache_info->pixels+offset;
5059 nexus_info->indexes=(IndexPacket *) NULL;
5060 if (cache_info->active_index_channel != MagickFalse)
5061 nexus_info->indexes=cache_info->indexes+offset;
5062 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00005063 }
5064 }
5065 /*
5066 Pixels are stored in a cache region until they are synced to the cache.
5067 */
5068 number_pixels=(MagickSizeType) nexus_info->region.width*
5069 nexus_info->region.height;
5070 length=number_pixels*sizeof(PixelPacket);
5071 if (cache_info->active_index_channel != MagickFalse)
5072 length+=number_pixels*sizeof(IndexPacket);
5073 if (nexus_info->cache == (PixelPacket *) NULL)
5074 {
5075 nexus_info->length=length;
5076 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5077 if (status == MagickFalse)
5078 return((PixelPacket *) NULL);
5079 }
5080 else
5081 if (nexus_info->length != length)
5082 {
5083 RelinquishCacheNexusPixels(nexus_info);
5084 nexus_info->length=length;
5085 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5086 if (status == MagickFalse)
5087 return((PixelPacket *) NULL);
5088 }
5089 nexus_info->pixels=nexus_info->cache;
5090 nexus_info->indexes=(IndexPacket *) NULL;
5091 if (cache_info->active_index_channel != MagickFalse)
5092 nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
5093 return(nexus_info->pixels);
5094}
5095
5096/*
5097%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5098% %
5099% %
5100% %
5101% 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 %
5102% %
5103% %
5104% %
5105%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5106%
5107% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5108% pixel cache and returns the previous setting. A virtual pixel is any pixel
5109% access that is outside the boundaries of the image cache.
5110%
5111% The format of the SetPixelCacheVirtualMethod() method is:
5112%
5113% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5114% const VirtualPixelMethod virtual_pixel_method)
5115%
5116% A description of each parameter follows:
5117%
5118% o image: the image.
5119%
5120% o virtual_pixel_method: choose the type of virtual pixel.
5121%
5122*/
5123MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5124 const VirtualPixelMethod virtual_pixel_method)
5125{
5126 CacheInfo
5127 *cache_info;
5128
5129 VirtualPixelMethod
5130 method;
5131
5132 assert(image != (Image *) NULL);
5133 assert(image->signature == MagickSignature);
5134 if (image->debug != MagickFalse)
5135 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5136 assert(image->cache != (Cache) NULL);
5137 cache_info=(CacheInfo *) image->cache;
5138 assert(cache_info->signature == MagickSignature);
5139 method=cache_info->virtual_pixel_method;
5140 cache_info->virtual_pixel_method=virtual_pixel_method;
5141 return(method);
5142}
5143
5144/*
5145%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5146% %
5147% %
5148% %
5149+ 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 %
5150% %
5151% %
5152% %
5153%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5154%
5155% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5156% in-memory or disk cache. The method returns MagickTrue if the pixel region
5157% is synced, otherwise MagickFalse.
5158%
5159% The format of the SyncAuthenticPixelCacheNexus() method is:
5160%
5161% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5162% NexusInfo *nexus_info,ExceptionInfo *exception)
5163%
5164% A description of each parameter follows:
5165%
5166% o image: the image.
5167%
5168% o nexus_info: the cache nexus to sync.
5169%
5170% o exception: return any errors or warnings in this structure.
5171%
5172*/
5173MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5174 NexusInfo *nexus_info,ExceptionInfo *exception)
5175{
5176 CacheInfo
5177 *cache_info;
5178
5179 MagickBooleanType
5180 status;
5181
5182 /*
5183 Transfer pixels to the cache.
5184 */
5185 assert(image != (Image *) NULL);
5186 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005187 if (image->cache == (Cache) NULL)
5188 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5189 cache_info=(CacheInfo *) image->cache;
5190 if (cache_info->type == UndefinedCache)
5191 return(MagickFalse);
5192 if ((image->clip_mask != (Image *) NULL) &&
5193 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5194 return(MagickFalse);
5195 if ((image->mask != (Image *) NULL) &&
5196 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5197 return(MagickFalse);
5198 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5199 return(MagickTrue);
5200 assert(cache_info->signature == MagickSignature);
5201 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5202 if ((cache_info->active_index_channel != MagickFalse) &&
5203 (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
5204 return(MagickFalse);
5205 return(status);
5206}
5207
5208/*
5209%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5210% %
5211% %
5212% %
5213+ S y n c A u t h e n t i c P i x e l C a c h e %
5214% %
5215% %
5216% %
5217%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5218%
5219% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5220% or disk cache. The method returns MagickTrue if the pixel region is synced,
5221% otherwise MagickFalse.
5222%
5223% The format of the SyncAuthenticPixelsCache() method is:
5224%
5225% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5226% ExceptionInfo *exception)
5227%
5228% A description of each parameter follows:
5229%
5230% o image: the image.
5231%
5232% o exception: return any errors or warnings in this structure.
5233%
5234*/
5235static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5236 ExceptionInfo *exception)
5237{
5238 CacheInfo
5239 *cache_info;
5240
cristy6ebe97c2010-07-03 01:17:28 +00005241 int
cristy3ed852e2009-09-05 21:47:34 +00005242 id;
5243
5244 MagickBooleanType
5245 status;
5246
5247 cache_info=(CacheInfo *) image->cache;
5248 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00005249 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00005250 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5251 exception);
5252 return(status);
5253}
5254
5255/*
5256%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5257% %
5258% %
5259% %
5260% S y n c A u t h e n t i c P i x e l s %
5261% %
5262% %
5263% %
5264%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5265%
5266% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5267% The method returns MagickTrue if the pixel region is flushed, otherwise
5268% MagickFalse.
5269%
5270% The format of the SyncAuthenticPixels() method is:
5271%
5272% MagickBooleanType SyncAuthenticPixels(Image *image,
5273% ExceptionInfo *exception)
5274%
5275% A description of each parameter follows:
5276%
5277% o image: the image.
5278%
5279% o exception: return any errors or warnings in this structure.
5280%
5281*/
5282MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5283 ExceptionInfo *exception)
5284{
5285 CacheInfo
5286 *cache_info;
5287
5288 assert(image != (Image *) NULL);
5289 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005290 assert(image->cache != (Cache) NULL);
5291 cache_info=(CacheInfo *) image->cache;
5292 assert(cache_info->signature == MagickSignature);
5293 if (cache_info->methods.sync_authentic_pixels_handler ==
5294 (SyncAuthenticPixelsHandler) NULL)
5295 return(MagickFalse);
5296 return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
5297}
5298
5299/*
5300%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5301% %
5302% %
5303% %
5304+ W r i t e P i x e l C a c h e I n d e x e s %
5305% %
5306% %
5307% %
5308%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5309%
5310% WritePixelCacheIndexes() writes the colormap indexes to the specified
5311% region of the pixel cache.
5312%
5313% The format of the WritePixelCacheIndexes() method is:
5314%
5315% MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5316% NexusInfo *nexus_info,ExceptionInfo *exception)
5317%
5318% A description of each parameter follows:
5319%
5320% o cache_info: the pixel cache.
5321%
5322% o nexus_info: the cache nexus to write the colormap indexes.
5323%
5324% o exception: return any errors or warnings in this structure.
5325%
5326*/
5327static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5328 NexusInfo *nexus_info,ExceptionInfo *exception)
5329{
5330 MagickOffsetType
5331 count,
5332 offset;
5333
5334 MagickSizeType
5335 length,
5336 number_pixels;
5337
5338 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005339 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005340
cristybb503372010-05-27 20:51:26 +00005341 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005342 y;
5343
cristybb503372010-05-27 20:51:26 +00005344 size_t
cristy3ed852e2009-09-05 21:47:34 +00005345 rows;
5346
cristy3ed852e2009-09-05 21:47:34 +00005347 if (cache_info->active_index_channel == MagickFalse)
5348 return(MagickFalse);
5349 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5350 return(MagickTrue);
5351 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5352 nexus_info->region.x;
5353 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
5354 rows=nexus_info->region.height;
5355 number_pixels=(MagickSizeType) length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005356 p=nexus_info->indexes;
5357 switch (cache_info->type)
5358 {
5359 case MemoryCache:
5360 case MapCache:
5361 {
5362 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005363 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005364
5365 /*
5366 Write indexes to memory.
5367 */
cristydd341db2010-03-04 19:06:38 +00005368 if ((cache_info->columns == nexus_info->region.width) &&
5369 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5370 {
5371 length=number_pixels;
5372 rows=1UL;
5373 }
cristy3ed852e2009-09-05 21:47:34 +00005374 q=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00005375 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005376 {
5377 (void) CopyMagickMemory(q,p,(size_t) length);
5378 p+=nexus_info->region.width;
5379 q+=cache_info->columns;
5380 }
5381 break;
5382 }
5383 case DiskCache:
5384 {
5385 /*
5386 Write indexes to disk.
5387 */
5388 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5389 {
5390 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5391 cache_info->cache_filename);
5392 return(MagickFalse);
5393 }
cristydd341db2010-03-04 19:06:38 +00005394 if ((cache_info->columns == nexus_info->region.width) &&
5395 (number_pixels < MagickMaxBufferExtent))
5396 {
5397 length=number_pixels;
5398 rows=1UL;
5399 }
cristy3ed852e2009-09-05 21:47:34 +00005400 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005401 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005402 {
5403 count=WritePixelCacheRegion(cache_info,cache_info->offset+number_pixels*
5404 sizeof(PixelPacket)+offset*sizeof(*p),length,
5405 (const unsigned char *) p);
5406 if ((MagickSizeType) count < length)
5407 break;
5408 p+=nexus_info->region.width;
5409 offset+=cache_info->columns;
5410 }
cristybb503372010-05-27 20:51:26 +00005411 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005412 {
5413 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5414 cache_info->cache_filename);
5415 return(MagickFalse);
5416 }
5417 break;
5418 }
5419 default:
5420 break;
5421 }
5422 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005423 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005424 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005425 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005426 nexus_info->region.width,(double) nexus_info->region.height,(double)
5427 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005428 return(MagickTrue);
5429}
5430
5431/*
5432%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5433% %
5434% %
5435% %
5436+ W r i t e C a c h e P i x e l s %
5437% %
5438% %
5439% %
5440%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5441%
5442% WritePixelCachePixels() writes image pixels to the specified region of the
5443% pixel cache.
5444%
5445% The format of the WritePixelCachePixels() method is:
5446%
5447% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5448% NexusInfo *nexus_info,ExceptionInfo *exception)
5449%
5450% A description of each parameter follows:
5451%
5452% o cache_info: the pixel cache.
5453%
5454% o nexus_info: the cache nexus to write the pixels.
5455%
5456% o exception: return any errors or warnings in this structure.
5457%
5458*/
5459static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5460 NexusInfo *nexus_info,ExceptionInfo *exception)
5461{
5462 MagickOffsetType
5463 count,
5464 offset;
5465
5466 MagickSizeType
5467 length,
5468 number_pixels;
5469
cristy3ed852e2009-09-05 21:47:34 +00005470 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005471 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005472
cristybb503372010-05-27 20:51:26 +00005473 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005474 y;
5475
cristybb503372010-05-27 20:51:26 +00005476 size_t
cristy3ed852e2009-09-05 21:47:34 +00005477 rows;
5478
cristy3ed852e2009-09-05 21:47:34 +00005479 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5480 return(MagickTrue);
5481 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5482 nexus_info->region.x;
5483 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
5484 rows=nexus_info->region.height;
5485 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005486 p=nexus_info->pixels;
5487 switch (cache_info->type)
5488 {
5489 case MemoryCache:
5490 case MapCache:
5491 {
5492 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005493 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005494
5495 /*
5496 Write pixels to memory.
5497 */
cristydd341db2010-03-04 19:06:38 +00005498 if ((cache_info->columns == nexus_info->region.width) &&
5499 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5500 {
5501 length=number_pixels;
5502 rows=1UL;
5503 }
cristy3ed852e2009-09-05 21:47:34 +00005504 q=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00005505 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005506 {
5507 (void) CopyMagickMemory(q,p,(size_t) length);
5508 p+=nexus_info->region.width;
5509 q+=cache_info->columns;
5510 }
5511 break;
5512 }
5513 case DiskCache:
5514 {
5515 /*
5516 Write pixels to disk.
5517 */
5518 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5519 {
5520 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5521 cache_info->cache_filename);
5522 return(MagickFalse);
5523 }
cristydd341db2010-03-04 19:06:38 +00005524 if ((cache_info->columns == nexus_info->region.width) &&
5525 (number_pixels < MagickMaxBufferExtent))
5526 {
5527 length=number_pixels;
5528 rows=1UL;
5529 }
cristybb503372010-05-27 20:51:26 +00005530 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005531 {
5532 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5533 sizeof(*p),length,(const unsigned char *) p);
5534 if ((MagickSizeType) count < length)
5535 break;
5536 p+=nexus_info->region.width;
5537 offset+=cache_info->columns;
5538 }
cristybb503372010-05-27 20:51:26 +00005539 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005540 {
5541 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5542 cache_info->cache_filename);
5543 return(MagickFalse);
5544 }
5545 break;
5546 }
5547 default:
5548 break;
5549 }
5550 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005551 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005552 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005553 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005554 nexus_info->region.width,(double) nexus_info->region.height,(double)
5555 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005556 return(MagickTrue);
5557}