blob: 6e6cd6aebed03c4b44493b154a015e34a6731a2d [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"
59#include "magick/quantum.h"
60#include "magick/random_.h"
61#include "magick/resource_.h"
62#include "magick/semaphore.h"
63#include "magick/splay-tree.h"
64#include "magick/string_.h"
65#include "magick/thread-private.h"
66#include "magick/utility.h"
67#if defined(MAGICKCORE_ZLIB_DELEGATE)
68#include "zlib.h"
69#endif
70
71/*
72 Typedef declarations.
73*/
74typedef struct _MagickModulo
75{
cristybb503372010-05-27 20:51:26 +000076 ssize_t
cristy3ed852e2009-09-05 21:47:34 +000077 quotient,
78 remainder;
79} MagickModulo;
80
81struct _NexusInfo
82{
83 MagickBooleanType
84 mapped;
85
86 RectangleInfo
87 region;
88
89 MagickSizeType
90 length;
91
92 PixelPacket
93 *cache,
94 *pixels;
95
96 IndexPacket
97 *indexes;
98
cristybb503372010-05-27 20:51:26 +000099 size_t
cristy3ed852e2009-09-05 21:47:34 +0000100 signature;
101};
102
103/*
104 Forward declarations.
105*/
106#if defined(__cplusplus) || defined(c_plusplus)
107extern "C" {
108#endif
109
110static const IndexPacket
111 *GetVirtualIndexesFromCache(const Image *);
112
113static const PixelPacket
cristybb503372010-05-27 20:51:26 +0000114 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
115 const ssize_t,const size_t,const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000116 *GetVirtualPixelsCache(const Image *);
117
118static MagickBooleanType
cristy09c1c4d2010-06-30 18:23:16 +0000119 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,
120 PixelPacket *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000121 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
cristybb503372010-05-27 20:51:26 +0000122 const ssize_t,const ssize_t,PixelPacket *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000123 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
124 ReadPixelCacheIndexes(CacheInfo *,NexusInfo *,ExceptionInfo *),
125 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
126 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
127 WritePixelCacheIndexes(CacheInfo *,NexusInfo *,ExceptionInfo *),
128 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
129
130static PixelPacket
cristybb503372010-05-27 20:51:26 +0000131 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
132 const size_t,ExceptionInfo *),
133 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
134 const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000135 *SetPixelCacheNexusPixels(const Image *,const RectangleInfo *,NexusInfo *,
cristya4af2e32010-03-08 00:51:56 +0000136 ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +0000137
138#if defined(__cplusplus) || defined(c_plusplus)
139}
140#endif
141
142/*
143 Global declarations.
144*/
145static volatile MagickBooleanType
146 instantiate_cache = MagickFalse;
147
148static SemaphoreInfo
149 *cache_semaphore = (SemaphoreInfo *) NULL;
150
151static SplayTreeInfo
152 *cache_resources = (SplayTreeInfo *) NULL;
cristy3ed852e2009-09-05 21:47:34 +0000153
154/*
155%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
156% %
157% %
158% %
159+ A c q u i r e P i x e l C a c h e %
160% %
161% %
162% %
163%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
164%
165% AcquirePixelCache() acquires a pixel cache.
166%
167% The format of the AcquirePixelCache() method is:
168%
cristybb503372010-05-27 20:51:26 +0000169% Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000170%
171% A description of each parameter follows:
172%
173% o number_threads: the number of nexus threads.
174%
175*/
cristybb503372010-05-27 20:51:26 +0000176MagickExport Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000177{
178 CacheInfo
179 *cache_info;
180
181 cache_info=(CacheInfo *) AcquireAlignedMemory(1,sizeof(*cache_info));
182 if (cache_info == (CacheInfo *) NULL)
183 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
184 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
185 cache_info->type=UndefinedCache;
cristy87528ea2009-09-10 14:53:56 +0000186 cache_info->mode=IOMode;
cristy3ed852e2009-09-05 21:47:34 +0000187 cache_info->colorspace=RGBColorspace;
188 cache_info->file=(-1);
189 cache_info->id=GetMagickThreadId();
190 cache_info->number_threads=number_threads;
191 if (number_threads == 0)
192 cache_info->number_threads=GetOpenMPMaximumThreads();
193 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
194 if (cache_info->nexus_info == (NexusInfo **) NULL)
195 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
196 GetPixelCacheMethods(&cache_info->methods);
197 cache_info->reference_count=1;
198 cache_info->semaphore=AllocateSemaphoreInfo();
199 cache_info->disk_semaphore=AllocateSemaphoreInfo();
200 cache_info->debug=IsEventLogging();
201 cache_info->signature=MagickSignature;
202 if ((cache_resources == (SplayTreeInfo *) NULL) &&
203 (instantiate_cache == MagickFalse))
204 {
cristy4e1dff62009-10-25 20:36:03 +0000205 if (cache_semaphore == (SemaphoreInfo *) NULL)
206 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000207 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000208 if ((cache_resources == (SplayTreeInfo *) NULL) &&
209 (instantiate_cache == MagickFalse))
210 {
211 cache_resources=NewSplayTree((int (*)(const void *,const void *))
212 NULL,(void *(*)(void *)) NULL,(void *(*)(void *)) NULL);
213 instantiate_cache=MagickTrue;
214 }
cristyf84a1932010-01-03 18:00:18 +0000215 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000216 }
217 (void) AddValueToSplayTree(cache_resources,cache_info,cache_info);
218 return((Cache ) cache_info);
219}
220
221/*
222%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
223% %
224% %
225% %
226% A c q u i r e P i x e l C a c h e N e x u s %
227% %
228% %
229% %
230%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
231%
232% AcquirePixelCacheNexus() allocates the NexusInfo structure.
233%
234% The format of the AcquirePixelCacheNexus method is:
235%
cristybb503372010-05-27 20:51:26 +0000236% NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000237%
238% A description of each parameter follows:
239%
240% o number_threads: the number of nexus threads.
241%
242*/
243MagickExport NexusInfo **AcquirePixelCacheNexus(
cristybb503372010-05-27 20:51:26 +0000244 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000245{
cristybb503372010-05-27 20:51:26 +0000246 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000247 i;
248
249 NexusInfo
250 **nexus_info;
251
252 nexus_info=(NexusInfo **) AcquireAlignedMemory(number_threads,
253 sizeof(*nexus_info));
254 if (nexus_info == (NexusInfo **) NULL)
255 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristybb503372010-05-27 20:51:26 +0000256 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000257 {
258 nexus_info[i]=(NexusInfo *) AcquireAlignedMemory(1,sizeof(**nexus_info));
259 if (nexus_info[i] == (NexusInfo *) NULL)
260 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
261 (void) ResetMagickMemory(nexus_info[i],0,sizeof(*nexus_info[i]));
262 nexus_info[i]->signature=MagickSignature;
263 }
264 return(nexus_info);
265}
266
267/*
268%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
269% %
270% %
271% %
cristyd43a46b2010-01-21 02:13:41 +0000272+ A c q u i r e P i x e l C a c h e P i x e l s %
273% %
274% %
275% %
276%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
277%
278% AcquirePixelCachePixels() returns the pixels associated with the specified
279% image.
280%
281% The format of the AcquirePixelCachePixels() method is:
282%
283% const void *AcquirePixelCachePixels(const Image *image,
284% MagickSizeType *length,ExceptionInfo *exception)
285%
286% A description of each parameter follows:
287%
288% o image: the image.
289%
290% o length: the pixel cache length.
291%
292% o exception: return any errors or warnings in this structure.
293%
294*/
295MagickExport const void *AcquirePixelCachePixels(const Image *image,
296 MagickSizeType *length,ExceptionInfo *exception)
297{
298 CacheInfo
299 *cache_info;
300
301 assert(image != (const Image *) NULL);
302 assert(image->signature == MagickSignature);
303 if (image->debug != MagickFalse)
304 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
305 assert(exception != (ExceptionInfo *) NULL);
306 assert(exception->signature == MagickSignature);
307 assert(image->cache != (Cache) NULL);
308 cache_info=(CacheInfo *) image->cache;
309 assert(cache_info->signature == MagickSignature);
310 *length=0;
311 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
312 return((const void *) NULL);
313 *length=cache_info->length;
314 return((const void *) cache_info->pixels);
315}
316
317/*
318%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
319% %
320% %
321% %
cristyf34a1452009-10-24 22:29:27 +0000322+ C a c h e C o m p o n e n t G e n e s i s %
323% %
324% %
325% %
326%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
327%
328% CacheComponentGenesis() instantiates the cache component.
329%
330% The format of the CacheComponentGenesis method is:
331%
332% MagickBooleanType CacheComponentGenesis(void)
333%
334*/
335MagickExport MagickBooleanType CacheComponentGenesis(void)
336{
cristy165b6092009-10-26 13:52:10 +0000337 AcquireSemaphoreInfo(&cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000338 return(MagickTrue);
339}
340
341/*
342%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
343% %
344% %
345% %
346+ C a c h e C o m p o n e n t T e r m i n u s %
347% %
348% %
349% %
350%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
351%
352% CacheComponentTerminus() destroys the cache component.
353%
354% The format of the CacheComponentTerminus() method is:
355%
356% CacheComponentTerminus(void)
357%
358*/
359MagickExport void CacheComponentTerminus(void)
360{
cristy18b17442009-10-25 18:36:48 +0000361 if (cache_semaphore == (SemaphoreInfo *) NULL)
362 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000363 LockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000364 if (cache_resources != (SplayTreeInfo *) NULL)
365 cache_resources=DestroySplayTree(cache_resources);
366 instantiate_cache=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +0000367 UnlockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000368 DestroySemaphoreInfo(&cache_semaphore);
369}
370
371/*
372%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
373% %
374% %
375% %
cristy3ed852e2009-09-05 21:47:34 +0000376+ C l i p P i x e l C a c h e N e x u s %
377% %
378% %
379% %
380%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
381%
382% ClipPixelCacheNexus() clips the cache nexus as defined by the image clip
383% mask. The method returns MagickTrue if the pixel region is clipped,
384% otherwise MagickFalse.
385%
386% The format of the ClipPixelCacheNexus() method is:
387%
388% MagickBooleanType ClipPixelCacheNexus(Image *image,NexusInfo *nexus_info,
389% ExceptionInfo *exception)
390%
391% A description of each parameter follows:
392%
393% o image: the image.
394%
395% o nexus_info: the cache nexus to clip.
396%
397% o exception: return any errors or warnings in this structure.
398%
399*/
400static MagickBooleanType ClipPixelCacheNexus(Image *image,
401 NexusInfo *nexus_info,ExceptionInfo *exception)
402{
403 CacheInfo
404 *cache_info;
405
406 MagickSizeType
407 number_pixels;
408
409 NexusInfo
410 **clip_nexus,
411 **image_nexus;
412
413 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000414 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +0000415
416 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +0000417 *restrict nexus_indexes,
418 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +0000419
cristybb503372010-05-27 20:51:26 +0000420 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000421 i;
422
423 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000424 *restrict p,
425 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000426
427 /*
428 Apply clip mask.
429 */
430 if (image->debug != MagickFalse)
431 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
432 if (image->clip_mask == (Image *) NULL)
433 return(MagickFalse);
434 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
435 if (cache_info == (Cache) NULL)
436 return(MagickFalse);
437 image_nexus=AcquirePixelCacheNexus(1);
438 clip_nexus=AcquirePixelCacheNexus(1);
439 if ((image_nexus == (NexusInfo **) NULL) ||
440 (clip_nexus == (NexusInfo **) NULL))
441 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
442 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,nexus_info->region.y,
443 nexus_info->region.width,nexus_info->region.height,image_nexus[0],
444 exception);
445 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
446 q=nexus_info->pixels;
447 nexus_indexes=nexus_info->indexes;
448 r=GetVirtualPixelsFromNexus(image->clip_mask,MaskVirtualPixelMethod,
449 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
450 nexus_info->region.height,clip_nexus[0],exception);
451 number_pixels=(MagickSizeType) nexus_info->region.width*
452 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +0000453 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000454 {
455 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
456 break;
457 if (PixelIntensityToQuantum(r) > ((Quantum) QuantumRange/2))
458 {
cristyce70c172010-01-07 17:15:30 +0000459 SetRedPixelComponent(q,GetRedPixelComponent(p));
460 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
461 SetBluePixelComponent(q,GetBluePixelComponent(p));
462 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
cristy3ed852e2009-09-05 21:47:34 +0000463 if (cache_info->active_index_channel != MagickFalse)
464 nexus_indexes[i]=indexes[i];
465 }
466 p++;
467 q++;
468 r++;
469 }
470 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
471 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +0000472 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +0000473 return(MagickFalse);
474 return(MagickTrue);
475}
476
477/*
478%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
479% %
480% %
481% %
482+ C l o n e P i x e l C a c h e %
483% %
484% %
485% %
486%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
487%
488% ClonePixelCache() clones a pixel cache.
489%
490% The format of the ClonePixelCache() method is:
491%
492% Cache ClonePixelCache(const Cache cache)
493%
494% A description of each parameter follows:
495%
496% o cache: the pixel cache.
497%
498*/
499MagickExport Cache ClonePixelCache(const Cache cache)
500{
501 CacheInfo
502 *clone_info;
503
504 const CacheInfo
505 *cache_info;
506
507 assert(cache != (const Cache) NULL);
508 cache_info=(const CacheInfo *) cache;
509 assert(cache_info->signature == MagickSignature);
510 if (cache_info->debug != MagickFalse)
511 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
512 cache_info->filename);
513 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
514 if (clone_info == (Cache) NULL)
515 return((Cache) NULL);
516 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
517 return((Cache ) clone_info);
518}
519
520/*
521%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
522% %
523% %
524% %
525+ C l o n e P i x e l C a c h e N e x u s %
526% %
527% %
528% %
529%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
530%
531% ClonePixelCacheNexus() clones the source cache nexus to the destination
532% nexus.
533%
534% The format of the ClonePixelCacheNexus() method is:
535%
536% MagickBooleanType ClonePixelCacheNexus(CacheInfo *destination,
537% CacheInfo *source,ExceptionInfo *exception)
538%
539% A description of each parameter follows:
540%
541% o destination: the destination cache nexus.
542%
543% o source: the source cache nexus.
544%
545% o exception: return any errors or warnings in this structure.
546%
547*/
548
549static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
550 NexusInfo *nexus_info,ExceptionInfo *exception)
551{
552 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
553 return(MagickFalse);
554 nexus_info->mapped=MagickFalse;
555 nexus_info->cache=(PixelPacket *) AcquireMagickMemory((size_t)
556 nexus_info->length);
557 if (nexus_info->cache == (PixelPacket *) NULL)
558 {
559 nexus_info->mapped=MagickTrue;
560 nexus_info->cache=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
561 nexus_info->length);
562 }
563 if (nexus_info->cache == (PixelPacket *) NULL)
564 {
565 (void) ThrowMagickException(exception,GetMagickModule(),
566 ResourceLimitError,"MemoryAllocationFailed","`%s'",
567 cache_info->filename);
568 return(MagickFalse);
569 }
570 return(MagickTrue);
571}
572
573static MagickBooleanType ClonePixelCacheNexus(CacheInfo *destination,
574 CacheInfo *source,ExceptionInfo *exception)
575{
576 MagickBooleanType
577 status;
578
579 MagickSizeType
580 number_pixels;
581
cristybb503372010-05-27 20:51:26 +0000582 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000583 i;
584
585 register const NexusInfo
586 *p;
587
588 register NexusInfo
589 *q;
590
591 status=MagickTrue;
cristybb503372010-05-27 20:51:26 +0000592 for (i=0; i < (ssize_t) source->number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000593 {
594 p=source->nexus_info[i];
595 q=destination->nexus_info[i];
596 q->mapped=p->mapped;
597 q->region=p->region;
598 q->length=p->length;
599 q->cache=p->cache;
600 q->pixels=p->pixels;
601 q->indexes=p->indexes;
602 if (p->cache != (PixelPacket *) NULL)
603 {
604 status=AcquireCacheNexusPixels(source,q,exception);
605 if (status != MagickFalse)
606 {
607 (void) CopyMagickMemory(q->cache,p->cache,(size_t) p->length);
608 q->pixels=q->cache;
609 q->indexes=(IndexPacket *) NULL;
610 number_pixels=(MagickSizeType) q->region.width*q->region.height;
611 if (p->indexes != (IndexPacket *) NULL)
612 q->indexes=(IndexPacket *) (q->pixels+number_pixels);
613 }
614 }
615 }
616 return(status);
617}
618
619/*
620%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
621% %
622% %
623% %
cristy60c44a82009-10-07 00:58:49 +0000624+ 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 +0000625% %
626% %
627% %
628%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
629% ClonePixelCachePixels() clones the source pixel cache to the destination
630% cache.
631%
632% The format of the ClonePixelCachePixels() method is:
633%
634% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
635% CacheInfo *source_info,ExceptionInfo *exception)
636%
637% A description of each parameter follows:
638%
639% o cache_info: the pixel cache.
640%
641% o source_info: the source pixel cache.
642%
643% o exception: return any errors or warnings in this structure.
644%
645*/
646
647static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
648{
649 int
650 status;
651
cristy5ee247a2010-02-12 15:42:34 +0000652 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000653 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000654 if (cache_info->file != -1)
655 status=close(cache_info->file);
cristy3ed852e2009-09-05 21:47:34 +0000656 cache_info->file=(-1);
657 RelinquishMagickResource(FileResource,1);
cristyf84a1932010-01-03 18:00:18 +0000658 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000659 return(status == -1 ? MagickFalse : MagickTrue);
660}
661
662static void LimitPixelCacheDescriptors(void)
663{
664 register CacheInfo
665 *p,
666 *q;
667
668 /*
669 Limit # of open file descriptors.
670 */
671 if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
672 return;
cristyf84a1932010-01-03 18:00:18 +0000673 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000674 if (cache_resources == (SplayTreeInfo *) NULL)
675 {
cristyf84a1932010-01-03 18:00:18 +0000676 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000677 return;
678 }
679 ResetSplayTreeIterator(cache_resources);
680 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
681 while (p != (CacheInfo *) NULL)
682 {
683 if ((p->type == DiskCache) && (p->file != -1))
cristy508d9312010-02-10 21:10:30 +0000684 break;
cristy3ed852e2009-09-05 21:47:34 +0000685 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
686 }
687 for (q=p; p != (CacheInfo *) NULL; )
688 {
689 if ((p->type == DiskCache) && (p->file != -1) &&
690 (p->timestamp < q->timestamp))
cristy508d9312010-02-10 21:10:30 +0000691 q=p;
cristy3ed852e2009-09-05 21:47:34 +0000692 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
693 }
694 if (q != (CacheInfo *) NULL)
cristy9e116922010-02-12 20:58:13 +0000695 {
696 /*
697 Close least recently used cache.
698 */
699 (void) close(q->file);
700 q->file=(-1);
701 }
cristyf84a1932010-01-03 18:00:18 +0000702 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000703}
704
705static inline MagickSizeType MagickMax(const MagickSizeType x,
706 const MagickSizeType y)
707{
708 if (x > y)
709 return(x);
710 return(y);
711}
712
713static inline MagickSizeType MagickMin(const MagickSizeType x,
714 const MagickSizeType y)
715{
716 if (x < y)
717 return(x);
718 return(y);
719}
720
721static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
722 const MapMode mode)
723{
724 int
725 file;
726
727 /*
728 Open pixel cache on disk.
729 */
cristyf84a1932010-01-03 18:00:18 +0000730 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000731 if (cache_info->file != -1)
732 {
cristyf84a1932010-01-03 18:00:18 +0000733 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000734 return(MagickTrue); /* cache already open */
735 }
736 LimitPixelCacheDescriptors();
737 if (*cache_info->cache_filename == '\0')
738 file=AcquireUniqueFileResource(cache_info->cache_filename);
739 else
740 switch (mode)
741 {
742 case ReadMode:
743 {
744 file=open(cache_info->cache_filename,O_RDONLY | O_BINARY);
745 break;
746 }
747 case WriteMode:
748 {
749 file=open(cache_info->cache_filename,O_WRONLY | O_CREAT | O_BINARY |
750 O_EXCL,S_MODE);
751 if (file == -1)
752 file=open(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
753 break;
754 }
755 case IOMode:
756 default:
757 {
758 file=open(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
759 O_EXCL,S_MODE);
760 if (file == -1)
761 file=open(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
762 break;
763 }
764 }
765 if (file == -1)
766 {
cristyf84a1932010-01-03 18:00:18 +0000767 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000768 return(MagickFalse);
769 }
770 (void) AcquireMagickResource(FileResource,1);
771 cache_info->file=file;
772 cache_info->timestamp=time(0);
cristyf84a1932010-01-03 18:00:18 +0000773 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000774 return(MagickTrue);
775}
776
777static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
778 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000779 unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000780{
781 register MagickOffsetType
782 i;
783
784 ssize_t
785 count;
786
cristy08a88202010-03-04 19:18:05 +0000787 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000788#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000789 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000790 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
791 {
cristyf84a1932010-01-03 18:00:18 +0000792 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000793 return((MagickOffsetType) -1);
794 }
795#endif
796 count=0;
797 for (i=0; i < (MagickOffsetType) length; i+=count)
798 {
799#if !defined(MAGICKCORE_HAVE_PREAD)
800 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
801 (MagickSizeType) SSIZE_MAX));
802#else
803 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
804 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
805#endif
806 if (count > 0)
807 continue;
808 count=0;
809 if (errno != EINTR)
810 {
811 i=(-1);
812 break;
813 }
814 }
815#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000816 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000817#endif
818 return(i);
819}
820
821static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
822 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000823 const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000824{
825 register MagickOffsetType
826 i;
827
828 ssize_t
829 count;
830
cristy08a88202010-03-04 19:18:05 +0000831 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000832#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000833 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000834 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
835 {
cristyf84a1932010-01-03 18:00:18 +0000836 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000837 return((MagickOffsetType) -1);
838 }
839#endif
840 count=0;
841 for (i=0; i < (MagickOffsetType) length; i+=count)
842 {
843#if !defined(MAGICKCORE_HAVE_PWRITE)
844 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
845 (MagickSizeType) SSIZE_MAX));
846#else
847 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
848 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
849#endif
850 if (count > 0)
851 continue;
852 count=0;
853 if (errno != EINTR)
854 {
855 i=(-1);
856 break;
857 }
858 }
859#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000860 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000861#endif
862 return(i);
863}
864
865static MagickBooleanType CloneDiskToDiskPixelCache(CacheInfo *clone_info,
866 CacheInfo *cache_info,ExceptionInfo *exception)
867{
868 MagickOffsetType
869 count,
870 offset,
871 source_offset;
872
873 MagickSizeType
874 length;
875
cristybb503372010-05-27 20:51:26 +0000876 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000877 y;
878
879 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000880 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +0000881
cristybb503372010-05-27 20:51:26 +0000882 size_t
cristy3ed852e2009-09-05 21:47:34 +0000883 columns,
884 rows;
885
886 if (cache_info->debug != MagickFalse)
887 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
888 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
889 {
890 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
891 clone_info->cache_filename);
892 return(MagickFalse);
893 }
894 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
895 {
896 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
897 cache_info->cache_filename);
898 return(MagickFalse);
899 }
cristybb503372010-05-27 20:51:26 +0000900 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
901 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +0000902 if ((clone_info->active_index_channel != MagickFalse) &&
903 (cache_info->active_index_channel != MagickFalse))
904 {
905 register IndexPacket
906 *indexes;
907
908 /*
909 Clone cache indexes.
910 */
911 length=MagickMax(clone_info->columns,cache_info->columns)*
912 sizeof(*indexes);
913 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
914 if (indexes == (IndexPacket *) NULL)
915 {
916 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
917 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
918 return(MagickFalse);
919 }
920 (void) ResetMagickMemory(indexes,0,(size_t) length);
921 length=columns*sizeof(*indexes);
922 source_offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
923 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
924 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
925 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +0000926 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000927 {
928 source_offset-=cache_info->columns*sizeof(*indexes);
929 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
930 length,(unsigned char *) indexes);
931 if ((MagickSizeType) count != length)
932 break;
933 offset-=clone_info->columns*sizeof(*indexes);
934 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
935 (unsigned char *) indexes);
936 if ((MagickSizeType) count != length)
937 break;
938 }
cristybb503372010-05-27 20:51:26 +0000939 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000940 {
941 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
942 ThrowFileException(exception,CacheError,"UnableToCloneCache",
943 cache_info->cache_filename);
944 return(MagickFalse);
945 }
946 if (clone_info->columns > cache_info->columns)
947 {
948 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
949 (void) ResetMagickMemory(indexes,0,(size_t) length);
950 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
951 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +0000952 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000953 {
954 offset-=clone_info->columns*sizeof(*indexes);
955 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
956 length,(unsigned char *) indexes);
957 if ((MagickSizeType) count != length)
958 break;
959 }
cristybb503372010-05-27 20:51:26 +0000960 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000961 {
962 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
963 ThrowFileException(exception,CacheError,"UnableToCloneCache",
964 cache_info->cache_filename);
965 return(MagickFalse);
966 }
967 }
968 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
969 }
970 /*
971 Clone cache pixels.
972 */
973 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
974 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
975 if (pixels == (PixelPacket *) NULL)
976 {
977 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
978 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
979 return(MagickFalse);
980 }
981 (void) ResetMagickMemory(pixels,0,(size_t) length);
982 length=columns*sizeof(*pixels);
983 source_offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
984 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +0000985 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000986 {
987 source_offset-=cache_info->columns*sizeof(*pixels);
988 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
989 length,(unsigned char *) pixels);
990 if ((MagickSizeType) count != length)
991 break;
992 offset-=clone_info->columns*sizeof(*pixels);
993 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
994 (unsigned char *) pixels);
995 if ((MagickSizeType) count != length)
996 break;
997 }
cristybb503372010-05-27 20:51:26 +0000998 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000999 {
1000 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1001 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1002 cache_info->cache_filename);
1003 return(MagickFalse);
1004 }
1005 if (clone_info->columns > cache_info->columns)
1006 {
1007 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
1008 sizeof(*pixels);
1009 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1010 (void) ResetMagickMemory(pixels,0,(size_t) length);
cristybb503372010-05-27 20:51:26 +00001011 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001012 {
1013 offset-=clone_info->columns*sizeof(*pixels);
1014 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1015 (unsigned char *) pixels);
1016 if ((MagickSizeType) count != length)
1017 break;
1018 }
cristybb503372010-05-27 20:51:26 +00001019 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001020 {
1021 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1022 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1023 cache_info->cache_filename);
1024 return(MagickFalse);
1025 }
1026 }
1027 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1028 return(MagickTrue);
1029}
1030
1031static MagickBooleanType CloneDiskToMemoryPixelCache(CacheInfo *clone_info,
1032 CacheInfo *cache_info,ExceptionInfo *exception)
1033{
1034 MagickOffsetType
1035 count,
1036 offset;
1037
1038 MagickSizeType
1039 length;
1040
cristybb503372010-05-27 20:51:26 +00001041 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001042 y;
1043
1044 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001045 *restrict pixels,
1046 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00001047
cristybb503372010-05-27 20:51:26 +00001048 size_t
cristy3ed852e2009-09-05 21:47:34 +00001049 columns,
1050 rows;
1051
1052 if (cache_info->debug != MagickFalse)
1053 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
1054 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
1055 {
1056 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1057 cache_info->cache_filename);
1058 return(MagickFalse);
1059 }
cristybb503372010-05-27 20:51:26 +00001060 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1061 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001062 if ((clone_info->active_index_channel != MagickFalse) &&
1063 (cache_info->active_index_channel != MagickFalse))
1064 {
1065 register IndexPacket
1066 *indexes,
1067 *q;
1068
1069 /*
1070 Clone cache indexes.
1071 */
1072 length=MagickMax(clone_info->columns,cache_info->columns)*
1073 sizeof(*indexes);
1074 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1075 if (indexes == (IndexPacket *) NULL)
1076 {
1077 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1078 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1079 return(MagickFalse);
1080 }
1081 (void) ResetMagickMemory(indexes,0,(size_t) length);
1082 length=columns*sizeof(IndexPacket);
1083 offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
1084 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
1085 q=clone_info->indexes+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001086 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001087 {
1088 offset-=cache_info->columns*sizeof(IndexPacket);
1089 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,
1090 length,(unsigned char *) indexes);
1091 if ((MagickSizeType) count != length)
1092 break;
1093 q-=clone_info->columns;
1094 (void) CopyMagickMemory(q,indexes,(size_t) length);
1095 if ((MagickSizeType) count != length)
1096 break;
1097 }
cristybb503372010-05-27 20:51:26 +00001098 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001099 {
1100 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1101 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1102 cache_info->cache_filename);
1103 return(MagickFalse);
1104 }
1105 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1106 }
1107 /*
1108 Clone cache pixels.
1109 */
1110 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1111 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1112 if (pixels == (PixelPacket *) NULL)
1113 {
1114 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1115 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1116 return(MagickFalse);
1117 }
1118 (void) ResetMagickMemory(pixels,0,(size_t) length);
1119 length=columns*sizeof(*pixels);
1120 offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
1121 q=clone_info->pixels+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001122 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001123 {
1124 offset-=cache_info->columns*sizeof(*pixels);
1125 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,length,
1126 (unsigned char *) pixels);
1127 if ((MagickSizeType) count != length)
1128 break;
1129 q-=clone_info->columns;
1130 (void) CopyMagickMemory(q,pixels,(size_t) length);
1131 }
cristybb503372010-05-27 20:51:26 +00001132 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001133 {
1134 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1135 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1136 cache_info->cache_filename);
1137 return(MagickFalse);
1138 }
1139 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1140 return(MagickTrue);
1141}
1142
1143static MagickBooleanType CloneMemoryToDiskPixelCache(CacheInfo *clone_info,
1144 CacheInfo *cache_info,ExceptionInfo *exception)
1145{
1146 MagickOffsetType
1147 count,
1148 offset;
1149
1150 MagickSizeType
1151 length;
1152
cristybb503372010-05-27 20:51:26 +00001153 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001154 y;
1155
1156 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001157 *restrict p,
1158 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +00001159
cristybb503372010-05-27 20:51:26 +00001160 size_t
cristy3ed852e2009-09-05 21:47:34 +00001161 columns,
1162 rows;
1163
1164 if (cache_info->debug != MagickFalse)
1165 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
1166 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
1167 {
1168 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1169 clone_info->cache_filename);
1170 return(MagickFalse);
1171 }
cristybb503372010-05-27 20:51:26 +00001172 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1173 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001174 if ((clone_info->active_index_channel != MagickFalse) &&
1175 (cache_info->active_index_channel != MagickFalse))
1176 {
1177 register IndexPacket
1178 *p,
1179 *indexes;
1180
1181 /*
1182 Clone cache indexes.
1183 */
1184 length=MagickMax(clone_info->columns,cache_info->columns)*
1185 sizeof(*indexes);
1186 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1187 if (indexes == (IndexPacket *) NULL)
1188 {
1189 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1190 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1191 return(MagickFalse);
1192 }
1193 (void) ResetMagickMemory(indexes,0,(size_t) length);
1194 length=columns*sizeof(*indexes);
1195 p=cache_info->indexes+cache_info->columns*rows;
1196 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1197 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +00001198 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001199 {
1200 p-=cache_info->columns;
1201 (void) CopyMagickMemory(indexes,p,(size_t) length);
1202 offset-=clone_info->columns*sizeof(*indexes);
1203 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1204 (unsigned char *) indexes);
1205 if ((MagickSizeType) count != length)
1206 break;
1207 }
cristybb503372010-05-27 20:51:26 +00001208 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001209 {
1210 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1211 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1212 cache_info->cache_filename);
1213 return(MagickFalse);
1214 }
1215 if (clone_info->columns > cache_info->columns)
1216 {
1217 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
1218 (void) ResetMagickMemory(indexes,0,(size_t) length);
1219 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1220 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +00001221 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001222 {
1223 offset-=clone_info->columns*sizeof(*indexes);
1224 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
1225 length,(unsigned char *) indexes);
1226 if ((MagickSizeType) count != length)
1227 break;
1228 }
cristybb503372010-05-27 20:51:26 +00001229 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001230 {
1231 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1232 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1233 cache_info->cache_filename);
1234 return(MagickFalse);
1235 }
1236 }
1237 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1238 }
1239 /*
1240 Clone cache pixels.
1241 */
1242 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1243 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1244 if (pixels == (PixelPacket *) NULL)
1245 {
1246 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1247 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1248 return(MagickFalse);
1249 }
1250 (void) ResetMagickMemory(pixels,0,(size_t) length);
1251 length=columns*sizeof(*pixels);
1252 p=cache_info->pixels+cache_info->columns*rows;
1253 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +00001254 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001255 {
1256 p-=cache_info->columns;
1257 (void) CopyMagickMemory(pixels,p,(size_t) length);
1258 offset-=clone_info->columns*sizeof(*pixels);
1259 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1260 (unsigned char *) pixels);
1261 if ((MagickSizeType) count != length)
1262 break;
1263 }
cristybb503372010-05-27 20:51:26 +00001264 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001265 {
1266 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1267 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1268 cache_info->cache_filename);
1269 return(MagickFalse);
1270 }
1271 if (clone_info->columns > cache_info->columns)
1272 {
1273 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
1274 sizeof(*pixels);
1275 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1276 (void) ResetMagickMemory(pixels,0,(size_t) length);
cristybb503372010-05-27 20:51:26 +00001277 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001278 {
1279 offset-=clone_info->columns*sizeof(*pixels);
1280 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1281 (unsigned char *) pixels);
1282 if ((MagickSizeType) count != length)
1283 break;
1284 }
cristybb503372010-05-27 20:51:26 +00001285 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001286 {
1287 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1288 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1289 cache_info->cache_filename);
1290 return(MagickFalse);
1291 }
1292 }
1293 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1294 return(MagickTrue);
1295}
1296
1297static MagickBooleanType CloneMemoryToMemoryPixelCache(CacheInfo *clone_info,
1298 CacheInfo *cache_info,ExceptionInfo *magick_unused(exception))
1299{
cristybb503372010-05-27 20:51:26 +00001300 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001301 y;
1302
1303 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001304 *restrict pixels,
1305 *restrict source_pixels;
cristy3ed852e2009-09-05 21:47:34 +00001306
1307 size_t
1308 length;
1309
cristybb503372010-05-27 20:51:26 +00001310 size_t
cristy3ed852e2009-09-05 21:47:34 +00001311 columns,
1312 rows;
1313
1314 if (cache_info->debug != MagickFalse)
1315 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
cristybb503372010-05-27 20:51:26 +00001316 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1317 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001318 if ((clone_info->active_index_channel != MagickFalse) &&
1319 (cache_info->active_index_channel != MagickFalse))
1320 {
1321 register IndexPacket
1322 *indexes,
1323 *source_indexes;
1324
1325 /*
1326 Clone cache indexes.
1327 */
1328 length=columns*sizeof(*indexes);
1329 if (clone_info->columns == cache_info->columns)
1330 (void) CopyMagickMemory(clone_info->indexes,cache_info->indexes,
1331 length*rows);
1332 else
1333 {
1334 source_indexes=cache_info->indexes+cache_info->columns*rows;
1335 indexes=clone_info->indexes+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001336 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001337 {
1338 source_indexes-=cache_info->columns;
1339 indexes-=clone_info->columns;
1340 (void) CopyMagickMemory(indexes,source_indexes,length);
1341 }
1342 if (clone_info->columns > cache_info->columns)
1343 {
1344 length=(clone_info->columns-cache_info->columns)*
1345 sizeof(*indexes);
1346 indexes=clone_info->indexes+clone_info->columns*rows+
1347 cache_info->columns;
cristybb503372010-05-27 20:51:26 +00001348 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001349 {
1350 indexes-=clone_info->columns;
1351 (void) ResetMagickMemory(indexes,0,length);
1352 }
1353 }
1354 }
1355 }
1356 /*
1357 Clone cache pixels.
1358 */
1359 length=columns*sizeof(*pixels);
1360 if (clone_info->columns == cache_info->columns)
1361 (void) CopyMagickMemory(clone_info->pixels,cache_info->pixels,length*rows);
1362 else
1363 {
1364 source_pixels=cache_info->pixels+cache_info->columns*rows;
1365 pixels=clone_info->pixels+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001366 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001367 {
1368 source_pixels-=cache_info->columns;
1369 pixels-=clone_info->columns;
1370 (void) CopyMagickMemory(pixels,source_pixels,length);
1371 }
1372 if (clone_info->columns > cache_info->columns)
1373 {
1374 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1375 pixels=clone_info->pixels+clone_info->columns*rows+
1376 cache_info->columns;
cristybb503372010-05-27 20:51:26 +00001377 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001378 {
1379 pixels-=clone_info->columns;
1380 (void) ResetMagickMemory(pixels,0,length);
1381 }
1382 }
1383 }
1384 return(MagickTrue);
1385}
1386
1387static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1388 CacheInfo *cache_info,ExceptionInfo *exception)
1389{
1390 if ((clone_info->type != DiskCache) && (cache_info->type != DiskCache))
1391 return(CloneMemoryToMemoryPixelCache(clone_info,cache_info,exception));
1392 if ((clone_info->type == DiskCache) && (cache_info->type == DiskCache))
1393 return(CloneDiskToDiskPixelCache(clone_info,cache_info,exception));
1394 if (cache_info->type == DiskCache)
1395 return(CloneDiskToMemoryPixelCache(clone_info,cache_info,exception));
1396 return(CloneMemoryToDiskPixelCache(clone_info,cache_info,exception));
1397}
1398
1399/*
1400%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1401% %
1402% %
1403% %
1404+ C l o n e P i x e l C a c h e M e t h o d s %
1405% %
1406% %
1407% %
1408%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1409%
1410% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1411% another.
1412%
1413% The format of the ClonePixelCacheMethods() method is:
1414%
1415% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1416%
1417% A description of each parameter follows:
1418%
1419% o clone: Specifies a pointer to a Cache structure.
1420%
1421% o cache: the pixel cache.
1422%
1423*/
1424MagickExport void ClonePixelCacheMethods(Cache clone,const Cache cache)
1425{
1426 CacheInfo
1427 *cache_info,
1428 *source_info;
1429
1430 assert(clone != (Cache) NULL);
1431 source_info=(CacheInfo *) clone;
1432 assert(source_info->signature == MagickSignature);
1433 if (source_info->debug != MagickFalse)
1434 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1435 source_info->filename);
1436 assert(cache != (Cache) NULL);
1437 cache_info=(CacheInfo *) cache;
1438 assert(cache_info->signature == MagickSignature);
1439 source_info->methods=cache_info->methods;
1440}
1441
1442/*
1443%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1444% %
1445% %
1446% %
1447+ D e s t r o y I m a g e P i x e l C a c h e %
1448% %
1449% %
1450% %
1451%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1452%
1453% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1454%
1455% The format of the DestroyImagePixelCache() method is:
1456%
1457% void DestroyImagePixelCache(Image *image)
1458%
1459% A description of each parameter follows:
1460%
1461% o image: the image.
1462%
1463*/
1464static void DestroyImagePixelCache(Image *image)
1465{
1466 assert(image != (Image *) NULL);
1467 assert(image->signature == MagickSignature);
1468 if (image->debug != MagickFalse)
1469 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1470 if (image->cache == (void *) NULL)
1471 return;
1472 image->cache=DestroyPixelCache(image->cache);
1473}
1474
1475/*
1476%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1477% %
1478% %
1479% %
1480+ D e s t r o y I m a g e P i x e l s %
1481% %
1482% %
1483% %
1484%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1485%
1486% DestroyImagePixels() deallocates memory associated with the pixel cache.
1487%
1488% The format of the DestroyImagePixels() method is:
1489%
1490% void DestroyImagePixels(Image *image)
1491%
1492% A description of each parameter follows:
1493%
1494% o image: the image.
1495%
1496*/
1497MagickExport void DestroyImagePixels(Image *image)
1498{
1499 CacheInfo
1500 *cache_info;
1501
1502 assert(image != (const Image *) NULL);
1503 assert(image->signature == MagickSignature);
1504 if (image->debug != MagickFalse)
1505 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1506 assert(image->cache != (Cache) NULL);
1507 cache_info=(CacheInfo *) image->cache;
1508 assert(cache_info->signature == MagickSignature);
1509 if (cache_info->methods.destroy_pixel_handler == (DestroyPixelHandler) NULL)
1510 return;
1511 cache_info->methods.destroy_pixel_handler(image);
1512}
1513
1514/*
1515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1516% %
1517% %
1518% %
1519+ D e s t r o y P i x e l C a c h e %
1520% %
1521% %
1522% %
1523%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1524%
1525% DestroyPixelCache() deallocates memory associated with the pixel cache.
1526%
1527% The format of the DestroyPixelCache() method is:
1528%
1529% Cache DestroyPixelCache(Cache cache)
1530%
1531% A description of each parameter follows:
1532%
1533% o cache: the pixel cache.
1534%
1535*/
1536
1537static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1538{
1539 switch (cache_info->type)
1540 {
1541 case MemoryCache:
1542 {
1543 if (cache_info->mapped == MagickFalse)
1544 cache_info->pixels=(PixelPacket *) RelinquishMagickMemory(
1545 cache_info->pixels);
1546 else
1547 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,
1548 (size_t) cache_info->length);
1549 RelinquishMagickResource(MemoryResource,cache_info->length);
1550 break;
1551 }
1552 case MapCache:
1553 {
1554 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,(size_t)
1555 cache_info->length);
1556 RelinquishMagickResource(MapResource,cache_info->length);
1557 }
1558 case DiskCache:
1559 {
1560 if (cache_info->file != -1)
1561 (void) ClosePixelCacheOnDisk(cache_info);
1562 RelinquishMagickResource(DiskResource,cache_info->length);
1563 break;
1564 }
1565 default:
1566 break;
1567 }
1568 cache_info->type=UndefinedCache;
1569 cache_info->mapped=MagickFalse;
1570 cache_info->indexes=(IndexPacket *) NULL;
1571}
1572
1573MagickExport Cache DestroyPixelCache(Cache cache)
1574{
1575 CacheInfo
1576 *cache_info;
1577
cristy3ed852e2009-09-05 21:47:34 +00001578 assert(cache != (Cache) NULL);
1579 cache_info=(CacheInfo *) cache;
1580 assert(cache_info->signature == MagickSignature);
1581 if (cache_info->debug != MagickFalse)
1582 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1583 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001584 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001585 cache_info->reference_count--;
1586 if (cache_info->reference_count != 0)
1587 {
cristyf84a1932010-01-03 18:00:18 +00001588 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001589 return((Cache) NULL);
1590 }
cristyf84a1932010-01-03 18:00:18 +00001591 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001592 if (cache_resources != (SplayTreeInfo *) NULL)
1593 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
cristy5b8de732009-09-10 23:50:40 +00001594 if (cache_info->debug != MagickFalse)
1595 {
1596 char
1597 message[MaxTextExtent];
1598
1599 (void) FormatMagickString(message,MaxTextExtent,"destroy %s",
1600 cache_info->filename);
1601 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1602 }
cristyc2e1bdd2009-09-10 23:43:34 +00001603 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1604 (cache_info->type != DiskCache)))
1605 RelinquishPixelCachePixels(cache_info);
1606 else
1607 {
1608 RelinquishPixelCachePixels(cache_info);
1609 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1610 }
cristy3ed852e2009-09-05 21:47:34 +00001611 *cache_info->cache_filename='\0';
1612 if (cache_info->nexus_info != (NexusInfo **) NULL)
1613 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1614 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001615 if (cache_info->random_info != (RandomInfo *) NULL)
1616 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001617 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1618 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1619 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1620 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001621 cache_info->signature=(~MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001622 cache_info=(CacheInfo *) RelinquishAlignedMemory(cache_info);
1623 cache=(Cache) NULL;
1624 return(cache);
1625}
1626
1627/*
1628%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1629% %
1630% %
1631% %
1632+ D e s t r o y P i x e l C a c h e N e x u s %
1633% %
1634% %
1635% %
1636%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1637%
1638% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1639%
1640% The format of the DestroyPixelCacheNexus() method is:
1641%
1642% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001643% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001644%
1645% A description of each parameter follows:
1646%
1647% o nexus_info: the nexus to destroy.
1648%
1649% o number_threads: the number of nexus threads.
1650%
1651*/
1652
1653static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1654{
1655 if (nexus_info->mapped == MagickFalse)
1656 (void) RelinquishMagickMemory(nexus_info->cache);
1657 else
1658 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1659 nexus_info->cache=(PixelPacket *) NULL;
1660 nexus_info->pixels=(PixelPacket *) NULL;
1661 nexus_info->indexes=(IndexPacket *) NULL;
1662 nexus_info->length=0;
1663 nexus_info->mapped=MagickFalse;
1664}
1665
1666MagickExport NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001667 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001668{
cristybb503372010-05-27 20:51:26 +00001669 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001670 i;
1671
1672 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001673 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001674 {
1675 if (nexus_info[i]->cache != (PixelPacket *) NULL)
1676 RelinquishCacheNexusPixels(nexus_info[i]);
1677 nexus_info[i]->signature=(~MagickSignature);
1678 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
1679 }
1680 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
1681 return(nexus_info);
1682}
1683
1684/*
1685%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1686% %
1687% %
1688% %
cristy3ed852e2009-09-05 21:47:34 +00001689+ 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 %
1690% %
1691% %
1692% %
1693%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1694%
1695% GetAuthenticIndexesFromCache() returns the indexes associated with the last
1696% call to QueueAuthenticPixelsCache() or GetAuthenticPixelsCache().
1697%
1698% The format of the GetAuthenticIndexesFromCache() method is:
1699%
1700% IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1701%
1702% A description of each parameter follows:
1703%
1704% o image: the image.
1705%
1706*/
1707static IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1708{
1709 CacheInfo
1710 *cache_info;
1711
1712 IndexPacket
1713 *indexes;
1714
cristybb503372010-05-27 20:51:26 +00001715 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001716 id;
1717
1718 if (image->debug != MagickFalse)
1719 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1720 cache_info=(CacheInfo *) image->cache;
1721 id=GetOpenMPThreadId();
cristybb503372010-05-27 20:51:26 +00001722 assert(id < (ssize_t) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001723 indexes=GetPixelCacheNexusIndexes(image->cache,cache_info->nexus_info[id]);
1724 return(indexes);
1725}
1726
1727/*
1728%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1729% %
1730% %
1731% %
1732% G e t A u t h e n t i c I n d e x Q u e u e %
1733% %
1734% %
1735% %
1736%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1737%
1738% GetAuthenticIndexQueue() returns the authentic black channel or the colormap
1739% indexes associated with the last call to QueueAuthenticPixels() or
1740% GetVirtualPixels(). NULL is returned if the black channel or colormap
1741% indexes are not available.
1742%
1743% The format of the GetAuthenticIndexQueue() method is:
1744%
1745% IndexPacket *GetAuthenticIndexQueue(const Image *image)
1746%
1747% A description of each parameter follows:
1748%
1749% o image: the image.
1750%
1751*/
1752MagickExport IndexPacket *GetAuthenticIndexQueue(const Image *image)
1753{
1754 CacheInfo
1755 *cache_info;
1756
1757 assert(image != (const Image *) NULL);
1758 assert(image->signature == MagickSignature);
1759 if (image->debug != MagickFalse)
1760 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1761 assert(image->cache != (Cache) NULL);
1762 cache_info=(CacheInfo *) image->cache;
1763 assert(cache_info->signature == MagickSignature);
1764 if (cache_info->methods.get_authentic_indexes_from_handler ==
1765 (GetAuthenticIndexesFromHandler) NULL)
1766 return((IndexPacket *) NULL);
1767 return(cache_info->methods.get_authentic_indexes_from_handler(image));
1768}
1769
1770/*
1771%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1772% %
1773% %
1774% %
1775+ 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 %
1776% %
1777% %
1778% %
1779%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1780%
1781% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1782% disk pixel cache as defined by the geometry parameters. A pointer to the
1783% pixels is returned if the pixels are transferred, otherwise a NULL is
1784% returned.
1785%
1786% The format of the GetAuthenticPixelCacheNexus() method is:
1787%
cristybb503372010-05-27 20:51:26 +00001788% PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1789% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001790% NexusInfo *nexus_info,ExceptionInfo *exception)
1791%
1792% A description of each parameter follows:
1793%
1794% o image: the image.
1795%
1796% o x,y,columns,rows: These values define the perimeter of a region of
1797% pixels.
1798%
1799% o nexus_info: the cache nexus to return.
1800%
1801% o exception: return any errors or warnings in this structure.
1802%
1803*/
1804
1805static inline MagickBooleanType IsNexusInCore(const CacheInfo *cache_info,
1806 NexusInfo *nexus_info)
1807{
1808 MagickOffsetType
1809 offset;
1810
cristy73724512010-04-12 14:43:14 +00001811 if (cache_info->type == PingCache)
1812 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001813 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1814 nexus_info->region.x;
1815 if (nexus_info->pixels != (cache_info->pixels+offset))
1816 return(MagickFalse);
1817 return(MagickTrue);
1818}
1819
cristybb503372010-05-27 20:51:26 +00001820MagickExport PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1821 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001822 NexusInfo *nexus_info,ExceptionInfo *exception)
1823{
1824 CacheInfo
1825 *cache_info;
1826
1827 PixelPacket
1828 *pixels;
1829
1830 /*
1831 Transfer pixels from the cache.
1832 */
1833 assert(image != (Image *) NULL);
1834 assert(image->signature == MagickSignature);
1835 if (image->debug != MagickFalse)
1836 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1837 pixels=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
1838 if (pixels == (PixelPacket *) NULL)
1839 return((PixelPacket *) NULL);
1840 cache_info=(CacheInfo *) image->cache;
1841 assert(cache_info->signature == MagickSignature);
1842 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
1843 return(pixels);
1844 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1845 return((PixelPacket *) NULL);
1846 if (cache_info->active_index_channel != MagickFalse)
1847 if (ReadPixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse)
1848 return((PixelPacket *) NULL);
1849 return(pixels);
1850}
1851
1852/*
1853%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1854% %
1855% %
1856% %
1857+ 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 %
1858% %
1859% %
1860% %
1861%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1862%
1863% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1864% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1865%
1866% The format of the GetAuthenticPixelsFromCache() method is:
1867%
1868% PixelPacket *GetAuthenticPixelsFromCache(const Image image)
1869%
1870% A description of each parameter follows:
1871%
1872% o image: the image.
1873%
1874*/
1875static PixelPacket *GetAuthenticPixelsFromCache(const Image *image)
1876{
1877 CacheInfo
1878 *cache_info;
1879
cristybb503372010-05-27 20:51:26 +00001880 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001881 id;
1882
1883 PixelPacket
1884 *pixels;
1885
1886 if (image->debug != MagickFalse)
1887 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1888 cache_info=(CacheInfo *) image->cache;
1889 id=GetOpenMPThreadId();
cristybb503372010-05-27 20:51:26 +00001890 assert(id < (ssize_t) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001891 pixels=GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]);
1892 return(pixels);
1893}
1894
1895/*
1896%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1897% %
1898% %
1899% %
1900% G e t A u t h e n t i c P i x e l Q u e u e %
1901% %
1902% %
1903% %
1904%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1905%
1906% GetAuthenticPixelQueue() returns the authentic pixels associated with the
1907% last call to QueueAuthenticPixels() or GetAuthenticPixels().
1908%
1909% The format of the GetAuthenticPixelQueue() method is:
1910%
1911% PixelPacket *GetAuthenticPixelQueue(const Image image)
1912%
1913% A description of each parameter follows:
1914%
1915% o image: the image.
1916%
1917*/
1918MagickExport PixelPacket *GetAuthenticPixelQueue(const Image *image)
1919{
1920 CacheInfo
1921 *cache_info;
1922
1923 assert(image != (const Image *) NULL);
1924 assert(image->signature == MagickSignature);
1925 if (image->debug != MagickFalse)
1926 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1927 assert(image->cache != (Cache) NULL);
1928 cache_info=(CacheInfo *) image->cache;
1929 assert(cache_info->signature == MagickSignature);
1930 if (cache_info->methods.get_authentic_pixels_from_handler ==
1931 (GetAuthenticPixelsFromHandler) NULL)
1932 return((PixelPacket *) NULL);
1933 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1934}
1935
1936/*
1937%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1938% %
1939% %
1940% %
1941% G e t A u t h e n t i c P i x e l s %
1942% %
1943% %
1944% %
1945%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1946%
1947% GetAuthenticPixels() obtains a pixel region for read/write access. If the
1948% region is successfully accessed, a pointer to a PixelPacket array
1949% representing the region is returned, otherwise NULL is returned.
1950%
1951% The returned pointer may point to a temporary working copy of the pixels
1952% or it may point to the original pixels in memory. Performance is maximized
1953% if the selected region is part of one row, or one or more full rows, since
1954% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001955% if the image is in memory, or in a memory-mapped file. The returned pointer
1956% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001957%
1958% Pixels accessed via the returned pointer represent a simple array of type
1959% PixelPacket. If the image type is CMYK or if the storage class is
1960% PseduoClass, call GetAuthenticIndexQueue() after invoking
1961% GetAuthenticPixels() to obtain the black color component or colormap indexes
1962% (of type IndexPacket) corresponding to the region. Once the PixelPacket
1963% (and/or IndexPacket) array has been updated, the changes must be saved back
1964% to the underlying image using SyncAuthenticPixels() or they may be lost.
1965%
1966% The format of the GetAuthenticPixels() method is:
1967%
cristy5f959472010-05-27 22:19:46 +00001968% PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1969% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001970% ExceptionInfo *exception)
1971%
1972% A description of each parameter follows:
1973%
1974% o image: the image.
1975%
1976% o x,y,columns,rows: These values define the perimeter of a region of
1977% pixels.
1978%
1979% o exception: return any errors or warnings in this structure.
1980%
1981*/
cristybb503372010-05-27 20:51:26 +00001982MagickExport PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1983 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001984 ExceptionInfo *exception)
1985{
1986 CacheInfo
1987 *cache_info;
1988
1989 PixelPacket
1990 *pixels;
1991
1992 assert(image != (Image *) NULL);
1993 assert(image->signature == MagickSignature);
1994 if (image->debug != MagickFalse)
1995 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1996 assert(image->cache != (Cache) NULL);
1997 cache_info=(CacheInfo *) image->cache;
1998 assert(cache_info->signature == MagickSignature);
1999 if (cache_info->methods.get_authentic_pixels_handler ==
2000 (GetAuthenticPixelsHandler) NULL)
2001 return((PixelPacket *) NULL);
2002 pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
2003 rows,exception);
2004 return(pixels);
2005}
2006
2007/*
2008%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2009% %
2010% %
2011% %
2012+ G e t A u t h e n t i c P i x e l s C a c h e %
2013% %
2014% %
2015% %
2016%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2017%
2018% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
2019% as defined by the geometry parameters. A pointer to the pixels is returned
2020% if the pixels are transferred, otherwise a NULL is returned.
2021%
2022% The format of the GetAuthenticPixelsCache() method is:
2023%
cristybb503372010-05-27 20:51:26 +00002024% PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
2025% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00002026% ExceptionInfo *exception)
2027%
2028% A description of each parameter follows:
2029%
2030% o image: the image.
2031%
2032% o x,y,columns,rows: These values define the perimeter of a region of
2033% pixels.
2034%
2035% o exception: return any errors or warnings in this structure.
2036%
2037*/
cristybb503372010-05-27 20:51:26 +00002038static PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
2039 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00002040 ExceptionInfo *exception)
2041{
2042 CacheInfo
2043 *cache_info;
2044
cristybb503372010-05-27 20:51:26 +00002045 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002046 id;
2047
2048 PixelPacket
2049 *pixels;
2050
2051 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
2052 if (cache_info == (Cache) NULL)
2053 return((PixelPacket *) NULL);
2054 id=GetOpenMPThreadId();
cristybb503372010-05-27 20:51:26 +00002055 assert(id < (ssize_t) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00002056 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
2057 cache_info->nexus_info[id],exception);
2058 return(pixels);
2059}
2060
2061/*
2062%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2063% %
2064% %
2065% %
2066+ G e t I m a g e E x t e n t %
2067% %
2068% %
2069% %
2070%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2071%
2072% GetImageExtent() returns the extent of the pixels associated with the
2073% last call to QueueAuthenticPixels() or GetAuthenticPixels().
2074%
2075% The format of the GetImageExtent() method is:
2076%
2077% MagickSizeType GetImageExtent(const Image *image)
2078%
2079% A description of each parameter follows:
2080%
2081% o image: the image.
2082%
2083*/
2084MagickExport MagickSizeType GetImageExtent(const Image *image)
2085{
2086 CacheInfo
2087 *cache_info;
2088
cristybb503372010-05-27 20:51:26 +00002089 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002090 id;
2091
2092 MagickSizeType
2093 extent;
2094
2095 assert(image != (Image *) NULL);
2096 assert(image->signature == MagickSignature);
2097 if (image->debug != MagickFalse)
2098 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2099 assert(image->cache != (Cache) NULL);
2100 cache_info=(CacheInfo *) image->cache;
2101 assert(cache_info->signature == MagickSignature);
2102 id=GetOpenMPThreadId();
cristybb503372010-05-27 20:51:26 +00002103 assert(id < (ssize_t) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00002104 extent=GetPixelCacheNexusExtent(image->cache,cache_info->nexus_info[id]);
2105 return(extent);
2106}
2107
2108/*
2109%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2110% %
2111% %
2112% %
2113+ G e t I m a g e P i x e l C a c h e %
2114% %
2115% %
2116% %
2117%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2118%
2119% GetImagePixelCache() ensures that there is only a single reference to the
2120% pixel cache to be modified, updating the provided cache pointer to point to
2121% a clone of the original pixel cache if necessary.
2122%
2123% The format of the GetImagePixelCache method is:
2124%
2125% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2126% ExceptionInfo *exception)
2127%
2128% A description of each parameter follows:
2129%
2130% o image: the image.
2131%
2132% o clone: any value other than MagickFalse clones the cache pixels.
2133%
2134% o exception: return any errors or warnings in this structure.
2135%
2136*/
2137
2138static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
2139{
2140 CacheInfo
2141 *cache_info;
2142
2143 /*
2144 Does the image match the pixel cache morphology?
2145 */
2146 cache_info=(CacheInfo *) image->cache;
2147 if ((image->storage_class != cache_info->storage_class) ||
2148 (image->colorspace != cache_info->colorspace) ||
2149 (image->columns != cache_info->columns) ||
2150 (image->rows != cache_info->rows) ||
2151 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2152 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2153 return(MagickFalse);
2154 return(MagickTrue);
2155}
2156
2157MagickExport Cache GetImagePixelCache(Image *image,
2158 const MagickBooleanType clone,ExceptionInfo *exception)
2159{
2160 CacheInfo
2161 *cache_info;
2162
cristy3ed852e2009-09-05 21:47:34 +00002163 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00002164 destroy,
cristy3ed852e2009-09-05 21:47:34 +00002165 status;
2166
cristy50a10922010-02-15 18:35:25 +00002167 static MagickSizeType
2168 time_limit = 0;
2169
cristy3ed852e2009-09-05 21:47:34 +00002170 if (image->debug != MagickFalse)
2171 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy50a10922010-02-15 18:35:25 +00002172 if (time_limit == 0)
2173 time_limit=GetMagickResourceLimit(TimeResource);
2174 if (time_limit != MagickResourceInfinity)
2175 {
2176 static time_t
2177 cache_timer = 0;
2178
2179 if (cache_timer == 0)
2180 cache_timer=time((time_t *) NULL);
2181 if ((MagickSizeType) (time((time_t *) NULL)-cache_timer) >= time_limit)
2182 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
2183 }
cristyc4f9f132010-03-04 18:50:01 +00002184 status=MagickTrue;
2185 LockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002186 assert(image->cache != (Cache) NULL);
2187 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002188 destroy=MagickFalse;
cristy01b7eb02009-09-10 23:10:14 +00002189 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002190 {
cristyaaa0cb62010-02-15 17:47:27 +00002191 LockSemaphoreInfo(cache_info->semaphore);
2192 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002193 {
cristyaaa0cb62010-02-15 17:47:27 +00002194 Image
2195 clone_image;
2196
2197 CacheInfo
2198 *clone_info;
2199
2200 /*
2201 Clone pixel cache.
2202 */
2203 clone_image=(*image);
2204 clone_image.cache=ClonePixelCache(cache_info);
2205 clone_info=(CacheInfo *) clone_image.cache;
2206 status=ClonePixelCacheNexus(cache_info,clone_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002207 if (status != MagickFalse)
2208 {
cristyaaa0cb62010-02-15 17:47:27 +00002209 status=OpenPixelCache(&clone_image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00002210 if (status != MagickFalse)
2211 {
cristyaaa0cb62010-02-15 17:47:27 +00002212 if (clone != MagickFalse)
2213 status=ClonePixelCachePixels(clone_info,cache_info,
2214 exception);
2215 if (status != MagickFalse)
2216 {
2217 destroy=MagickTrue;
2218 image->cache=clone_image.cache;
2219 }
cristy3ed852e2009-09-05 21:47:34 +00002220 }
2221 }
2222 }
cristyaaa0cb62010-02-15 17:47:27 +00002223 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002224 }
cristy4320e0e2009-09-10 15:00:08 +00002225 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002226 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002227 if (status != MagickFalse)
2228 {
2229 /*
2230 Ensure the image matches the pixel cache morphology.
2231 */
2232 image->taint=MagickTrue;
2233 image->type=UndefinedType;
cristydd438462010-05-06 13:44:04 +00002234 if (image->colorspace == GRAYColorspace)
2235 image->colorspace=RGBColorspace;
cristy3ed852e2009-09-05 21:47:34 +00002236 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2237 status=OpenPixelCache(image,IOMode,exception);
2238 }
cristyf84a1932010-01-03 18:00:18 +00002239 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002240 if (status == MagickFalse)
2241 return((Cache) NULL);
2242 return(image->cache);
2243}
2244
2245/*
2246%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2247% %
2248% %
2249% %
2250% G e t O n e A u t h e n t i c P i x e l %
2251% %
2252% %
2253% %
2254%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2255%
2256% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2257% location. The image background color is returned if an error occurs.
2258%
2259% The format of the GetOneAuthenticPixel() method is:
2260%
cristybb503372010-05-27 20:51:26 +00002261% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2262% const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002263%
2264% A description of each parameter follows:
2265%
2266% o image: the image.
2267%
2268% o x,y: These values define the location of the pixel to return.
2269%
2270% o pixel: return a pixel at the specified (x,y) location.
2271%
2272% o exception: return any errors or warnings in this structure.
2273%
2274*/
cristyacbbb7c2010-06-30 18:56:48 +00002275MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2276 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002277{
2278 CacheInfo
2279 *cache_info;
2280
2281 GetOneAuthenticPixelFromHandler
2282 get_one_authentic_pixel_from_handler;
2283
2284 MagickBooleanType
2285 status;
2286
2287 assert(image != (Image *) NULL);
2288 assert(image->signature == MagickSignature);
2289 if (image->debug != MagickFalse)
2290 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2291 assert(image->cache != (Cache) NULL);
2292 cache_info=(CacheInfo *) image->cache;
2293 assert(cache_info->signature == MagickSignature);
2294 *pixel=image->background_color;
2295 get_one_authentic_pixel_from_handler=
2296 cache_info->methods.get_one_authentic_pixel_from_handler;
2297 if (get_one_authentic_pixel_from_handler ==
2298 (GetOneAuthenticPixelFromHandler) NULL)
2299 return(MagickFalse);
2300 status=cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2301 pixel,exception);
2302 return(status);
2303}
2304
2305/*
2306%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2307% %
2308% %
2309% %
2310+ 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 %
2311% %
2312% %
2313% %
2314%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2315%
2316% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2317% location. The image background color is returned if an error occurs.
2318%
2319% The format of the GetOneAuthenticPixelFromCache() method is:
2320%
2321% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy5f959472010-05-27 22:19:46 +00002322% const ssize_t x,const ssize_t y,PixelPacket *pixel,
2323% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002324%
2325% A description of each parameter follows:
2326%
2327% o image: the image.
2328%
2329% o x,y: These values define the location of the pixel to return.
2330%
2331% o pixel: return a pixel at the specified (x,y) location.
2332%
2333% o exception: return any errors or warnings in this structure.
2334%
2335*/
2336static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristybb503372010-05-27 20:51:26 +00002337 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002338{
2339 PixelPacket
2340 *pixels;
2341
2342 if (image->debug != MagickFalse)
2343 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2344 *pixel=image->background_color;
2345 pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2346 if (pixels == (PixelPacket *) NULL)
2347 return(MagickFalse);
2348 *pixel=(*pixels);
2349 return(MagickTrue);
2350}
2351
2352/*
2353%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2354% %
2355% %
2356% %
2357% G e t O n e V i r t u a l M a g i c k P i x e l %
2358% %
2359% %
2360% %
2361%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2362%
2363% GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2364% location. The image background color is returned if an error occurs. If
2365% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2366%
2367% The format of the GetOneVirtualMagickPixel() method is:
2368%
2369% MagickBooleanType GetOneVirtualMagickPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002370% const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
cristy3ed852e2009-09-05 21:47:34 +00002371% ExceptionInfo exception)
2372%
2373% A description of each parameter follows:
2374%
2375% o image: the image.
2376%
2377% o x,y: these values define the location of the pixel to return.
2378%
2379% o pixel: return a pixel at the specified (x,y) location.
2380%
2381% o exception: return any errors or warnings in this structure.
2382%
2383*/
2384MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
cristyacbbb7c2010-06-30 18:56:48 +00002385 const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
2386 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002387{
2388 CacheInfo
2389 *cache_info;
2390
2391 register const IndexPacket
2392 *indexes;
2393
2394 register const PixelPacket
2395 *p;
2396
2397 assert(image != (const Image *) NULL);
2398 assert(image->signature == MagickSignature);
2399 assert(image->cache != (Cache) NULL);
2400 cache_info=(CacheInfo *) image->cache;
2401 assert(cache_info->signature == MagickSignature);
2402 GetMagickPixelPacket(image,pixel);
2403 p=GetVirtualPixelCache(image,GetPixelCacheVirtualMethod(image),x,y,1,1,
2404 exception);
2405 if (p == (const PixelPacket *) NULL)
2406 return(MagickFalse);
2407 indexes=GetVirtualIndexQueue(image);
2408 SetMagickPixelPacket(image,p,indexes,pixel);
2409 return(MagickTrue);
2410}
2411
2412/*
2413%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2414% %
2415% %
2416% %
2417% G e t O n e V i r t u a l M e t h o d P i x e l %
2418% %
2419% %
2420% %
2421%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2422%
2423% GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2424% location as defined by specified pixel method. The image background color
2425% is returned if an error occurs. If you plan to modify the pixel, use
2426% GetOneAuthenticPixel() instead.
2427%
2428% The format of the GetOneVirtualMethodPixel() method is:
2429%
2430% MagickBooleanType GetOneVirtualMethodPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002431% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2432% const ssize_t y,Pixelpacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002433%
2434% A description of each parameter follows:
2435%
2436% o image: the image.
2437%
2438% o virtual_pixel_method: the virtual pixel method.
2439%
2440% o x,y: These values define the location of the pixel to return.
2441%
2442% o pixel: return a pixel at the specified (x,y) location.
2443%
2444% o exception: return any errors or warnings in this structure.
2445%
2446*/
2447MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002448 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002449 PixelPacket *pixel,ExceptionInfo *exception)
2450{
2451 GetOneVirtualPixelFromHandler
2452 get_one_virtual_pixel_from_handler;
2453
2454 CacheInfo
2455 *cache_info;
2456
2457 MagickBooleanType
2458 status;
2459
2460 assert(image != (const Image *) NULL);
2461 assert(image->signature == MagickSignature);
2462 assert(image->cache != (Cache) NULL);
2463 cache_info=(CacheInfo *) image->cache;
2464 assert(cache_info->signature == MagickSignature);
2465 *pixel=image->background_color;
2466 get_one_virtual_pixel_from_handler=
2467 cache_info->methods.get_one_virtual_pixel_from_handler;
2468 if (get_one_virtual_pixel_from_handler ==
2469 (GetOneVirtualPixelFromHandler) NULL)
2470 return(MagickFalse);
2471 status=get_one_virtual_pixel_from_handler(image,virtual_pixel_method,x,y,
2472 pixel,exception);
2473 return(status);
2474}
2475
2476/*
2477%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2478% %
2479% %
2480% %
2481% G e t O n e V i r t u a l P i x e l %
2482% %
2483% %
2484% %
2485%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2486%
2487% GetOneVirtualPixel() returns a single virtual pixel at the specified
2488% (x,y) location. The image background color is returned if an error occurs.
2489% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2490%
2491% The format of the GetOneVirtualPixel() method is:
2492%
cristybb503372010-05-27 20:51:26 +00002493% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2494% const ssize_t y,PixelPacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002495%
2496% A description of each parameter follows:
2497%
2498% o image: the image.
2499%
2500% o x,y: These values define the location of the pixel to return.
2501%
2502% o pixel: return a pixel at the specified (x,y) location.
2503%
2504% o exception: return any errors or warnings in this structure.
2505%
2506*/
2507MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002508 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002509{
2510 GetOneVirtualPixelFromHandler
2511 get_one_virtual_pixel_from_handler;
2512
2513 CacheInfo
2514 *cache_info;
2515
2516 MagickBooleanType
2517 status;
2518
2519 assert(image != (const Image *) NULL);
2520 assert(image->signature == MagickSignature);
2521 assert(image->cache != (Cache) NULL);
2522 cache_info=(CacheInfo *) image->cache;
2523 assert(cache_info->signature == MagickSignature);
2524 *pixel=image->background_color;
2525 get_one_virtual_pixel_from_handler=
2526 cache_info->methods.get_one_virtual_pixel_from_handler;
2527 if (get_one_virtual_pixel_from_handler ==
2528 (GetOneVirtualPixelFromHandler) NULL)
2529 return(MagickFalse);
2530 status=get_one_virtual_pixel_from_handler(image,GetPixelCacheVirtualMethod(
2531 image),x,y,pixel,exception);
2532 return(status);
2533}
2534
2535/*
2536%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2537% %
2538% %
2539% %
2540+ 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 %
2541% %
2542% %
2543% %
2544%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2545%
2546% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2547% specified (x,y) location. The image background color is returned if an
2548% error occurs.
2549%
2550% The format of the GetOneVirtualPixelFromCache() method is:
2551%
2552% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristybb503372010-05-27 20:51:26 +00002553% const VirtualPixelPacket method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002554% PixelPacket *pixel,ExceptionInfo *exception)
2555%
2556% A description of each parameter follows:
2557%
2558% o image: the image.
2559%
2560% o virtual_pixel_method: the virtual pixel method.
2561%
2562% o x,y: These values define the location of the pixel to return.
2563%
2564% o pixel: return a pixel at the specified (x,y) location.
2565%
2566% o exception: return any errors or warnings in this structure.
2567%
2568*/
2569static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002570 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002571 PixelPacket *pixel,ExceptionInfo *exception)
2572{
2573 const PixelPacket
2574 *pixels;
2575
2576 *pixel=image->background_color;
2577 pixels=GetVirtualPixelCache(image,virtual_pixel_method,x,y,1UL,1UL,exception);
2578 if (pixels == (const PixelPacket *) NULL)
2579 return(MagickFalse);
2580 *pixel=(*pixels);
2581 return(MagickTrue);
2582}
2583
2584/*
2585%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2586% %
2587% %
2588% %
2589+ G e t P i x e l C a c h e C o l o r s p a c e %
2590% %
2591% %
2592% %
2593%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2594%
2595% GetPixelCacheColorspace() returns the class type of the pixel cache.
2596%
2597% The format of the GetPixelCacheColorspace() method is:
2598%
2599% Colorspace GetPixelCacheColorspace(Cache cache)
2600%
2601% A description of each parameter follows:
2602%
2603% o cache: the pixel cache.
2604%
2605*/
2606MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
2607{
2608 CacheInfo
2609 *cache_info;
2610
2611 assert(cache != (Cache) NULL);
2612 cache_info=(CacheInfo *) cache;
2613 assert(cache_info->signature == MagickSignature);
2614 if (cache_info->debug != MagickFalse)
2615 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2616 cache_info->filename);
2617 return(cache_info->colorspace);
2618}
2619
2620/*
2621%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2622% %
2623% %
2624% %
2625+ G e t P i x e l C a c h e M e t h o d s %
2626% %
2627% %
2628% %
2629%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2630%
2631% GetPixelCacheMethods() initializes the CacheMethods structure.
2632%
2633% The format of the GetPixelCacheMethods() method is:
2634%
2635% void GetPixelCacheMethods(CacheMethods *cache_methods)
2636%
2637% A description of each parameter follows:
2638%
2639% o cache_methods: Specifies a pointer to a CacheMethods structure.
2640%
2641*/
2642MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
2643{
2644 assert(cache_methods != (CacheMethods *) NULL);
2645 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2646 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2647 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2648 cache_methods->get_virtual_indexes_from_handler=GetVirtualIndexesFromCache;
2649 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2650 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2651 cache_methods->get_authentic_indexes_from_handler=
2652 GetAuthenticIndexesFromCache;
2653 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2654 cache_methods->get_one_authentic_pixel_from_handler=
2655 GetOneAuthenticPixelFromCache;
2656 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2657 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2658 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2659}
2660
2661/*
2662%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2663% %
2664% %
2665% %
2666+ G e t P i x e l C a c h e N e x u s E x t e n t %
2667% %
2668% %
2669% %
2670%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2671%
2672% GetPixelCacheNexusExtent() returns the extent of the pixels associated with
2673% the last call to SetPixelCacheNexusPixels() or GetPixelCacheNexusPixels().
2674%
2675% The format of the GetPixelCacheNexusExtent() method is:
2676%
2677% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2678% NexusInfo *nexus_info)
2679%
2680% A description of each parameter follows:
2681%
2682% o nexus_info: the nexus info.
2683%
2684*/
2685MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2686 NexusInfo *nexus_info)
2687{
2688 CacheInfo
2689 *cache_info;
2690
2691 MagickSizeType
2692 extent;
2693
2694 if (cache == (Cache) NULL)
2695 return(0);
2696 cache_info=(CacheInfo *) cache;
2697 assert(cache_info->signature == MagickSignature);
2698 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2699 if (extent == 0)
2700 return((MagickSizeType) cache_info->columns*cache_info->rows);
2701 return(extent);
2702}
2703
2704/*
2705%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2706% %
2707% %
2708% %
2709+ 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 %
2710% %
2711% %
2712% %
2713%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2714%
2715% GetPixelCacheNexusIndexes() returns the indexes associated with the
2716% specified cache nexus.
2717%
2718% The format of the GetPixelCacheNexusIndexes() method is:
2719%
2720% IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2721% NexusInfo *nexus_info)
2722%
2723% A description of each parameter follows:
2724%
2725% o cache: the pixel cache.
2726%
2727% o nexus_info: the cache nexus to return the colormap indexes.
2728%
2729*/
2730MagickExport IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2731 NexusInfo *nexus_info)
2732{
2733 CacheInfo
2734 *cache_info;
2735
2736 if (cache == (Cache) NULL)
2737 return((IndexPacket *) NULL);
2738 cache_info=(CacheInfo *) cache;
2739 assert(cache_info->signature == MagickSignature);
2740 if (cache_info->storage_class == UndefinedClass)
2741 return((IndexPacket *) NULL);
2742 return(nexus_info->indexes);
2743}
2744
2745/*
2746%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2747% %
2748% %
2749% %
2750+ G e t P i x e l C a c h e N e x u s P i x e l s %
2751% %
2752% %
2753% %
2754%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2755%
2756% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2757% cache nexus.
2758%
2759% The format of the GetPixelCacheNexusPixels() method is:
2760%
2761% PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2762% NexusInfo *nexus_info)
2763%
2764% A description of each parameter follows:
2765%
2766% o cache: the pixel cache.
2767%
2768% o nexus_info: the cache nexus to return the pixels.
2769%
2770*/
2771MagickExport PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2772 NexusInfo *nexus_info)
2773{
2774 CacheInfo
2775 *cache_info;
2776
2777 if (cache == (Cache) NULL)
2778 return((PixelPacket *) NULL);
2779 cache_info=(CacheInfo *) cache;
2780 assert(cache_info->signature == MagickSignature);
2781 if (cache_info->debug != MagickFalse)
2782 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2783 cache_info->filename);
2784 if (cache_info->storage_class == UndefinedClass)
2785 return((PixelPacket *) NULL);
2786 return(nexus_info->pixels);
2787}
2788
2789/*
2790%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2791% %
2792% %
2793% %
cristy056ba772010-01-02 23:33:54 +00002794+ G e t P i x e l C a c h e P i x e l s %
2795% %
2796% %
2797% %
2798%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2799%
2800% GetPixelCachePixels() returns the pixels associated with the specified image.
2801%
2802% The format of the GetPixelCachePixels() method is:
2803%
cristyf84a1932010-01-03 18:00:18 +00002804% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2805% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002806%
2807% A description of each parameter follows:
2808%
2809% o image: the image.
2810%
2811% o length: the pixel cache length.
2812%
cristyf84a1932010-01-03 18:00:18 +00002813% o exception: return any errors or warnings in this structure.
2814%
cristy056ba772010-01-02 23:33:54 +00002815*/
cristyf84a1932010-01-03 18:00:18 +00002816MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2817 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002818{
2819 CacheInfo
2820 *cache_info;
2821
2822 assert(image != (const Image *) NULL);
2823 assert(image->signature == MagickSignature);
2824 if (image->debug != MagickFalse)
2825 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2826 assert(image->cache != (Cache) NULL);
cristyc4c8d132010-01-07 01:58:38 +00002827 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
cristy056ba772010-01-02 23:33:54 +00002828 assert(cache_info->signature == MagickSignature);
2829 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002830 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002831 return((void *) NULL);
2832 *length=cache_info->length;
2833 return((void *) cache_info->pixels);
2834}
2835
2836/*
2837%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2838% %
2839% %
2840% %
cristyb32b90a2009-09-07 21:45:48 +00002841+ 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 +00002842% %
2843% %
2844% %
2845%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2846%
2847% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2848%
2849% The format of the GetPixelCacheStorageClass() method is:
2850%
2851% ClassType GetPixelCacheStorageClass(Cache cache)
2852%
2853% A description of each parameter follows:
2854%
2855% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2856%
2857% o cache: the pixel cache.
2858%
2859*/
2860MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
2861{
2862 CacheInfo
2863 *cache_info;
2864
2865 assert(cache != (Cache) NULL);
2866 cache_info=(CacheInfo *) cache;
2867 assert(cache_info->signature == MagickSignature);
2868 if (cache_info->debug != MagickFalse)
2869 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2870 cache_info->filename);
2871 return(cache_info->storage_class);
2872}
2873
2874/*
2875%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2876% %
2877% %
2878% %
cristyb32b90a2009-09-07 21:45:48 +00002879+ G e t P i x e l C a c h e T i l e S i z e %
2880% %
2881% %
2882% %
2883%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2884%
2885% GetPixelCacheTileSize() returns the pixel cache tile size.
2886%
2887% The format of the GetPixelCacheTileSize() method is:
2888%
cristybb503372010-05-27 20:51:26 +00002889% void GetPixelCacheTileSize(const Image *image,size_t *width,
2890% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002891%
2892% A description of each parameter follows:
2893%
2894% o image: the image.
2895%
2896% o width: the optimize cache tile width in pixels.
2897%
2898% o height: the optimize cache tile height in pixels.
2899%
2900*/
cristybb503372010-05-27 20:51:26 +00002901MagickExport void GetPixelCacheTileSize(const Image *image,size_t *width,
2902 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002903{
2904 CacheInfo
2905 *cache_info;
2906
2907 assert(image != (Image *) NULL);
2908 assert(image->signature == MagickSignature);
2909 if (image->debug != MagickFalse)
2910 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2911 assert(image->cache != (Cache) NULL);
2912 cache_info=(CacheInfo *) image->cache;
2913 assert(cache_info->signature == MagickSignature);
2914 *width=2048UL/sizeof(PixelPacket);
2915 if (GetPixelCacheType(image) == DiskCache)
cristydaa97692009-09-13 02:10:35 +00002916 *width=8192UL/sizeof(PixelPacket);
cristyb32b90a2009-09-07 21:45:48 +00002917 *height=(*width);
2918}
2919
2920/*
2921%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2922% %
2923% %
2924% %
2925+ G e t P i x e l C a c h e T y p e %
2926% %
2927% %
2928% %
2929%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2930%
2931% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2932%
2933% The format of the GetPixelCacheType() method is:
2934%
2935% CacheType GetPixelCacheType(const Image *image)
2936%
2937% A description of each parameter follows:
2938%
2939% o image: the image.
2940%
2941*/
2942MagickExport CacheType GetPixelCacheType(const Image *image)
2943{
2944 CacheInfo
2945 *cache_info;
2946
2947 assert(image != (Image *) NULL);
2948 assert(image->signature == MagickSignature);
2949 if (image->debug != MagickFalse)
2950 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2951 assert(image->cache != (Cache) NULL);
2952 cache_info=(CacheInfo *) image->cache;
2953 assert(cache_info->signature == MagickSignature);
2954 return(cache_info->type);
2955}
2956
2957/*
2958%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2959% %
2960% %
2961% %
cristy3ed852e2009-09-05 21:47:34 +00002962+ 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 %
2963% %
2964% %
2965% %
2966%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2967%
2968% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2969% pixel cache. A virtual pixel is any pixel access that is outside the
2970% boundaries of the image cache.
2971%
2972% The format of the GetPixelCacheVirtualMethod() method is:
2973%
2974% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2975%
2976% A description of each parameter follows:
2977%
2978% o image: the image.
2979%
2980*/
2981MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2982{
2983 CacheInfo
2984 *cache_info;
2985
2986 assert(image != (Image *) NULL);
2987 assert(image->signature == MagickSignature);
2988 if (image->debug != MagickFalse)
2989 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2990 assert(image->cache != (Cache) NULL);
2991 cache_info=(CacheInfo *) image->cache;
2992 assert(cache_info->signature == MagickSignature);
2993 return(cache_info->virtual_pixel_method);
2994}
2995
2996/*
2997%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2998% %
2999% %
3000% %
3001+ 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 %
3002% %
3003% %
3004% %
3005%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3006%
3007% GetVirtualIndexesFromCache() returns the indexes associated with the last
3008% call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3009%
3010% The format of the GetVirtualIndexesFromCache() method is:
3011%
3012% IndexPacket *GetVirtualIndexesFromCache(const Image *image)
3013%
3014% A description of each parameter follows:
3015%
3016% o image: the image.
3017%
3018*/
3019static const IndexPacket *GetVirtualIndexesFromCache(const Image *image)
3020{
3021 CacheInfo
3022 *cache_info;
3023
3024 const IndexPacket
3025 *indexes;
3026
cristybb503372010-05-27 20:51:26 +00003027 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003028 id;
3029
3030 if (image->debug != MagickFalse)
3031 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3032 cache_info=(CacheInfo *) image->cache;
3033 id=GetOpenMPThreadId();
cristybb503372010-05-27 20:51:26 +00003034 assert(id < (ssize_t) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00003035 indexes=GetVirtualIndexesFromNexus(image->cache,cache_info->nexus_info[id]);
3036 return(indexes);
3037}
3038
3039/*
3040%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3041% %
3042% %
3043% %
3044+ G e t V i r t u a l I n d e x e s F r o m N e x u s %
3045% %
3046% %
3047% %
3048%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3049%
3050% GetVirtualIndexesFromNexus() returns the indexes associated with the
3051% specified cache nexus.
3052%
3053% The format of the GetVirtualIndexesFromNexus() method is:
3054%
3055% const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
3056% NexusInfo *nexus_info)
3057%
3058% A description of each parameter follows:
3059%
3060% o cache: the pixel cache.
3061%
3062% o nexus_info: the cache nexus to return the colormap indexes.
3063%
3064*/
3065MagickExport const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
3066 NexusInfo *nexus_info)
3067{
3068 CacheInfo
3069 *cache_info;
3070
3071 if (cache == (Cache) NULL)
3072 return((IndexPacket *) NULL);
3073 cache_info=(CacheInfo *) cache;
3074 assert(cache_info->signature == MagickSignature);
3075 if (cache_info->storage_class == UndefinedClass)
3076 return((IndexPacket *) NULL);
3077 return(nexus_info->indexes);
3078}
3079
3080/*
3081%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3082% %
3083% %
3084% %
3085% G e t V i r t u a l I n d e x Q u e u e %
3086% %
3087% %
3088% %
3089%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3090%
3091% GetVirtualIndexQueue() returns the virtual black channel or the
3092% colormap indexes associated with the last call to QueueAuthenticPixels() or
3093% GetVirtualPixels(). NULL is returned if the black channel or colormap
3094% indexes are not available.
3095%
3096% The format of the GetVirtualIndexQueue() method is:
3097%
3098% const IndexPacket *GetVirtualIndexQueue(const Image *image)
3099%
3100% A description of each parameter follows:
3101%
3102% o image: the image.
3103%
3104*/
3105MagickExport const IndexPacket *GetVirtualIndexQueue(const Image *image)
3106{
3107 CacheInfo
3108 *cache_info;
3109
3110 assert(image != (const Image *) NULL);
3111 assert(image->signature == MagickSignature);
3112 if (image->debug != MagickFalse)
3113 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3114 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 */
3294 if (image->debug != MagickFalse)
3295 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3296 cache_info=(CacheInfo *) image->cache;
cristy4cfbb3f2010-03-14 20:40:23 +00003297 if (cache_info->type == UndefinedCache)
cristy3ed852e2009-09-05 21:47:34 +00003298 return((const PixelPacket *) NULL);
3299 region.x=x;
3300 region.y=y;
3301 region.width=columns;
3302 region.height=rows;
3303 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
3304 if (pixels == (PixelPacket *) NULL)
3305 return((const PixelPacket *) NULL);
cristydf415c82010-03-11 16:47:50 +00003306 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3307 nexus_info->region.x;
3308 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3309 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003310 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3311 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003312 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3313 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003314 {
3315 MagickBooleanType
3316 status;
3317
3318 /*
3319 Pixel request is inside cache extents.
3320 */
3321 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
3322 return(pixels);
3323 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3324 if (status == MagickFalse)
3325 return((const PixelPacket *) NULL);
3326 if ((cache_info->storage_class == PseudoClass) ||
3327 (cache_info->colorspace == CMYKColorspace))
3328 {
3329 status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
3330 if (status == MagickFalse)
3331 return((const PixelPacket *) NULL);
3332 }
3333 return(pixels);
3334 }
3335 /*
3336 Pixel request is outside cache extents.
3337 */
3338 q=pixels;
3339 indexes=GetPixelCacheNexusIndexes(cache_info,nexus_info);
3340 virtual_nexus=AcquirePixelCacheNexus(1);
3341 if (virtual_nexus == (NexusInfo **) NULL)
3342 {
3343 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3344 "UnableToGetCacheNexus","`%s'",image->filename);
3345 return((const PixelPacket *) NULL);
3346 }
3347 switch (virtual_pixel_method)
3348 {
3349 case BlackVirtualPixelMethod:
3350 {
cristy4789f0d2010-01-10 00:01:06 +00003351 SetRedPixelComponent(&virtual_pixel,0);
3352 SetGreenPixelComponent(&virtual_pixel,0);
3353 SetBluePixelComponent(&virtual_pixel,0);
3354 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003355 break;
3356 }
3357 case GrayVirtualPixelMethod:
3358 {
cristy4789f0d2010-01-10 00:01:06 +00003359 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3360 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3361 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3362 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003363 break;
3364 }
3365 case TransparentVirtualPixelMethod:
3366 {
cristy4789f0d2010-01-10 00:01:06 +00003367 SetRedPixelComponent(&virtual_pixel,0);
3368 SetGreenPixelComponent(&virtual_pixel,0);
3369 SetBluePixelComponent(&virtual_pixel,0);
3370 SetOpacityPixelComponent(&virtual_pixel,TransparentOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003371 break;
3372 }
3373 case MaskVirtualPixelMethod:
3374 case WhiteVirtualPixelMethod:
3375 {
cristy4789f0d2010-01-10 00:01:06 +00003376 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3377 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3378 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3379 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003380 break;
3381 }
3382 default:
3383 {
3384 virtual_pixel=image->background_color;
3385 break;
3386 }
3387 }
cristyc3ec0d42010-04-07 01:18:08 +00003388 virtual_index=0;
cristybb503372010-05-27 20:51:26 +00003389 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003390 {
cristybb503372010-05-27 20:51:26 +00003391 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003392 {
3393 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003394 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
3395 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) || (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003396 {
3397 MagickModulo
3398 x_modulo,
3399 y_modulo;
3400
3401 /*
3402 Transfer a single pixel.
3403 */
3404 length=(MagickSizeType) 1;
3405 switch (virtual_pixel_method)
3406 {
3407 case BackgroundVirtualPixelMethod:
3408 case ConstantVirtualPixelMethod:
3409 case BlackVirtualPixelMethod:
3410 case GrayVirtualPixelMethod:
3411 case TransparentVirtualPixelMethod:
3412 case MaskVirtualPixelMethod:
3413 case WhiteVirtualPixelMethod:
3414 {
3415 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003416 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003417 break;
3418 }
3419 case EdgeVirtualPixelMethod:
3420 default:
3421 {
3422 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003423 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003424 1UL,1UL,virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003425 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3426 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003427 break;
3428 }
3429 case RandomVirtualPixelMethod:
3430 {
3431 if (cache_info->random_info == (RandomInfo *) NULL)
3432 cache_info->random_info=AcquireRandomInfo();
3433 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003434 RandomX(cache_info->random_info,cache_info->columns),
3435 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003436 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003437 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3438 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003439 break;
3440 }
3441 case DitherVirtualPixelMethod:
3442 {
3443 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003444 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003445 1UL,1UL,virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003446 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3447 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003448 break;
3449 }
3450 case TileVirtualPixelMethod:
3451 {
3452 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3453 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3454 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3455 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3456 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003457 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3458 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003459 break;
3460 }
3461 case MirrorVirtualPixelMethod:
3462 {
3463 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3464 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003465 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003466 x_modulo.remainder-1L;
3467 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3468 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003469 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003470 y_modulo.remainder-1L;
3471 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3472 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3473 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003474 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3475 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003476 break;
3477 }
3478 case CheckerTileVirtualPixelMethod:
3479 {
3480 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3481 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3482 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3483 {
3484 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003485 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003486 break;
3487 }
3488 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3489 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3490 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003491 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3492 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003493 break;
3494 }
3495 case HorizontalTileVirtualPixelMethod:
3496 {
cristybb503372010-05-27 20:51:26 +00003497 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003498 {
3499 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003500 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003501 break;
3502 }
3503 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3504 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3505 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3506 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3507 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003508 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3509 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003510 break;
3511 }
3512 case VerticalTileVirtualPixelMethod:
3513 {
cristybb503372010-05-27 20:51:26 +00003514 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
cristy3ed852e2009-09-05 21:47:34 +00003515 {
3516 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003517 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003518 break;
3519 }
3520 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3521 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3522 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3523 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3524 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003525 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3526 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003527 break;
3528 }
3529 case HorizontalTileEdgeVirtualPixelMethod:
3530 {
3531 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3532 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003533 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003534 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003535 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3536 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003537 break;
3538 }
3539 case VerticalTileEdgeVirtualPixelMethod:
3540 {
3541 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3542 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003543 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003544 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003545 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3546 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003547 break;
3548 }
3549 }
3550 if (p == (const PixelPacket *) NULL)
3551 break;
3552 *q++=(*p);
cristyc3ec0d42010-04-07 01:18:08 +00003553 if ((indexes != (IndexPacket *) NULL) &&
3554 (virtual_indexes != (const IndexPacket *) NULL))
3555 *indexes++=(*virtual_indexes);
cristy3ed852e2009-09-05 21:47:34 +00003556 continue;
3557 }
3558 /*
3559 Transfer a run of pixels.
3560 */
3561 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,
cristybb503372010-05-27 20:51:26 +00003562 (size_t) length,1UL,virtual_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003563 if (p == (const PixelPacket *) NULL)
3564 break;
cristyc3ec0d42010-04-07 01:18:08 +00003565 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003566 (void) CopyMagickMemory(q,p,(size_t) length*sizeof(*p));
3567 q+=length;
cristyc3ec0d42010-04-07 01:18:08 +00003568 if ((indexes != (IndexPacket *) NULL) &&
3569 (virtual_indexes != (const IndexPacket *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003570 {
cristyc3ec0d42010-04-07 01:18:08 +00003571 (void) CopyMagickMemory(indexes,virtual_indexes,(size_t) length*
3572 sizeof(*virtual_indexes));
3573 indexes+=length;
cristy3ed852e2009-09-05 21:47:34 +00003574 }
3575 }
3576 }
3577 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3578 return(pixels);
3579}
3580
3581/*
3582%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3583% %
3584% %
3585% %
3586+ G e t V i r t u a l P i x e l C a c h e %
3587% %
3588% %
3589% %
3590%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3591%
3592% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3593% cache as defined by the geometry parameters. A pointer to the pixels
3594% is returned if the pixels are transferred, otherwise a NULL is returned.
3595%
3596% The format of the GetVirtualPixelCache() method is:
3597%
3598% const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003599% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3600% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003601% ExceptionInfo *exception)
3602%
3603% A description of each parameter follows:
3604%
3605% o image: the image.
3606%
3607% o virtual_pixel_method: the virtual pixel method.
3608%
3609% o x,y,columns,rows: These values define the perimeter of a region of
3610% pixels.
3611%
3612% o exception: return any errors or warnings in this structure.
3613%
3614*/
3615static const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003616 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3617 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003618{
3619 CacheInfo
3620 *cache_info;
3621
3622 const PixelPacket
3623 *pixels;
3624
cristybb503372010-05-27 20:51:26 +00003625 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003626 id;
3627
3628 if (image->debug != MagickFalse)
3629 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3630 cache_info=(CacheInfo *) image->cache;
3631 id=GetOpenMPThreadId();
cristybb503372010-05-27 20:51:26 +00003632 assert(id < (ssize_t) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00003633 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3634 cache_info->nexus_info[id],exception);
3635 return(pixels);
3636}
3637
3638/*
3639%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3640% %
3641% %
3642% %
3643% G e t V i r t u a l P i x e l Q u e u e %
3644% %
3645% %
3646% %
3647%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3648%
3649% GetVirtualPixelQueue() returns the virtual pixels associated with the
3650% last call to QueueAuthenticPixels() or GetVirtualPixels().
3651%
3652% The format of the GetVirtualPixelQueue() method is:
3653%
3654% const PixelPacket *GetVirtualPixelQueue(const Image image)
3655%
3656% A description of each parameter follows:
3657%
3658% o image: the image.
3659%
3660*/
3661MagickExport const PixelPacket *GetVirtualPixelQueue(const Image *image)
3662{
3663 CacheInfo
3664 *cache_info;
3665
3666 assert(image != (const Image *) NULL);
3667 assert(image->signature == MagickSignature);
3668 if (image->debug != MagickFalse)
3669 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3670 assert(image->cache != (Cache) NULL);
3671 cache_info=(CacheInfo *) image->cache;
3672 assert(cache_info->signature == MagickSignature);
3673 if (cache_info->methods.get_virtual_pixels_handler ==
3674 (GetVirtualPixelsHandler) NULL)
3675 return((PixelPacket *) NULL);
3676 return(cache_info->methods.get_virtual_pixels_handler(image));
3677}
3678
3679/*
3680%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3681% %
3682% %
3683% %
3684% G e t V i r t u a l P i x e l s %
3685% %
3686% %
3687% %
3688%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3689%
3690% GetVirtualPixels() returns an immutable pixel region. If the
3691% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003692% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003693% copy of the pixels or it may point to the original pixels in memory.
3694% Performance is maximized if the selected region is part of one row, or one
3695% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003696% (without a copy) if the image is in memory, or in a memory-mapped file. The
3697% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003698%
3699% Pixels accessed via the returned pointer represent a simple array of type
3700% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
3701% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access
3702% the black color component or to obtain the colormap indexes (of type
3703% IndexPacket) corresponding to the region.
3704%
3705% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3706%
3707% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3708% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3709% GetCacheViewAuthenticPixels() instead.
3710%
3711% The format of the GetVirtualPixels() method is:
3712%
cristybb503372010-05-27 20:51:26 +00003713% const PixelPacket *GetVirtualPixels(const Image *image,const ssize_t x,
3714% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003715% ExceptionInfo *exception)
3716%
3717% A description of each parameter follows:
3718%
3719% o image: the image.
3720%
3721% o x,y,columns,rows: These values define the perimeter of a region of
3722% pixels.
3723%
3724% o exception: return any errors or warnings in this structure.
3725%
3726*/
3727MagickExport const PixelPacket *GetVirtualPixels(const Image *image,
cristybb503372010-05-27 20:51:26 +00003728 const ssize_t x,const ssize_t y,const size_t columns,
3729 const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003730{
3731 CacheInfo
3732 *cache_info;
3733
3734 const PixelPacket
3735 *pixels;
3736
3737 assert(image != (const Image *) NULL);
3738 assert(image->signature == MagickSignature);
3739 if (image->debug != MagickFalse)
3740 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3741 assert(image->cache != (Cache) NULL);
3742 cache_info=(CacheInfo *) image->cache;
3743 assert(cache_info->signature == MagickSignature);
3744 if (cache_info->methods.get_virtual_pixel_handler ==
3745 (GetVirtualPixelHandler) NULL)
3746 return((const PixelPacket *) NULL);
3747 pixels=cache_info->methods.get_virtual_pixel_handler(image,
3748 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception);
3749 return(pixels);
3750}
3751
3752/*
3753%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3754% %
3755% %
3756% %
3757+ 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 %
3758% %
3759% %
3760% %
3761%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3762%
3763% GetVirtualPixelsCache() returns the pixels associated with the last call
3764% to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3765%
3766% The format of the GetVirtualPixelsCache() method is:
3767%
3768% PixelPacket *GetVirtualPixelsCache(const Image *image)
3769%
3770% A description of each parameter follows:
3771%
3772% o image: the image.
3773%
3774*/
3775static const PixelPacket *GetVirtualPixelsCache(const Image *image)
3776{
3777 CacheInfo
3778 *cache_info;
3779
3780 const PixelPacket
3781 *pixels;
3782
cristybb503372010-05-27 20:51:26 +00003783 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003784 id;
3785
3786 if (image->debug != MagickFalse)
3787 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3788 cache_info=(CacheInfo *) image->cache;
3789 id=GetOpenMPThreadId();
cristybb503372010-05-27 20:51:26 +00003790 assert(id < (ssize_t) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00003791 pixels=GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]);
3792 return(pixels);
3793}
3794
3795/*
3796%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3797% %
3798% %
3799% %
3800+ G e t V i r t u a l P i x e l s N e x u s %
3801% %
3802% %
3803% %
3804%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3805%
3806% GetVirtualPixelsNexus() returns the pixels associated with the specified
3807% cache nexus.
3808%
3809% The format of the GetVirtualPixelsNexus() method is:
3810%
3811% const IndexPacket *GetVirtualPixelsNexus(const Cache cache,
3812% NexusInfo *nexus_info)
3813%
3814% A description of each parameter follows:
3815%
3816% o cache: the pixel cache.
3817%
3818% o nexus_info: the cache nexus to return the colormap pixels.
3819%
3820*/
3821MagickExport const PixelPacket *GetVirtualPixelsNexus(const Cache cache,
3822 NexusInfo *nexus_info)
3823{
3824 CacheInfo
3825 *cache_info;
3826
3827 if (cache == (Cache) NULL)
3828 return((PixelPacket *) NULL);
3829 cache_info=(CacheInfo *) cache;
3830 assert(cache_info->signature == MagickSignature);
3831 if (cache_info->storage_class == UndefinedClass)
3832 return((PixelPacket *) NULL);
3833 return((const PixelPacket *) nexus_info->pixels);
3834}
3835
3836/*
3837%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3838% %
3839% %
3840% %
3841+ M a s k P i x e l C a c h e N e x u s %
3842% %
3843% %
3844% %
3845%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3846%
3847% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3848% The method returns MagickTrue if the pixel region is masked, otherwise
3849% MagickFalse.
3850%
3851% The format of the MaskPixelCacheNexus() method is:
3852%
3853% MagickBooleanType MaskPixelCacheNexus(Image *image,
3854% NexusInfo *nexus_info,ExceptionInfo *exception)
3855%
3856% A description of each parameter follows:
3857%
3858% o image: the image.
3859%
3860% o nexus_info: the cache nexus to clip.
3861%
3862% o exception: return any errors or warnings in this structure.
3863%
3864*/
3865
3866static inline void MagickPixelCompositeMask(const MagickPixelPacket *p,
3867 const MagickRealType alpha,const MagickPixelPacket *q,
3868 const MagickRealType beta,MagickPixelPacket *composite)
3869{
3870 MagickRealType
3871 gamma;
3872
3873 if (alpha == TransparentOpacity)
3874 {
3875 *composite=(*q);
3876 return;
3877 }
3878 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3879 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3880 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3881 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3882 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3883 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3884 composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
3885}
3886
3887static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3888 ExceptionInfo *exception)
3889{
3890 CacheInfo
3891 *cache_info;
3892
3893 MagickPixelPacket
3894 alpha,
3895 beta;
3896
3897 MagickSizeType
3898 number_pixels;
3899
3900 NexusInfo
3901 **clip_nexus,
3902 **image_nexus;
3903
3904 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003905 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003906
3907 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003908 *restrict nexus_indexes,
3909 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003910
cristybb503372010-05-27 20:51:26 +00003911 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003912 i;
3913
3914 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003915 *restrict p,
3916 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003917
3918 /*
3919 Apply clip mask.
3920 */
3921 if (image->debug != MagickFalse)
3922 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3923 if (image->mask == (Image *) NULL)
3924 return(MagickFalse);
3925 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
3926 if (cache_info == (Cache) NULL)
3927 return(MagickFalse);
3928 image_nexus=AcquirePixelCacheNexus(1);
3929 clip_nexus=AcquirePixelCacheNexus(1);
3930 if ((image_nexus == (NexusInfo **) NULL) ||
3931 (clip_nexus == (NexusInfo **) NULL))
3932 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy09449f72010-01-23 03:08:36 +00003933 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,
3934 nexus_info->region.y,nexus_info->region.width,nexus_info->region.height,
3935 image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003936 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
3937 q=nexus_info->pixels;
3938 nexus_indexes=nexus_info->indexes;
3939 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3940 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3941 nexus_info->region.height,clip_nexus[0],&image->exception);
3942 GetMagickPixelPacket(image,&alpha);
3943 GetMagickPixelPacket(image,&beta);
3944 number_pixels=(MagickSizeType) nexus_info->region.width*
3945 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +00003946 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +00003947 {
3948 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
3949 break;
3950 SetMagickPixelPacket(image,p,indexes+i,&alpha);
3951 SetMagickPixelPacket(image,q,nexus_indexes+i,&beta);
3952 MagickPixelCompositeMask(&beta,(MagickRealType) PixelIntensityToQuantum(r),
3953 &alpha,alpha.opacity,&beta);
cristyce70c172010-01-07 17:15:30 +00003954 q->red=ClampToQuantum(beta.red);
3955 q->green=ClampToQuantum(beta.green);
3956 q->blue=ClampToQuantum(beta.blue);
3957 q->opacity=ClampToQuantum(beta.opacity);
cristy3ed852e2009-09-05 21:47:34 +00003958 if (cache_info->active_index_channel != MagickFalse)
3959 nexus_indexes[i]=indexes[i];
3960 p++;
3961 q++;
3962 r++;
3963 }
3964 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3965 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +00003966 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003967 return(MagickFalse);
3968 return(MagickTrue);
3969}
3970
3971/*
3972%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3973% %
3974% %
3975% %
3976+ O p e n P i x e l C a c h e %
3977% %
3978% %
3979% %
3980%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3981%
3982% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3983% dimensions, allocating space for the image pixels and optionally the
3984% colormap indexes, and memory mapping the cache if it is disk based. The
3985% cache nexus array is initialized as well.
3986%
3987% The format of the OpenPixelCache() method is:
3988%
3989% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3990% ExceptionInfo *exception)
3991%
3992% A description of each parameter follows:
3993%
3994% o image: the image.
3995%
3996% o mode: ReadMode, WriteMode, or IOMode.
3997%
3998% o exception: return any errors or warnings in this structure.
3999%
4000*/
4001
cristyd43a46b2010-01-21 02:13:41 +00004002static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00004003{
4004 cache_info->mapped=MagickFalse;
4005 cache_info->pixels=(PixelPacket *) AcquireMagickMemory((size_t)
4006 cache_info->length);
4007 if (cache_info->pixels == (PixelPacket *) NULL)
4008 {
4009 cache_info->mapped=MagickTrue;
4010 cache_info->pixels=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
4011 cache_info->length);
4012 }
4013}
4014
4015static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
4016{
4017 CacheInfo
4018 *cache_info;
4019
4020 MagickOffsetType
4021 count,
4022 extent,
4023 offset;
4024
4025 cache_info=(CacheInfo *) image->cache;
4026 if (image->debug != MagickFalse)
4027 {
4028 char
4029 format[MaxTextExtent],
4030 message[MaxTextExtent];
4031
cristyb9080c92009-12-01 20:13:26 +00004032 (void) FormatMagickSize(length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00004033 (void) FormatMagickString(message,MaxTextExtent,
cristy2ce15c92010-03-12 14:03:41 +00004034 "extend %s (%s[%d], disk, %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00004035 cache_info->cache_filename,cache_info->file,format);
4036 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4037 }
4038 if (length != (MagickSizeType) ((MagickOffsetType) length))
4039 return(MagickFalse);
4040 extent=(MagickOffsetType) MagickSeek(cache_info->file,0,SEEK_END);
4041 if (extent < 0)
4042 return(MagickFalse);
4043 if ((MagickSizeType) extent >= length)
4044 return(MagickTrue);
4045 offset=(MagickOffsetType) length-1;
4046 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
4047 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
4048}
4049
4050static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
4051 ExceptionInfo *exception)
4052{
4053 char
4054 format[MaxTextExtent],
4055 message[MaxTextExtent];
4056
4057 CacheInfo
4058 *cache_info,
4059 source_info;
4060
4061 MagickSizeType
4062 length,
4063 number_pixels;
4064
4065 MagickStatusType
4066 status;
4067
4068 size_t
4069 packet_size;
4070
cristybb503372010-05-27 20:51:26 +00004071 size_t
cristy3ed852e2009-09-05 21:47:34 +00004072 columns;
4073
4074 if (image->debug != MagickFalse)
4075 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4076 if ((image->columns == 0) || (image->rows == 0))
4077 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
4078 cache_info=(CacheInfo *) image->cache;
4079 source_info=(*cache_info);
4080 source_info.file=(-1);
cristye8c25f92010-06-03 00:53:06 +00004081 (void) FormatMagickString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
4082 image->filename,(double) GetImageIndexInList(image));
cristy87528ea2009-09-10 14:53:56 +00004083 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +00004084 cache_info->rows=image->rows;
4085 cache_info->columns=image->columns;
4086 cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
4087 (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
cristy73724512010-04-12 14:43:14 +00004088 if (image->ping != MagickFalse)
4089 {
4090 cache_info->storage_class=image->storage_class;
4091 cache_info->colorspace=image->colorspace;
4092 cache_info->type=PingCache;
4093 cache_info->pixels=(PixelPacket *) NULL;
4094 cache_info->indexes=(IndexPacket *) NULL;
4095 cache_info->length=0;
4096 return(MagickTrue);
4097 }
cristy3ed852e2009-09-05 21:47:34 +00004098 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4099 packet_size=sizeof(PixelPacket);
4100 if (cache_info->active_index_channel != MagickFalse)
4101 packet_size+=sizeof(IndexPacket);
4102 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00004103 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00004104 if (cache_info->columns != columns)
4105 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4106 image->filename);
4107 cache_info->length=length;
4108 status=AcquireMagickResource(AreaResource,cache_info->length);
4109 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4110 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4111 {
4112 status=AcquireMagickResource(MemoryResource,cache_info->length);
4113 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4114 (cache_info->type == MemoryCache))
4115 {
cristyd43a46b2010-01-21 02:13:41 +00004116 AllocatePixelCachePixels(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004117 if (cache_info->pixels == (PixelPacket *) NULL)
4118 cache_info->pixels=source_info.pixels;
4119 else
4120 {
4121 /*
4122 Create memory pixel cache.
4123 */
4124 if (image->debug != MagickFalse)
4125 {
cristy97e7a572009-12-05 15:07:53 +00004126 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004127 format);
cristy3ed852e2009-09-05 21:47:34 +00004128 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004129 "open %s (%s memory, %.20gx%.20g %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00004130 cache_info->mapped != MagickFalse ? "anonymous" : "heap",
cristye8c25f92010-06-03 00:53:06 +00004131 (double) cache_info->columns,(double) cache_info->rows,
4132 format);
cristy3ed852e2009-09-05 21:47:34 +00004133 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4134 message);
4135 }
4136 cache_info->storage_class=image->storage_class;
4137 cache_info->colorspace=image->colorspace;
4138 cache_info->type=MemoryCache;
4139 cache_info->indexes=(IndexPacket *) NULL;
4140 if (cache_info->active_index_channel != MagickFalse)
4141 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4142 number_pixels);
4143 if (source_info.storage_class != UndefinedClass)
4144 {
4145 status|=ClonePixelCachePixels(cache_info,&source_info,
4146 exception);
4147 RelinquishPixelCachePixels(&source_info);
4148 }
4149 return(MagickTrue);
4150 }
4151 }
4152 RelinquishMagickResource(MemoryResource,cache_info->length);
4153 }
4154 /*
4155 Create pixel cache on disk.
4156 */
4157 status=AcquireMagickResource(DiskResource,cache_info->length);
4158 if (status == MagickFalse)
4159 {
4160 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4161 "CacheResourcesExhausted","`%s'",image->filename);
4162 return(MagickFalse);
4163 }
4164 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4165 {
4166 RelinquishMagickResource(DiskResource,cache_info->length);
4167 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4168 image->filename);
4169 return(MagickFalse);
4170 }
4171 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4172 cache_info->length);
4173 if (status == MagickFalse)
4174 {
4175 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4176 image->filename);
4177 return(MagickFalse);
4178 }
4179 cache_info->storage_class=image->storage_class;
4180 cache_info->colorspace=image->colorspace;
4181 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4182 status=AcquireMagickResource(AreaResource,cache_info->length);
4183 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4184 cache_info->type=DiskCache;
4185 else
4186 {
4187 status=AcquireMagickResource(MapResource,cache_info->length);
4188 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4189 (cache_info->type != MemoryCache))
4190 cache_info->type=DiskCache;
4191 else
4192 {
4193 cache_info->pixels=(PixelPacket *) MapBlob(cache_info->file,mode,
4194 cache_info->offset,(size_t) cache_info->length);
4195 if (cache_info->pixels == (PixelPacket *) NULL)
4196 {
4197 cache_info->pixels=source_info.pixels;
4198 cache_info->type=DiskCache;
4199 }
4200 else
4201 {
4202 /*
4203 Create file-backed memory-mapped pixel cache.
4204 */
4205 (void) ClosePixelCacheOnDisk(cache_info);
4206 cache_info->type=MapCache;
4207 cache_info->mapped=MagickTrue;
4208 cache_info->indexes=(IndexPacket *) NULL;
4209 if (cache_info->active_index_channel != MagickFalse)
4210 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4211 number_pixels);
4212 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4213 {
4214 status=ClonePixelCachePixels(cache_info,&source_info,
4215 exception);
4216 RelinquishPixelCachePixels(&source_info);
4217 }
4218 if (image->debug != MagickFalse)
4219 {
cristy97e7a572009-12-05 15:07:53 +00004220 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004221 format);
cristy3ed852e2009-09-05 21:47:34 +00004222 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004223 "open %s (%s[%d], memory-mapped, %.20gx%.20g %sB)",
cristy3ed852e2009-09-05 21:47:34 +00004224 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004225 cache_info->file,(double) cache_info->columns,(double)
4226 cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004227 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4228 message);
4229 }
4230 return(MagickTrue);
4231 }
4232 }
4233 RelinquishMagickResource(MapResource,cache_info->length);
4234 }
4235 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4236 {
4237 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4238 RelinquishPixelCachePixels(&source_info);
4239 }
4240 if (image->debug != MagickFalse)
4241 {
cristyb9080c92009-12-01 20:13:26 +00004242 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00004243 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004244 "open %s (%s[%d], disk, %.20gx%.20g %sB)",cache_info->filename,
4245 cache_info->cache_filename,cache_info->file,(double)
4246 cache_info->columns,(double) cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004247 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4248 }
4249 return(MagickTrue);
4250}
4251
4252/*
4253%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4254% %
4255% %
4256% %
4257+ P e r s i s t P i x e l C a c h e %
4258% %
4259% %
4260% %
4261%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4262%
4263% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4264% persistent pixel cache is one that resides on disk and is not destroyed
4265% when the program exits.
4266%
4267% The format of the PersistPixelCache() method is:
4268%
4269% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4270% const MagickBooleanType attach,MagickOffsetType *offset,
4271% ExceptionInfo *exception)
4272%
4273% A description of each parameter follows:
4274%
4275% o image: the image.
4276%
4277% o filename: the persistent pixel cache filename.
4278%
cristy01b7eb02009-09-10 23:10:14 +00004279% o attach: A value other than zero initializes the persistent pixel
4280% cache.
4281%
cristy3ed852e2009-09-05 21:47:34 +00004282% o initialize: A value other than zero initializes the persistent pixel
4283% cache.
4284%
4285% o offset: the offset in the persistent cache to store pixels.
4286%
4287% o exception: return any errors or warnings in this structure.
4288%
4289*/
4290MagickExport MagickBooleanType PersistPixelCache(Image *image,
4291 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4292 ExceptionInfo *exception)
4293{
4294 CacheInfo
4295 *cache_info,
4296 *clone_info;
4297
4298 Image
4299 clone_image;
4300
cristybb503372010-05-27 20:51:26 +00004301 ssize_t
cristy688f07b2009-09-27 15:19:13 +00004302 page_size;
cristy3ed852e2009-09-05 21:47:34 +00004303
4304 MagickBooleanType
4305 status;
4306
4307 assert(image != (Image *) NULL);
4308 assert(image->signature == MagickSignature);
4309 if (image->debug != MagickFalse)
4310 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4311 assert(image->cache != (void *) NULL);
4312 assert(filename != (const char *) NULL);
4313 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004314 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004315 cache_info=(CacheInfo *) image->cache;
4316 assert(cache_info->signature == MagickSignature);
4317 if (attach != MagickFalse)
4318 {
4319 /*
cristy01b7eb02009-09-10 23:10:14 +00004320 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004321 */
4322 if (image->debug != MagickFalse)
4323 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4324 "attach persistent cache");
4325 (void) CopyMagickString(cache_info->cache_filename,filename,
4326 MaxTextExtent);
4327 cache_info->type=DiskCache;
4328 cache_info->offset=(*offset);
4329 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4330 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004331 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004332 return(MagickTrue);
4333 }
cristy01b7eb02009-09-10 23:10:14 +00004334 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4335 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004336 {
cristyf84a1932010-01-03 18:00:18 +00004337 LockSemaphoreInfo(cache_info->semaphore);
cristy09449f72010-01-23 03:08:36 +00004338 if ((cache_info->mode != ReadMode) &&
4339 (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004340 (cache_info->reference_count == 1))
4341 {
4342 int
4343 status;
4344
4345 /*
cristy01b7eb02009-09-10 23:10:14 +00004346 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004347 */
4348 status=rename(cache_info->cache_filename,filename);
4349 if (status == 0)
4350 {
4351 (void) CopyMagickString(cache_info->cache_filename,filename,
4352 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004353 *offset+=cache_info->length+page_size-(cache_info->length %
4354 page_size);
cristyf84a1932010-01-03 18:00:18 +00004355 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004356 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004357 if (image->debug != MagickFalse)
4358 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4359 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004360 return(MagickTrue);
4361 }
4362 }
cristyf84a1932010-01-03 18:00:18 +00004363 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004364 }
4365 /*
cristy01b7eb02009-09-10 23:10:14 +00004366 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004367 */
4368 clone_image=(*image);
4369 clone_info=(CacheInfo *) clone_image.cache;
4370 image->cache=ClonePixelCache(cache_info);
4371 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4372 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4373 cache_info->type=DiskCache;
4374 cache_info->offset=(*offset);
4375 cache_info=(CacheInfo *) image->cache;
4376 status=ClonePixelCacheNexus(cache_info,clone_info,exception);
4377 if (status != MagickFalse)
4378 {
4379 status=OpenPixelCache(image,IOMode,exception);
4380 if (status != MagickFalse)
4381 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
4382 }
cristy688f07b2009-09-27 15:19:13 +00004383 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004384 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4385 return(status);
4386}
4387
4388/*
4389%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4390% %
4391% %
4392% %
4393+ Q u e u e A u t h e n t i c N e x u s %
4394% %
4395% %
4396% %
4397%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4398%
4399% QueueAuthenticNexus() allocates an region to store image pixels as defined
4400% by the region rectangle and returns a pointer to the region. This region is
4401% subsequently transferred from the pixel cache with
4402% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4403% pixels are transferred, otherwise a NULL is returned.
4404%
4405% The format of the QueueAuthenticNexus() method is:
4406%
cristy5f959472010-05-27 22:19:46 +00004407% PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
4408% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004409% NexusInfo *nexus_info,ExceptionInfo *exception)
4410%
4411% A description of each parameter follows:
4412%
4413% o image: the image.
4414%
4415% o x,y,columns,rows: These values define the perimeter of a region of
4416% pixels.
4417%
4418% o nexus_info: the cache nexus to set.
4419%
4420% o exception: return any errors or warnings in this structure.
4421%
4422*/
cristybb503372010-05-27 20:51:26 +00004423MagickExport PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
4424 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004425 NexusInfo *nexus_info,ExceptionInfo *exception)
4426{
4427 CacheInfo
4428 *cache_info;
4429
4430 MagickOffsetType
4431 offset;
4432
4433 MagickSizeType
4434 number_pixels;
4435
4436 RectangleInfo
4437 region;
4438
4439 /*
4440 Validate pixel cache geometry.
4441 */
4442 cache_info=(CacheInfo *) image->cache;
4443 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4444 {
4445 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4446 "NoPixelsDefinedInCache","`%s'",image->filename);
4447 return((PixelPacket *) NULL);
4448 }
cristybb503372010-05-27 20:51:26 +00004449 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4450 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004451 {
4452 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4453 "PixelsAreNotAuthentic","`%s'",image->filename);
4454 return((PixelPacket *) NULL);
4455 }
4456 offset=(MagickOffsetType) y*cache_info->columns+x;
4457 if (offset < 0)
4458 return((PixelPacket *) NULL);
4459 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4460 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4461 if ((MagickSizeType) offset >= number_pixels)
4462 return((PixelPacket *) NULL);
4463 /*
4464 Return pixel cache.
4465 */
4466 region.x=x;
4467 region.y=y;
4468 region.width=columns;
4469 region.height=rows;
4470 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4471}
4472
4473/*
4474%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4475% %
4476% %
4477% %
4478+ 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 %
4479% %
4480% %
4481% %
4482%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4483%
4484% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4485% defined by the region rectangle and returns a pointer to the region. This
4486% region is subsequently transferred from the pixel cache with
4487% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4488% pixels are transferred, otherwise a NULL is returned.
4489%
4490% The format of the QueueAuthenticPixelsCache() method is:
4491%
cristybb503372010-05-27 20:51:26 +00004492% PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4493% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004494% ExceptionInfo *exception)
4495%
4496% A description of each parameter follows:
4497%
4498% o image: the image.
4499%
4500% o x,y,columns,rows: These values define the perimeter of a region of
4501% pixels.
4502%
4503% o exception: return any errors or warnings in this structure.
4504%
4505*/
cristybb503372010-05-27 20:51:26 +00004506static PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4507 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004508 ExceptionInfo *exception)
4509{
4510 CacheInfo
4511 *cache_info;
4512
cristybb503372010-05-27 20:51:26 +00004513 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004514 id;
4515
4516 PixelPacket
4517 *pixels;
4518
4519 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickFalse,exception);
4520 if (cache_info == (Cache) NULL)
4521 return((PixelPacket *) NULL);
4522 id=GetOpenMPThreadId();
cristybb503372010-05-27 20:51:26 +00004523 assert(id < (ssize_t) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00004524 pixels=QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4525 exception);
4526 return(pixels);
4527}
4528
4529/*
4530%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4531% %
4532% %
4533% %
4534% Q u e u e A u t h e n t i c P i x e l s %
4535% %
4536% %
4537% %
4538%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4539%
4540% QueueAuthenticPixels() queues a mutable pixel region. If the region is
4541% successfully intialized a pointer to a PixelPacket array representing the
4542% region is returned, otherwise NULL is returned. The returned pointer may
4543% point to a temporary working buffer for the pixels or it may point to the
4544% final location of the pixels in memory.
4545%
4546% Write-only access means that any existing pixel values corresponding to
4547% the region are ignored. This is useful if the initial image is being
4548% created from scratch, or if the existing pixel values are to be
4549% completely replaced without need to refer to their pre-existing values.
4550% The application is free to read and write the pixel buffer returned by
4551% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4552% initialize the pixel array values. Initializing pixel array values is the
4553% application's responsibility.
4554%
4555% Performance is maximized if the selected region is part of one row, or
4556% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004557% pixels in-place (without a copy) if the image is in memory, or in a
4558% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004559% by the user.
4560%
4561% Pixels accessed via the returned pointer represent a simple array of type
4562% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
4563% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
4564% the black color component or the colormap indexes (of type IndexPacket)
4565% corresponding to the region. Once the PixelPacket (and/or IndexPacket)
4566% array has been updated, the changes must be saved back to the underlying
4567% image using SyncAuthenticPixels() or they may be lost.
4568%
4569% The format of the QueueAuthenticPixels() method is:
4570%
cristy5f959472010-05-27 22:19:46 +00004571% PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4572% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004573% ExceptionInfo *exception)
4574%
4575% A description of each parameter follows:
4576%
4577% o image: the image.
4578%
4579% o x,y,columns,rows: These values define the perimeter of a region of
4580% pixels.
4581%
4582% o exception: return any errors or warnings in this structure.
4583%
4584*/
cristybb503372010-05-27 20:51:26 +00004585MagickExport PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4586 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004587 ExceptionInfo *exception)
4588{
4589 CacheInfo
4590 *cache_info;
4591
4592 PixelPacket
4593 *pixels;
4594
4595 assert(image != (Image *) NULL);
4596 assert(image->signature == MagickSignature);
4597 if (image->debug != MagickFalse)
4598 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4599 assert(image->cache != (Cache) NULL);
4600 cache_info=(CacheInfo *) image->cache;
4601 assert(cache_info->signature == MagickSignature);
4602 if (cache_info->methods.queue_authentic_pixels_handler ==
4603 (QueueAuthenticPixelsHandler) NULL)
4604 return((PixelPacket *) NULL);
4605 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4606 rows,exception);
4607 return(pixels);
4608}
4609
4610/*
4611%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4612% %
4613% %
4614% %
4615+ R e a d P i x e l C a c h e I n d e x e s %
4616% %
4617% %
4618% %
4619%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4620%
4621% ReadPixelCacheIndexes() reads colormap indexes from the specified region of
4622% the pixel cache.
4623%
4624% The format of the ReadPixelCacheIndexes() method is:
4625%
4626% MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4627% NexusInfo *nexus_info,ExceptionInfo *exception)
4628%
4629% A description of each parameter follows:
4630%
4631% o cache_info: the pixel cache.
4632%
4633% o nexus_info: the cache nexus to read the colormap indexes.
4634%
4635% o exception: return any errors or warnings in this structure.
4636%
4637*/
4638static MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4639 NexusInfo *nexus_info,ExceptionInfo *exception)
4640{
4641 MagickOffsetType
4642 count,
4643 offset;
4644
4645 MagickSizeType
4646 length,
4647 number_pixels;
4648
4649 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004650 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004651
cristybb503372010-05-27 20:51:26 +00004652 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004653 y;
4654
cristybb503372010-05-27 20:51:26 +00004655 size_t
cristy3ed852e2009-09-05 21:47:34 +00004656 rows;
4657
4658 if (cache_info->debug != MagickFalse)
4659 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4660 cache_info->filename);
4661 if (cache_info->active_index_channel == MagickFalse)
4662 return(MagickFalse);
4663 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4664 return(MagickTrue);
4665 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4666 nexus_info->region.x;
4667 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
4668 rows=nexus_info->region.height;
4669 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004670 q=nexus_info->indexes;
4671 switch (cache_info->type)
4672 {
4673 case MemoryCache:
4674 case MapCache:
4675 {
4676 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004677 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004678
4679 /*
4680 Read indexes from memory.
4681 */
cristydd341db2010-03-04 19:06:38 +00004682 if ((cache_info->columns == nexus_info->region.width) &&
4683 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4684 {
4685 length=number_pixels;
4686 rows=1UL;
4687 }
cristy3ed852e2009-09-05 21:47:34 +00004688 p=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00004689 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004690 {
4691 (void) CopyMagickMemory(q,p,(size_t) length);
4692 p+=cache_info->columns;
4693 q+=nexus_info->region.width;
4694 }
4695 break;
4696 }
4697 case DiskCache:
4698 {
4699 /*
4700 Read indexes from disk.
4701 */
4702 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4703 {
4704 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4705 cache_info->cache_filename);
4706 return(MagickFalse);
4707 }
cristydd341db2010-03-04 19:06:38 +00004708 if ((cache_info->columns == nexus_info->region.width) &&
4709 (number_pixels < MagickMaxBufferExtent))
4710 {
4711 length=number_pixels;
4712 rows=1UL;
4713 }
cristy3ed852e2009-09-05 21:47:34 +00004714 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004715 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004716 {
4717 count=ReadPixelCacheRegion(cache_info,cache_info->offset+number_pixels*
4718 sizeof(PixelPacket)+offset*sizeof(*q),length,(unsigned char *) q);
4719 if ((MagickSizeType) count < length)
4720 break;
4721 offset+=cache_info->columns;
4722 q+=nexus_info->region.width;
4723 }
cristybb503372010-05-27 20:51:26 +00004724 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004725 {
4726 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4727 cache_info->cache_filename);
4728 return(MagickFalse);
4729 }
4730 break;
4731 }
4732 default:
4733 break;
4734 }
4735 if ((cache_info->debug != MagickFalse) &&
cristyecd0ab52010-05-30 14:59:20 +00004736 (QuantumTick((MagickOffsetType) nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004737 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004738 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004739 nexus_info->region.width,(double) nexus_info->region.height,(double)
4740 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004741 return(MagickTrue);
4742}
4743
4744/*
4745%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4746% %
4747% %
4748% %
4749+ R e a d P i x e l C a c h e P i x e l s %
4750% %
4751% %
4752% %
4753%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4754%
4755% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4756% cache.
4757%
4758% The format of the ReadPixelCachePixels() method is:
4759%
4760% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4761% NexusInfo *nexus_info,ExceptionInfo *exception)
4762%
4763% A description of each parameter follows:
4764%
4765% o cache_info: the pixel cache.
4766%
4767% o nexus_info: the cache nexus to read the pixels.
4768%
4769% o exception: return any errors or warnings in this structure.
4770%
4771*/
4772static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4773 NexusInfo *nexus_info,ExceptionInfo *exception)
4774{
4775 MagickOffsetType
4776 count,
4777 offset;
4778
4779 MagickSizeType
4780 length,
4781 number_pixels;
4782
cristybb503372010-05-27 20:51:26 +00004783 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004784 y;
4785
4786 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004787 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004788
cristybb503372010-05-27 20:51:26 +00004789 size_t
cristy3ed852e2009-09-05 21:47:34 +00004790 rows;
4791
4792 if (cache_info->debug != MagickFalse)
4793 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4794 cache_info->filename);
4795 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4796 return(MagickTrue);
4797 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4798 nexus_info->region.x;
4799 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
4800 rows=nexus_info->region.height;
4801 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004802 q=nexus_info->pixels;
4803 switch (cache_info->type)
4804 {
4805 case MemoryCache:
4806 case MapCache:
4807 {
4808 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004809 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004810
4811 /*
4812 Read pixels from memory.
4813 */
cristydd341db2010-03-04 19:06:38 +00004814 if ((cache_info->columns == nexus_info->region.width) &&
4815 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4816 {
4817 length=number_pixels;
4818 rows=1UL;
4819 }
cristy3ed852e2009-09-05 21:47:34 +00004820 p=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00004821 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004822 {
4823 (void) CopyMagickMemory(q,p,(size_t) length);
4824 p+=cache_info->columns;
4825 q+=nexus_info->region.width;
4826 }
4827 break;
4828 }
4829 case DiskCache:
4830 {
4831 /*
4832 Read pixels from disk.
4833 */
4834 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4835 {
4836 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4837 cache_info->cache_filename);
4838 return(MagickFalse);
4839 }
cristydd341db2010-03-04 19:06:38 +00004840 if ((cache_info->columns == nexus_info->region.width) &&
4841 (number_pixels < MagickMaxBufferExtent))
4842 {
4843 length=number_pixels;
4844 rows=1UL;
4845 }
cristybb503372010-05-27 20:51:26 +00004846 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004847 {
4848 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4849 sizeof(*q),length,(unsigned char *) q);
4850 if ((MagickSizeType) count < length)
4851 break;
4852 offset+=cache_info->columns;
4853 q+=nexus_info->region.width;
4854 }
cristybb503372010-05-27 20:51:26 +00004855 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004856 {
4857 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4858 cache_info->cache_filename);
4859 return(MagickFalse);
4860 }
4861 break;
4862 }
4863 default:
4864 break;
4865 }
4866 if ((cache_info->debug != MagickFalse) &&
cristyecd0ab52010-05-30 14:59:20 +00004867 (QuantumTick((MagickOffsetType) nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004868 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004869 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004870 nexus_info->region.width,(double) nexus_info->region.height,(double)
4871 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004872 return(MagickTrue);
4873}
4874
4875/*
4876%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4877% %
4878% %
4879% %
4880+ R e f e r e n c e P i x e l C a c h e %
4881% %
4882% %
4883% %
4884%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4885%
4886% ReferencePixelCache() increments the reference count associated with the
4887% pixel cache returning a pointer to the cache.
4888%
4889% The format of the ReferencePixelCache method is:
4890%
4891% Cache ReferencePixelCache(Cache cache_info)
4892%
4893% A description of each parameter follows:
4894%
4895% o cache_info: the pixel cache.
4896%
4897*/
4898MagickExport Cache ReferencePixelCache(Cache cache)
4899{
4900 CacheInfo
4901 *cache_info;
4902
4903 assert(cache != (Cache *) NULL);
4904 cache_info=(CacheInfo *) cache;
4905 assert(cache_info->signature == MagickSignature);
4906 if (cache_info->debug != MagickFalse)
4907 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4908 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00004909 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004910 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004911 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004912 return(cache_info);
4913}
4914
4915/*
4916%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4917% %
4918% %
4919% %
4920+ S e t P i x e l C a c h e M e t h o d s %
4921% %
4922% %
4923% %
4924%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4925%
4926% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4927%
4928% The format of the SetPixelCacheMethods() method is:
4929%
4930% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4931%
4932% A description of each parameter follows:
4933%
4934% o cache: the pixel cache.
4935%
4936% o cache_methods: Specifies a pointer to a CacheMethods structure.
4937%
4938*/
4939MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4940{
4941 CacheInfo
4942 *cache_info;
4943
4944 GetOneAuthenticPixelFromHandler
4945 get_one_authentic_pixel_from_handler;
4946
4947 GetOneVirtualPixelFromHandler
4948 get_one_virtual_pixel_from_handler;
4949
4950 /*
4951 Set cache pixel methods.
4952 */
4953 assert(cache != (Cache) NULL);
4954 assert(cache_methods != (CacheMethods *) NULL);
4955 cache_info=(CacheInfo *) cache;
4956 assert(cache_info->signature == MagickSignature);
4957 if (cache_info->debug != MagickFalse)
4958 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4959 cache_info->filename);
4960 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4961 cache_info->methods.get_virtual_pixel_handler=
4962 cache_methods->get_virtual_pixel_handler;
4963 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4964 cache_info->methods.destroy_pixel_handler=
4965 cache_methods->destroy_pixel_handler;
4966 if (cache_methods->get_virtual_indexes_from_handler !=
4967 (GetVirtualIndexesFromHandler) NULL)
4968 cache_info->methods.get_virtual_indexes_from_handler=
4969 cache_methods->get_virtual_indexes_from_handler;
4970 if (cache_methods->get_authentic_pixels_handler !=
4971 (GetAuthenticPixelsHandler) NULL)
4972 cache_info->methods.get_authentic_pixels_handler=
4973 cache_methods->get_authentic_pixels_handler;
4974 if (cache_methods->queue_authentic_pixels_handler !=
4975 (QueueAuthenticPixelsHandler) NULL)
4976 cache_info->methods.queue_authentic_pixels_handler=
4977 cache_methods->queue_authentic_pixels_handler;
4978 if (cache_methods->sync_authentic_pixels_handler !=
4979 (SyncAuthenticPixelsHandler) NULL)
4980 cache_info->methods.sync_authentic_pixels_handler=
4981 cache_methods->sync_authentic_pixels_handler;
4982 if (cache_methods->get_authentic_pixels_from_handler !=
4983 (GetAuthenticPixelsFromHandler) NULL)
4984 cache_info->methods.get_authentic_pixels_from_handler=
4985 cache_methods->get_authentic_pixels_from_handler;
4986 if (cache_methods->get_authentic_indexes_from_handler !=
4987 (GetAuthenticIndexesFromHandler) NULL)
4988 cache_info->methods.get_authentic_indexes_from_handler=
4989 cache_methods->get_authentic_indexes_from_handler;
4990 get_one_virtual_pixel_from_handler=
4991 cache_info->methods.get_one_virtual_pixel_from_handler;
4992 if (get_one_virtual_pixel_from_handler !=
4993 (GetOneVirtualPixelFromHandler) NULL)
4994 cache_info->methods.get_one_virtual_pixel_from_handler=
4995 cache_methods->get_one_virtual_pixel_from_handler;
4996 get_one_authentic_pixel_from_handler=
4997 cache_methods->get_one_authentic_pixel_from_handler;
4998 if (get_one_authentic_pixel_from_handler !=
4999 (GetOneAuthenticPixelFromHandler) NULL)
5000 cache_info->methods.get_one_authentic_pixel_from_handler=
5001 cache_methods->get_one_authentic_pixel_from_handler;
5002}
5003
5004/*
5005%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5006% %
5007% %
5008% %
5009+ S e t P i x e l C a c h e N e x u s P i x e l s %
5010% %
5011% %
5012% %
5013%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5014%
5015% SetPixelCacheNexusPixels() defines the region of the cache for the
5016% specified cache nexus.
5017%
5018% The format of the SetPixelCacheNexusPixels() method is:
5019%
5020% PixelPacket SetPixelCacheNexusPixels(const Image *image,
5021% const RectangleInfo *region,NexusInfo *nexus_info,
5022% ExceptionInfo *exception)
5023%
5024% A description of each parameter follows:
5025%
5026% o image: the image.
5027%
5028% o region: A pointer to the RectangleInfo structure that defines the
5029% region of this particular cache nexus.
5030%
5031% o nexus_info: the cache nexus to set.
5032%
5033% o exception: return any errors or warnings in this structure.
5034%
5035*/
5036static PixelPacket *SetPixelCacheNexusPixels(const Image *image,
5037 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
5038{
5039 CacheInfo
5040 *cache_info;
5041
5042 MagickBooleanType
5043 status;
5044
cristy3ed852e2009-09-05 21:47:34 +00005045 MagickSizeType
5046 length,
5047 number_pixels;
5048
5049 if (image->debug != MagickFalse)
5050 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5051 cache_info=(CacheInfo *) image->cache;
5052 assert(cache_info->signature == MagickSignature);
5053 if (cache_info->type == UndefinedCache)
5054 return((PixelPacket *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00005055 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00005056 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
5057 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00005058 {
cristybb503372010-05-27 20:51:26 +00005059 ssize_t
cristybad067a2010-02-15 17:20:55 +00005060 x,
5061 y;
cristy3ed852e2009-09-05 21:47:34 +00005062
cristyeaedf062010-05-29 22:36:02 +00005063 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
5064 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00005065 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5066 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristy731c3532010-02-15 15:40:03 +00005067 ((nexus_info->region.height == 1UL) ||
5068 ((nexus_info->region.x == 0) &&
5069 ((nexus_info->region.width == cache_info->columns) ||
5070 ((nexus_info->region.width % cache_info->columns) == 0)))))
5071 {
5072 MagickOffsetType
5073 offset;
5074
5075 /*
5076 Pixels are accessed directly from memory.
5077 */
5078 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5079 nexus_info->region.x;
5080 nexus_info->pixels=cache_info->pixels+offset;
5081 nexus_info->indexes=(IndexPacket *) NULL;
5082 if (cache_info->active_index_channel != MagickFalse)
5083 nexus_info->indexes=cache_info->indexes+offset;
5084 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00005085 }
5086 }
5087 /*
5088 Pixels are stored in a cache region until they are synced to the cache.
5089 */
5090 number_pixels=(MagickSizeType) nexus_info->region.width*
5091 nexus_info->region.height;
5092 length=number_pixels*sizeof(PixelPacket);
5093 if (cache_info->active_index_channel != MagickFalse)
5094 length+=number_pixels*sizeof(IndexPacket);
5095 if (nexus_info->cache == (PixelPacket *) NULL)
5096 {
5097 nexus_info->length=length;
5098 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5099 if (status == MagickFalse)
5100 return((PixelPacket *) NULL);
5101 }
5102 else
5103 if (nexus_info->length != length)
5104 {
5105 RelinquishCacheNexusPixels(nexus_info);
5106 nexus_info->length=length;
5107 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5108 if (status == MagickFalse)
5109 return((PixelPacket *) NULL);
5110 }
5111 nexus_info->pixels=nexus_info->cache;
5112 nexus_info->indexes=(IndexPacket *) NULL;
5113 if (cache_info->active_index_channel != MagickFalse)
5114 nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
5115 return(nexus_info->pixels);
5116}
5117
5118/*
5119%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5120% %
5121% %
5122% %
5123% 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 %
5124% %
5125% %
5126% %
5127%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5128%
5129% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5130% pixel cache and returns the previous setting. A virtual pixel is any pixel
5131% access that is outside the boundaries of the image cache.
5132%
5133% The format of the SetPixelCacheVirtualMethod() method is:
5134%
5135% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5136% const VirtualPixelMethod virtual_pixel_method)
5137%
5138% A description of each parameter follows:
5139%
5140% o image: the image.
5141%
5142% o virtual_pixel_method: choose the type of virtual pixel.
5143%
5144*/
5145MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5146 const VirtualPixelMethod virtual_pixel_method)
5147{
5148 CacheInfo
5149 *cache_info;
5150
5151 VirtualPixelMethod
5152 method;
5153
5154 assert(image != (Image *) NULL);
5155 assert(image->signature == MagickSignature);
5156 if (image->debug != MagickFalse)
5157 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5158 assert(image->cache != (Cache) NULL);
5159 cache_info=(CacheInfo *) image->cache;
5160 assert(cache_info->signature == MagickSignature);
5161 method=cache_info->virtual_pixel_method;
5162 cache_info->virtual_pixel_method=virtual_pixel_method;
5163 return(method);
5164}
5165
5166/*
5167%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5168% %
5169% %
5170% %
5171+ 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 %
5172% %
5173% %
5174% %
5175%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5176%
5177% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5178% in-memory or disk cache. The method returns MagickTrue if the pixel region
5179% is synced, otherwise MagickFalse.
5180%
5181% The format of the SyncAuthenticPixelCacheNexus() method is:
5182%
5183% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5184% NexusInfo *nexus_info,ExceptionInfo *exception)
5185%
5186% A description of each parameter follows:
5187%
5188% o image: the image.
5189%
5190% o nexus_info: the cache nexus to sync.
5191%
5192% o exception: return any errors or warnings in this structure.
5193%
5194*/
5195MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5196 NexusInfo *nexus_info,ExceptionInfo *exception)
5197{
5198 CacheInfo
5199 *cache_info;
5200
5201 MagickBooleanType
5202 status;
5203
5204 /*
5205 Transfer pixels to the cache.
5206 */
5207 assert(image != (Image *) NULL);
5208 assert(image->signature == MagickSignature);
5209 if (image->debug != MagickFalse)
5210 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5211 if (image->cache == (Cache) NULL)
5212 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5213 cache_info=(CacheInfo *) image->cache;
5214 if (cache_info->type == UndefinedCache)
5215 return(MagickFalse);
5216 if ((image->clip_mask != (Image *) NULL) &&
5217 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5218 return(MagickFalse);
5219 if ((image->mask != (Image *) NULL) &&
5220 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5221 return(MagickFalse);
5222 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5223 return(MagickTrue);
5224 assert(cache_info->signature == MagickSignature);
5225 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5226 if ((cache_info->active_index_channel != MagickFalse) &&
5227 (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
5228 return(MagickFalse);
5229 return(status);
5230}
5231
5232/*
5233%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5234% %
5235% %
5236% %
5237+ S y n c A u t h e n t i c P i x e l C a c h e %
5238% %
5239% %
5240% %
5241%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5242%
5243% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5244% or disk cache. The method returns MagickTrue if the pixel region is synced,
5245% otherwise MagickFalse.
5246%
5247% The format of the SyncAuthenticPixelsCache() method is:
5248%
5249% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5250% ExceptionInfo *exception)
5251%
5252% A description of each parameter follows:
5253%
5254% o image: the image.
5255%
5256% o exception: return any errors or warnings in this structure.
5257%
5258*/
5259static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5260 ExceptionInfo *exception)
5261{
5262 CacheInfo
5263 *cache_info;
5264
cristybb503372010-05-27 20:51:26 +00005265 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005266 id;
5267
5268 MagickBooleanType
5269 status;
5270
5271 cache_info=(CacheInfo *) image->cache;
5272 id=GetOpenMPThreadId();
cristybb503372010-05-27 20:51:26 +00005273 assert(id < (ssize_t) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00005274 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5275 exception);
5276 return(status);
5277}
5278
5279/*
5280%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5281% %
5282% %
5283% %
5284% S y n c A u t h e n t i c P i x e l s %
5285% %
5286% %
5287% %
5288%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5289%
5290% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5291% The method returns MagickTrue if the pixel region is flushed, otherwise
5292% MagickFalse.
5293%
5294% The format of the SyncAuthenticPixels() method is:
5295%
5296% MagickBooleanType SyncAuthenticPixels(Image *image,
5297% ExceptionInfo *exception)
5298%
5299% A description of each parameter follows:
5300%
5301% o image: the image.
5302%
5303% o exception: return any errors or warnings in this structure.
5304%
5305*/
5306MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5307 ExceptionInfo *exception)
5308{
5309 CacheInfo
5310 *cache_info;
5311
5312 assert(image != (Image *) NULL);
5313 assert(image->signature == MagickSignature);
5314 if (image->debug != MagickFalse)
5315 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5316 assert(image->cache != (Cache) NULL);
5317 cache_info=(CacheInfo *) image->cache;
5318 assert(cache_info->signature == MagickSignature);
5319 if (cache_info->methods.sync_authentic_pixels_handler ==
5320 (SyncAuthenticPixelsHandler) NULL)
5321 return(MagickFalse);
5322 return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
5323}
5324
5325/*
5326%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5327% %
5328% %
5329% %
5330+ W r i t e P i x e l C a c h e I n d e x e s %
5331% %
5332% %
5333% %
5334%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5335%
5336% WritePixelCacheIndexes() writes the colormap indexes to the specified
5337% region of the pixel cache.
5338%
5339% The format of the WritePixelCacheIndexes() method is:
5340%
5341% MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5342% NexusInfo *nexus_info,ExceptionInfo *exception)
5343%
5344% A description of each parameter follows:
5345%
5346% o cache_info: the pixel cache.
5347%
5348% o nexus_info: the cache nexus to write the colormap indexes.
5349%
5350% o exception: return any errors or warnings in this structure.
5351%
5352*/
5353static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5354 NexusInfo *nexus_info,ExceptionInfo *exception)
5355{
5356 MagickOffsetType
5357 count,
5358 offset;
5359
5360 MagickSizeType
5361 length,
5362 number_pixels;
5363
5364 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005365 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005366
cristybb503372010-05-27 20:51:26 +00005367 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005368 y;
5369
cristybb503372010-05-27 20:51:26 +00005370 size_t
cristy3ed852e2009-09-05 21:47:34 +00005371 rows;
5372
5373 if (cache_info->debug != MagickFalse)
5374 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
5375 cache_info->filename);
5376 if (cache_info->active_index_channel == MagickFalse)
5377 return(MagickFalse);
5378 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5379 return(MagickTrue);
5380 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5381 nexus_info->region.x;
5382 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
5383 rows=nexus_info->region.height;
5384 number_pixels=(MagickSizeType) length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005385 p=nexus_info->indexes;
5386 switch (cache_info->type)
5387 {
5388 case MemoryCache:
5389 case MapCache:
5390 {
5391 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005392 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005393
5394 /*
5395 Write indexes to memory.
5396 */
cristydd341db2010-03-04 19:06:38 +00005397 if ((cache_info->columns == nexus_info->region.width) &&
5398 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5399 {
5400 length=number_pixels;
5401 rows=1UL;
5402 }
cristy3ed852e2009-09-05 21:47:34 +00005403 q=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00005404 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005405 {
5406 (void) CopyMagickMemory(q,p,(size_t) length);
5407 p+=nexus_info->region.width;
5408 q+=cache_info->columns;
5409 }
5410 break;
5411 }
5412 case DiskCache:
5413 {
5414 /*
5415 Write indexes to disk.
5416 */
5417 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5418 {
5419 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5420 cache_info->cache_filename);
5421 return(MagickFalse);
5422 }
cristydd341db2010-03-04 19:06:38 +00005423 if ((cache_info->columns == nexus_info->region.width) &&
5424 (number_pixels < MagickMaxBufferExtent))
5425 {
5426 length=number_pixels;
5427 rows=1UL;
5428 }
cristy3ed852e2009-09-05 21:47:34 +00005429 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005430 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005431 {
5432 count=WritePixelCacheRegion(cache_info,cache_info->offset+number_pixels*
5433 sizeof(PixelPacket)+offset*sizeof(*p),length,
5434 (const unsigned char *) p);
5435 if ((MagickSizeType) count < length)
5436 break;
5437 p+=nexus_info->region.width;
5438 offset+=cache_info->columns;
5439 }
cristybb503372010-05-27 20:51:26 +00005440 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005441 {
5442 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5443 cache_info->cache_filename);
5444 return(MagickFalse);
5445 }
5446 break;
5447 }
5448 default:
5449 break;
5450 }
5451 if ((cache_info->debug != MagickFalse) &&
cristyecd0ab52010-05-30 14:59:20 +00005452 (QuantumTick((MagickOffsetType) nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005453 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005454 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005455 nexus_info->region.width,(double) nexus_info->region.height,(double)
5456 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005457 return(MagickTrue);
5458}
5459
5460/*
5461%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5462% %
5463% %
5464% %
5465+ W r i t e C a c h e P i x e l s %
5466% %
5467% %
5468% %
5469%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5470%
5471% WritePixelCachePixels() writes image pixels to the specified region of the
5472% pixel cache.
5473%
5474% The format of the WritePixelCachePixels() method is:
5475%
5476% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5477% NexusInfo *nexus_info,ExceptionInfo *exception)
5478%
5479% A description of each parameter follows:
5480%
5481% o cache_info: the pixel cache.
5482%
5483% o nexus_info: the cache nexus to write the pixels.
5484%
5485% o exception: return any errors or warnings in this structure.
5486%
5487*/
5488static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5489 NexusInfo *nexus_info,ExceptionInfo *exception)
5490{
5491 MagickOffsetType
5492 count,
5493 offset;
5494
5495 MagickSizeType
5496 length,
5497 number_pixels;
5498
cristy3ed852e2009-09-05 21:47:34 +00005499 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005500 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005501
cristybb503372010-05-27 20:51:26 +00005502 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005503 y;
5504
cristybb503372010-05-27 20:51:26 +00005505 size_t
cristy3ed852e2009-09-05 21:47:34 +00005506 rows;
5507
5508 if (cache_info->debug != MagickFalse)
5509 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
5510 cache_info->filename);
5511 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5512 return(MagickTrue);
5513 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5514 nexus_info->region.x;
5515 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
5516 rows=nexus_info->region.height;
5517 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005518 p=nexus_info->pixels;
5519 switch (cache_info->type)
5520 {
5521 case MemoryCache:
5522 case MapCache:
5523 {
5524 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005525 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005526
5527 /*
5528 Write pixels to memory.
5529 */
cristydd341db2010-03-04 19:06:38 +00005530 if ((cache_info->columns == nexus_info->region.width) &&
5531 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5532 {
5533 length=number_pixels;
5534 rows=1UL;
5535 }
cristy3ed852e2009-09-05 21:47:34 +00005536 q=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00005537 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005538 {
5539 (void) CopyMagickMemory(q,p,(size_t) length);
5540 p+=nexus_info->region.width;
5541 q+=cache_info->columns;
5542 }
5543 break;
5544 }
5545 case DiskCache:
5546 {
5547 /*
5548 Write pixels to disk.
5549 */
5550 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5551 {
5552 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5553 cache_info->cache_filename);
5554 return(MagickFalse);
5555 }
cristydd341db2010-03-04 19:06:38 +00005556 if ((cache_info->columns == nexus_info->region.width) &&
5557 (number_pixels < MagickMaxBufferExtent))
5558 {
5559 length=number_pixels;
5560 rows=1UL;
5561 }
cristybb503372010-05-27 20:51:26 +00005562 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005563 {
5564 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5565 sizeof(*p),length,(const unsigned char *) p);
5566 if ((MagickSizeType) count < length)
5567 break;
5568 p+=nexus_info->region.width;
5569 offset+=cache_info->columns;
5570 }
cristybb503372010-05-27 20:51:26 +00005571 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005572 {
5573 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5574 cache_info->cache_filename);
5575 return(MagickFalse);
5576 }
5577 break;
5578 }
5579 default:
5580 break;
5581 }
5582 if ((cache_info->debug != MagickFalse) &&
cristyecd0ab52010-05-30 14:59:20 +00005583 (QuantumTick((MagickOffsetType) nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005584 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005585 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005586 nexus_info->region.width,(double) nexus_info->region.height,(double)
5587 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005588 return(MagickTrue);
5589}