blob: 9d320d7f2024166ca6f1e008cfcc5d2547e78dd8 [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
cristybb503372010-05-27 20:51:26 +0000119 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,PixelPacket *,
cristy3ed852e2009-09-05 21:47:34 +0000120 ExceptionInfo *),
121 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*/
cristybb503372010-05-27 20:51:26 +00002275MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,const ssize_t x,
2276 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,
cristybb503372010-05-27 20:51:26 +00002385 const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002386{
2387 CacheInfo
2388 *cache_info;
2389
2390 register const IndexPacket
2391 *indexes;
2392
2393 register const PixelPacket
2394 *p;
2395
2396 assert(image != (const Image *) NULL);
2397 assert(image->signature == MagickSignature);
2398 assert(image->cache != (Cache) NULL);
2399 cache_info=(CacheInfo *) image->cache;
2400 assert(cache_info->signature == MagickSignature);
2401 GetMagickPixelPacket(image,pixel);
2402 p=GetVirtualPixelCache(image,GetPixelCacheVirtualMethod(image),x,y,1,1,
2403 exception);
2404 if (p == (const PixelPacket *) NULL)
2405 return(MagickFalse);
2406 indexes=GetVirtualIndexQueue(image);
2407 SetMagickPixelPacket(image,p,indexes,pixel);
2408 return(MagickTrue);
2409}
2410
2411/*
2412%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2413% %
2414% %
2415% %
2416% G e t O n e V i r t u a l M e t h o d P i x e l %
2417% %
2418% %
2419% %
2420%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2421%
2422% GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2423% location as defined by specified pixel method. The image background color
2424% is returned if an error occurs. If you plan to modify the pixel, use
2425% GetOneAuthenticPixel() instead.
2426%
2427% The format of the GetOneVirtualMethodPixel() method is:
2428%
2429% MagickBooleanType GetOneVirtualMethodPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002430% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2431% const ssize_t y,Pixelpacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002432%
2433% A description of each parameter follows:
2434%
2435% o image: the image.
2436%
2437% o virtual_pixel_method: the virtual pixel method.
2438%
2439% o x,y: These values define the location of the pixel to return.
2440%
2441% o pixel: return a pixel at the specified (x,y) location.
2442%
2443% o exception: return any errors or warnings in this structure.
2444%
2445*/
2446MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002447 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002448 PixelPacket *pixel,ExceptionInfo *exception)
2449{
2450 GetOneVirtualPixelFromHandler
2451 get_one_virtual_pixel_from_handler;
2452
2453 CacheInfo
2454 *cache_info;
2455
2456 MagickBooleanType
2457 status;
2458
2459 assert(image != (const Image *) NULL);
2460 assert(image->signature == MagickSignature);
2461 assert(image->cache != (Cache) NULL);
2462 cache_info=(CacheInfo *) image->cache;
2463 assert(cache_info->signature == MagickSignature);
2464 *pixel=image->background_color;
2465 get_one_virtual_pixel_from_handler=
2466 cache_info->methods.get_one_virtual_pixel_from_handler;
2467 if (get_one_virtual_pixel_from_handler ==
2468 (GetOneVirtualPixelFromHandler) NULL)
2469 return(MagickFalse);
2470 status=get_one_virtual_pixel_from_handler(image,virtual_pixel_method,x,y,
2471 pixel,exception);
2472 return(status);
2473}
2474
2475/*
2476%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2477% %
2478% %
2479% %
2480% G e t O n e V i r t u a l P i x e l %
2481% %
2482% %
2483% %
2484%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2485%
2486% GetOneVirtualPixel() returns a single virtual pixel at the specified
2487% (x,y) location. The image background color is returned if an error occurs.
2488% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2489%
2490% The format of the GetOneVirtualPixel() method is:
2491%
cristybb503372010-05-27 20:51:26 +00002492% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2493% const ssize_t y,PixelPacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002494%
2495% A description of each parameter follows:
2496%
2497% o image: the image.
2498%
2499% o x,y: These values define the location of the pixel to return.
2500%
2501% o pixel: return a pixel at the specified (x,y) location.
2502%
2503% o exception: return any errors or warnings in this structure.
2504%
2505*/
2506MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002507 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002508{
2509 GetOneVirtualPixelFromHandler
2510 get_one_virtual_pixel_from_handler;
2511
2512 CacheInfo
2513 *cache_info;
2514
2515 MagickBooleanType
2516 status;
2517
2518 assert(image != (const Image *) NULL);
2519 assert(image->signature == MagickSignature);
2520 assert(image->cache != (Cache) NULL);
2521 cache_info=(CacheInfo *) image->cache;
2522 assert(cache_info->signature == MagickSignature);
2523 *pixel=image->background_color;
2524 get_one_virtual_pixel_from_handler=
2525 cache_info->methods.get_one_virtual_pixel_from_handler;
2526 if (get_one_virtual_pixel_from_handler ==
2527 (GetOneVirtualPixelFromHandler) NULL)
2528 return(MagickFalse);
2529 status=get_one_virtual_pixel_from_handler(image,GetPixelCacheVirtualMethod(
2530 image),x,y,pixel,exception);
2531 return(status);
2532}
2533
2534/*
2535%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2536% %
2537% %
2538% %
2539+ 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 %
2540% %
2541% %
2542% %
2543%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2544%
2545% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2546% specified (x,y) location. The image background color is returned if an
2547% error occurs.
2548%
2549% The format of the GetOneVirtualPixelFromCache() method is:
2550%
2551% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristybb503372010-05-27 20:51:26 +00002552% const VirtualPixelPacket method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002553% PixelPacket *pixel,ExceptionInfo *exception)
2554%
2555% A description of each parameter follows:
2556%
2557% o image: the image.
2558%
2559% o virtual_pixel_method: the virtual pixel method.
2560%
2561% o x,y: These values define the location of the pixel to return.
2562%
2563% o pixel: return a pixel at the specified (x,y) location.
2564%
2565% o exception: return any errors or warnings in this structure.
2566%
2567*/
2568static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002569 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002570 PixelPacket *pixel,ExceptionInfo *exception)
2571{
2572 const PixelPacket
2573 *pixels;
2574
2575 *pixel=image->background_color;
2576 pixels=GetVirtualPixelCache(image,virtual_pixel_method,x,y,1UL,1UL,exception);
2577 if (pixels == (const PixelPacket *) NULL)
2578 return(MagickFalse);
2579 *pixel=(*pixels);
2580 return(MagickTrue);
2581}
2582
2583/*
2584%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2585% %
2586% %
2587% %
2588+ G e t P i x e l C a c h e C o l o r s p a c e %
2589% %
2590% %
2591% %
2592%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2593%
2594% GetPixelCacheColorspace() returns the class type of the pixel cache.
2595%
2596% The format of the GetPixelCacheColorspace() method is:
2597%
2598% Colorspace GetPixelCacheColorspace(Cache cache)
2599%
2600% A description of each parameter follows:
2601%
2602% o cache: the pixel cache.
2603%
2604*/
2605MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
2606{
2607 CacheInfo
2608 *cache_info;
2609
2610 assert(cache != (Cache) NULL);
2611 cache_info=(CacheInfo *) cache;
2612 assert(cache_info->signature == MagickSignature);
2613 if (cache_info->debug != MagickFalse)
2614 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2615 cache_info->filename);
2616 return(cache_info->colorspace);
2617}
2618
2619/*
2620%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2621% %
2622% %
2623% %
2624+ G e t P i x e l C a c h e M e t h o d s %
2625% %
2626% %
2627% %
2628%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2629%
2630% GetPixelCacheMethods() initializes the CacheMethods structure.
2631%
2632% The format of the GetPixelCacheMethods() method is:
2633%
2634% void GetPixelCacheMethods(CacheMethods *cache_methods)
2635%
2636% A description of each parameter follows:
2637%
2638% o cache_methods: Specifies a pointer to a CacheMethods structure.
2639%
2640*/
2641MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
2642{
2643 assert(cache_methods != (CacheMethods *) NULL);
2644 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2645 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2646 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2647 cache_methods->get_virtual_indexes_from_handler=GetVirtualIndexesFromCache;
2648 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2649 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2650 cache_methods->get_authentic_indexes_from_handler=
2651 GetAuthenticIndexesFromCache;
2652 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2653 cache_methods->get_one_authentic_pixel_from_handler=
2654 GetOneAuthenticPixelFromCache;
2655 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2656 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2657 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2658}
2659
2660/*
2661%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2662% %
2663% %
2664% %
2665+ G e t P i x e l C a c h e N e x u s E x t e n t %
2666% %
2667% %
2668% %
2669%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2670%
2671% GetPixelCacheNexusExtent() returns the extent of the pixels associated with
2672% the last call to SetPixelCacheNexusPixels() or GetPixelCacheNexusPixels().
2673%
2674% The format of the GetPixelCacheNexusExtent() method is:
2675%
2676% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2677% NexusInfo *nexus_info)
2678%
2679% A description of each parameter follows:
2680%
2681% o nexus_info: the nexus info.
2682%
2683*/
2684MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2685 NexusInfo *nexus_info)
2686{
2687 CacheInfo
2688 *cache_info;
2689
2690 MagickSizeType
2691 extent;
2692
2693 if (cache == (Cache) NULL)
2694 return(0);
2695 cache_info=(CacheInfo *) cache;
2696 assert(cache_info->signature == MagickSignature);
2697 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2698 if (extent == 0)
2699 return((MagickSizeType) cache_info->columns*cache_info->rows);
2700 return(extent);
2701}
2702
2703/*
2704%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2705% %
2706% %
2707% %
2708+ 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 %
2709% %
2710% %
2711% %
2712%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2713%
2714% GetPixelCacheNexusIndexes() returns the indexes associated with the
2715% specified cache nexus.
2716%
2717% The format of the GetPixelCacheNexusIndexes() method is:
2718%
2719% IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2720% NexusInfo *nexus_info)
2721%
2722% A description of each parameter follows:
2723%
2724% o cache: the pixel cache.
2725%
2726% o nexus_info: the cache nexus to return the colormap indexes.
2727%
2728*/
2729MagickExport IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2730 NexusInfo *nexus_info)
2731{
2732 CacheInfo
2733 *cache_info;
2734
2735 if (cache == (Cache) NULL)
2736 return((IndexPacket *) NULL);
2737 cache_info=(CacheInfo *) cache;
2738 assert(cache_info->signature == MagickSignature);
2739 if (cache_info->storage_class == UndefinedClass)
2740 return((IndexPacket *) NULL);
2741 return(nexus_info->indexes);
2742}
2743
2744/*
2745%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2746% %
2747% %
2748% %
2749+ G e t P i x e l C a c h e N e x u s P i x e l s %
2750% %
2751% %
2752% %
2753%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2754%
2755% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2756% cache nexus.
2757%
2758% The format of the GetPixelCacheNexusPixels() method is:
2759%
2760% PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2761% NexusInfo *nexus_info)
2762%
2763% A description of each parameter follows:
2764%
2765% o cache: the pixel cache.
2766%
2767% o nexus_info: the cache nexus to return the pixels.
2768%
2769*/
2770MagickExport PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2771 NexusInfo *nexus_info)
2772{
2773 CacheInfo
2774 *cache_info;
2775
2776 if (cache == (Cache) NULL)
2777 return((PixelPacket *) NULL);
2778 cache_info=(CacheInfo *) cache;
2779 assert(cache_info->signature == MagickSignature);
2780 if (cache_info->debug != MagickFalse)
2781 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2782 cache_info->filename);
2783 if (cache_info->storage_class == UndefinedClass)
2784 return((PixelPacket *) NULL);
2785 return(nexus_info->pixels);
2786}
2787
2788/*
2789%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2790% %
2791% %
2792% %
cristy056ba772010-01-02 23:33:54 +00002793+ G e t P i x e l C a c h e P i x e l s %
2794% %
2795% %
2796% %
2797%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2798%
2799% GetPixelCachePixels() returns the pixels associated with the specified image.
2800%
2801% The format of the GetPixelCachePixels() method is:
2802%
cristyf84a1932010-01-03 18:00:18 +00002803% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2804% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002805%
2806% A description of each parameter follows:
2807%
2808% o image: the image.
2809%
2810% o length: the pixel cache length.
2811%
cristyf84a1932010-01-03 18:00:18 +00002812% o exception: return any errors or warnings in this structure.
2813%
cristy056ba772010-01-02 23:33:54 +00002814*/
cristyf84a1932010-01-03 18:00:18 +00002815MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2816 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002817{
2818 CacheInfo
2819 *cache_info;
2820
2821 assert(image != (const Image *) NULL);
2822 assert(image->signature == MagickSignature);
2823 if (image->debug != MagickFalse)
2824 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2825 assert(image->cache != (Cache) NULL);
cristyc4c8d132010-01-07 01:58:38 +00002826 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
cristy056ba772010-01-02 23:33:54 +00002827 assert(cache_info->signature == MagickSignature);
2828 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002829 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002830 return((void *) NULL);
2831 *length=cache_info->length;
2832 return((void *) cache_info->pixels);
2833}
2834
2835/*
2836%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2837% %
2838% %
2839% %
cristyb32b90a2009-09-07 21:45:48 +00002840+ 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 +00002841% %
2842% %
2843% %
2844%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2845%
2846% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2847%
2848% The format of the GetPixelCacheStorageClass() method is:
2849%
2850% ClassType GetPixelCacheStorageClass(Cache cache)
2851%
2852% A description of each parameter follows:
2853%
2854% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2855%
2856% o cache: the pixel cache.
2857%
2858*/
2859MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
2860{
2861 CacheInfo
2862 *cache_info;
2863
2864 assert(cache != (Cache) NULL);
2865 cache_info=(CacheInfo *) cache;
2866 assert(cache_info->signature == MagickSignature);
2867 if (cache_info->debug != MagickFalse)
2868 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2869 cache_info->filename);
2870 return(cache_info->storage_class);
2871}
2872
2873/*
2874%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2875% %
2876% %
2877% %
cristyb32b90a2009-09-07 21:45:48 +00002878+ G e t P i x e l C a c h e T i l e S i z e %
2879% %
2880% %
2881% %
2882%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2883%
2884% GetPixelCacheTileSize() returns the pixel cache tile size.
2885%
2886% The format of the GetPixelCacheTileSize() method is:
2887%
cristybb503372010-05-27 20:51:26 +00002888% void GetPixelCacheTileSize(const Image *image,size_t *width,
2889% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002890%
2891% A description of each parameter follows:
2892%
2893% o image: the image.
2894%
2895% o width: the optimize cache tile width in pixels.
2896%
2897% o height: the optimize cache tile height in pixels.
2898%
2899*/
cristybb503372010-05-27 20:51:26 +00002900MagickExport void GetPixelCacheTileSize(const Image *image,size_t *width,
2901 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002902{
2903 CacheInfo
2904 *cache_info;
2905
2906 assert(image != (Image *) NULL);
2907 assert(image->signature == MagickSignature);
2908 if (image->debug != MagickFalse)
2909 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2910 assert(image->cache != (Cache) NULL);
2911 cache_info=(CacheInfo *) image->cache;
2912 assert(cache_info->signature == MagickSignature);
2913 *width=2048UL/sizeof(PixelPacket);
2914 if (GetPixelCacheType(image) == DiskCache)
cristydaa97692009-09-13 02:10:35 +00002915 *width=8192UL/sizeof(PixelPacket);
cristyb32b90a2009-09-07 21:45:48 +00002916 *height=(*width);
2917}
2918
2919/*
2920%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2921% %
2922% %
2923% %
2924+ G e t P i x e l C a c h e T y p e %
2925% %
2926% %
2927% %
2928%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2929%
2930% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2931%
2932% The format of the GetPixelCacheType() method is:
2933%
2934% CacheType GetPixelCacheType(const Image *image)
2935%
2936% A description of each parameter follows:
2937%
2938% o image: the image.
2939%
2940*/
2941MagickExport CacheType GetPixelCacheType(const Image *image)
2942{
2943 CacheInfo
2944 *cache_info;
2945
2946 assert(image != (Image *) NULL);
2947 assert(image->signature == MagickSignature);
2948 if (image->debug != MagickFalse)
2949 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2950 assert(image->cache != (Cache) NULL);
2951 cache_info=(CacheInfo *) image->cache;
2952 assert(cache_info->signature == MagickSignature);
2953 return(cache_info->type);
2954}
2955
2956/*
2957%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2958% %
2959% %
2960% %
cristy3ed852e2009-09-05 21:47:34 +00002961+ 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 %
2962% %
2963% %
2964% %
2965%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2966%
2967% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2968% pixel cache. A virtual pixel is any pixel access that is outside the
2969% boundaries of the image cache.
2970%
2971% The format of the GetPixelCacheVirtualMethod() method is:
2972%
2973% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2974%
2975% A description of each parameter follows:
2976%
2977% o image: the image.
2978%
2979*/
2980MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2981{
2982 CacheInfo
2983 *cache_info;
2984
2985 assert(image != (Image *) NULL);
2986 assert(image->signature == MagickSignature);
2987 if (image->debug != MagickFalse)
2988 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2989 assert(image->cache != (Cache) NULL);
2990 cache_info=(CacheInfo *) image->cache;
2991 assert(cache_info->signature == MagickSignature);
2992 return(cache_info->virtual_pixel_method);
2993}
2994
2995/*
2996%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2997% %
2998% %
2999% %
3000+ 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 %
3001% %
3002% %
3003% %
3004%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3005%
3006% GetVirtualIndexesFromCache() returns the indexes associated with the last
3007% call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3008%
3009% The format of the GetVirtualIndexesFromCache() method is:
3010%
3011% IndexPacket *GetVirtualIndexesFromCache(const Image *image)
3012%
3013% A description of each parameter follows:
3014%
3015% o image: the image.
3016%
3017*/
3018static const IndexPacket *GetVirtualIndexesFromCache(const Image *image)
3019{
3020 CacheInfo
3021 *cache_info;
3022
3023 const IndexPacket
3024 *indexes;
3025
cristybb503372010-05-27 20:51:26 +00003026 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003027 id;
3028
3029 if (image->debug != MagickFalse)
3030 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3031 cache_info=(CacheInfo *) image->cache;
3032 id=GetOpenMPThreadId();
cristybb503372010-05-27 20:51:26 +00003033 assert(id < (ssize_t) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00003034 indexes=GetVirtualIndexesFromNexus(image->cache,cache_info->nexus_info[id]);
3035 return(indexes);
3036}
3037
3038/*
3039%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3040% %
3041% %
3042% %
3043+ G e t V i r t u a l I n d e x e s F r o m N e x u s %
3044% %
3045% %
3046% %
3047%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3048%
3049% GetVirtualIndexesFromNexus() returns the indexes associated with the
3050% specified cache nexus.
3051%
3052% The format of the GetVirtualIndexesFromNexus() method is:
3053%
3054% const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
3055% NexusInfo *nexus_info)
3056%
3057% A description of each parameter follows:
3058%
3059% o cache: the pixel cache.
3060%
3061% o nexus_info: the cache nexus to return the colormap indexes.
3062%
3063*/
3064MagickExport const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
3065 NexusInfo *nexus_info)
3066{
3067 CacheInfo
3068 *cache_info;
3069
3070 if (cache == (Cache) NULL)
3071 return((IndexPacket *) NULL);
3072 cache_info=(CacheInfo *) cache;
3073 assert(cache_info->signature == MagickSignature);
3074 if (cache_info->storage_class == UndefinedClass)
3075 return((IndexPacket *) NULL);
3076 return(nexus_info->indexes);
3077}
3078
3079/*
3080%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3081% %
3082% %
3083% %
3084% G e t V i r t u a l I n d e x Q u e u e %
3085% %
3086% %
3087% %
3088%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3089%
3090% GetVirtualIndexQueue() returns the virtual black channel or the
3091% colormap indexes associated with the last call to QueueAuthenticPixels() or
3092% GetVirtualPixels(). NULL is returned if the black channel or colormap
3093% indexes are not available.
3094%
3095% The format of the GetVirtualIndexQueue() method is:
3096%
3097% const IndexPacket *GetVirtualIndexQueue(const Image *image)
3098%
3099% A description of each parameter follows:
3100%
3101% o image: the image.
3102%
3103*/
3104MagickExport const IndexPacket *GetVirtualIndexQueue(const Image *image)
3105{
3106 CacheInfo
3107 *cache_info;
3108
3109 assert(image != (const Image *) NULL);
3110 assert(image->signature == MagickSignature);
3111 if (image->debug != MagickFalse)
3112 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3113 assert(image->cache != (Cache) NULL);
3114 cache_info=(CacheInfo *) image->cache;
3115 assert(cache_info->signature == MagickSignature);
3116 if (cache_info->methods.get_virtual_indexes_from_handler ==
3117 (GetVirtualIndexesFromHandler) NULL)
3118 return((IndexPacket *) NULL);
3119 return(cache_info->methods.get_virtual_indexes_from_handler(image));
3120}
3121
3122/*
3123%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3124% %
3125% %
3126% %
3127+ 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 %
3128% %
3129% %
3130% %
3131%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3132%
3133% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3134% pixel cache as defined by the geometry parameters. A pointer to the pixels
3135% is returned if the pixels are transferred, otherwise a NULL is returned.
3136%
3137% The format of the GetVirtualPixelsFromNexus() method is:
3138%
3139% PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003140% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00003141% const size_t columns,const size_t rows,NexusInfo *nexus_info,
3142% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003143%
3144% A description of each parameter follows:
3145%
3146% o image: the image.
3147%
3148% o virtual_pixel_method: the virtual pixel method.
3149%
3150% o x,y,columns,rows: These values define the perimeter of a region of
3151% pixels.
3152%
3153% o nexus_info: the cache nexus to acquire.
3154%
3155% o exception: return any errors or warnings in this structure.
3156%
3157*/
3158
cristybb503372010-05-27 20:51:26 +00003159static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003160 DitherMatrix[64] =
3161 {
3162 0, 48, 12, 60, 3, 51, 15, 63,
3163 32, 16, 44, 28, 35, 19, 47, 31,
3164 8, 56, 4, 52, 11, 59, 7, 55,
3165 40, 24, 36, 20, 43, 27, 39, 23,
3166 2, 50, 14, 62, 1, 49, 13, 61,
3167 34, 18, 46, 30, 33, 17, 45, 29,
3168 10, 58, 6, 54, 9, 57, 5, 53,
3169 42, 26, 38, 22, 41, 25, 37, 21
3170 };
3171
cristybb503372010-05-27 20:51:26 +00003172static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003173{
cristybb503372010-05-27 20:51:26 +00003174 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003175 index;
3176
3177 index=x+DitherMatrix[x & 0x07]-32L;
3178 if (index < 0L)
3179 return(0L);
cristybb503372010-05-27 20:51:26 +00003180 if (index >= (ssize_t) columns)
3181 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00003182 return(index);
3183}
3184
cristybb503372010-05-27 20:51:26 +00003185static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003186{
cristybb503372010-05-27 20:51:26 +00003187 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003188 index;
3189
3190 index=y+DitherMatrix[y & 0x07]-32L;
3191 if (index < 0L)
3192 return(0L);
cristybb503372010-05-27 20:51:26 +00003193 if (index >= (ssize_t) rows)
3194 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00003195 return(index);
3196}
3197
cristybb503372010-05-27 20:51:26 +00003198static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003199{
3200 if (x < 0L)
3201 return(0L);
cristybb503372010-05-27 20:51:26 +00003202 if (x >= (ssize_t) columns)
3203 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003204 return(x);
3205}
3206
cristybb503372010-05-27 20:51:26 +00003207static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003208{
3209 if (y < 0L)
3210 return(0L);
cristybb503372010-05-27 20:51:26 +00003211 if (y >= (ssize_t) rows)
3212 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003213 return(y);
3214}
3215
cristybb503372010-05-27 20:51:26 +00003216static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003217{
cristybb503372010-05-27 20:51:26 +00003218 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003219}
3220
cristybb503372010-05-27 20:51:26 +00003221static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003222{
cristybb503372010-05-27 20:51:26 +00003223 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003224}
3225
3226/*
3227 VirtualPixelModulo() computes the remainder of dividing offset by extent. It
3228 returns not only the quotient (tile the offset falls in) but also the positive
3229 remainer within that tile such that 0 <= remainder < extent. This method is
3230 essentially a ldiv() using a floored modulo division rather than the normal
3231 default truncated modulo division.
3232*/
cristybb503372010-05-27 20:51:26 +00003233static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3234 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003235{
3236 MagickModulo
3237 modulo;
3238
cristybb503372010-05-27 20:51:26 +00003239 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003240 if (offset < 0L)
3241 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003242 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003243 return(modulo);
3244}
3245
3246MagickExport const PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003247 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3248 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003249 ExceptionInfo *exception)
3250{
3251 CacheInfo
3252 *cache_info;
3253
cristyc3ec0d42010-04-07 01:18:08 +00003254 IndexPacket
3255 virtual_index;
3256
cristy3ed852e2009-09-05 21:47:34 +00003257 MagickOffsetType
3258 offset;
3259
3260 MagickSizeType
3261 length,
3262 number_pixels;
3263
3264 NexusInfo
3265 **virtual_nexus;
3266
3267 PixelPacket
3268 *pixels,
3269 virtual_pixel;
3270
3271 RectangleInfo
3272 region;
3273
3274 register const IndexPacket
cristyc3ec0d42010-04-07 01:18:08 +00003275 *restrict virtual_indexes;
cristy3ed852e2009-09-05 21:47:34 +00003276
3277 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003278 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003279
3280 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003281 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003282
cristybb503372010-05-27 20:51:26 +00003283 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003284 u,
3285 v;
3286
3287 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003288 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003289
3290 /*
3291 Acquire pixels.
3292 */
3293 if (image->debug != MagickFalse)
3294 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3295 cache_info=(CacheInfo *) image->cache;
cristy4cfbb3f2010-03-14 20:40:23 +00003296 if (cache_info->type == UndefinedCache)
cristy3ed852e2009-09-05 21:47:34 +00003297 return((const PixelPacket *) NULL);
3298 region.x=x;
3299 region.y=y;
3300 region.width=columns;
3301 region.height=rows;
3302 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
3303 if (pixels == (PixelPacket *) NULL)
3304 return((const PixelPacket *) NULL);
cristydf415c82010-03-11 16:47:50 +00003305 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3306 nexus_info->region.x;
3307 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3308 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003309 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3310 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003311 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3312 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003313 {
3314 MagickBooleanType
3315 status;
3316
3317 /*
3318 Pixel request is inside cache extents.
3319 */
3320 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
3321 return(pixels);
3322 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3323 if (status == MagickFalse)
3324 return((const PixelPacket *) NULL);
3325 if ((cache_info->storage_class == PseudoClass) ||
3326 (cache_info->colorspace == CMYKColorspace))
3327 {
3328 status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
3329 if (status == MagickFalse)
3330 return((const PixelPacket *) NULL);
3331 }
3332 return(pixels);
3333 }
3334 /*
3335 Pixel request is outside cache extents.
3336 */
3337 q=pixels;
3338 indexes=GetPixelCacheNexusIndexes(cache_info,nexus_info);
3339 virtual_nexus=AcquirePixelCacheNexus(1);
3340 if (virtual_nexus == (NexusInfo **) NULL)
3341 {
3342 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3343 "UnableToGetCacheNexus","`%s'",image->filename);
3344 return((const PixelPacket *) NULL);
3345 }
3346 switch (virtual_pixel_method)
3347 {
3348 case BlackVirtualPixelMethod:
3349 {
cristy4789f0d2010-01-10 00:01:06 +00003350 SetRedPixelComponent(&virtual_pixel,0);
3351 SetGreenPixelComponent(&virtual_pixel,0);
3352 SetBluePixelComponent(&virtual_pixel,0);
3353 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003354 break;
3355 }
3356 case GrayVirtualPixelMethod:
3357 {
cristy4789f0d2010-01-10 00:01:06 +00003358 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3359 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3360 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3361 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003362 break;
3363 }
3364 case TransparentVirtualPixelMethod:
3365 {
cristy4789f0d2010-01-10 00:01:06 +00003366 SetRedPixelComponent(&virtual_pixel,0);
3367 SetGreenPixelComponent(&virtual_pixel,0);
3368 SetBluePixelComponent(&virtual_pixel,0);
3369 SetOpacityPixelComponent(&virtual_pixel,TransparentOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003370 break;
3371 }
3372 case MaskVirtualPixelMethod:
3373 case WhiteVirtualPixelMethod:
3374 {
cristy4789f0d2010-01-10 00:01:06 +00003375 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3376 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3377 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3378 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003379 break;
3380 }
3381 default:
3382 {
3383 virtual_pixel=image->background_color;
3384 break;
3385 }
3386 }
cristyc3ec0d42010-04-07 01:18:08 +00003387 virtual_index=0;
cristybb503372010-05-27 20:51:26 +00003388 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003389 {
cristybb503372010-05-27 20:51:26 +00003390 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003391 {
3392 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003393 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
3394 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) || (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003395 {
3396 MagickModulo
3397 x_modulo,
3398 y_modulo;
3399
3400 /*
3401 Transfer a single pixel.
3402 */
3403 length=(MagickSizeType) 1;
3404 switch (virtual_pixel_method)
3405 {
3406 case BackgroundVirtualPixelMethod:
3407 case ConstantVirtualPixelMethod:
3408 case BlackVirtualPixelMethod:
3409 case GrayVirtualPixelMethod:
3410 case TransparentVirtualPixelMethod:
3411 case MaskVirtualPixelMethod:
3412 case WhiteVirtualPixelMethod:
3413 {
3414 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003415 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003416 break;
3417 }
3418 case EdgeVirtualPixelMethod:
3419 default:
3420 {
3421 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003422 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003423 1UL,1UL,virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003424 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3425 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003426 break;
3427 }
3428 case RandomVirtualPixelMethod:
3429 {
3430 if (cache_info->random_info == (RandomInfo *) NULL)
3431 cache_info->random_info=AcquireRandomInfo();
3432 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003433 RandomX(cache_info->random_info,cache_info->columns),
3434 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003435 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003436 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3437 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003438 break;
3439 }
3440 case DitherVirtualPixelMethod:
3441 {
3442 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003443 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003444 1UL,1UL,virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003445 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3446 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003447 break;
3448 }
3449 case TileVirtualPixelMethod:
3450 {
3451 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3452 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3453 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3454 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3455 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003456 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3457 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003458 break;
3459 }
3460 case MirrorVirtualPixelMethod:
3461 {
3462 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3463 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003464 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003465 x_modulo.remainder-1L;
3466 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3467 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003468 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003469 y_modulo.remainder-1L;
3470 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3471 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3472 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003473 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3474 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003475 break;
3476 }
3477 case CheckerTileVirtualPixelMethod:
3478 {
3479 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3480 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3481 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3482 {
3483 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003484 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003485 break;
3486 }
3487 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3488 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3489 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003490 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3491 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003492 break;
3493 }
3494 case HorizontalTileVirtualPixelMethod:
3495 {
cristybb503372010-05-27 20:51:26 +00003496 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003497 {
3498 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003499 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003500 break;
3501 }
3502 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3503 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3504 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3505 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3506 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003507 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3508 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003509 break;
3510 }
3511 case VerticalTileVirtualPixelMethod:
3512 {
cristybb503372010-05-27 20:51:26 +00003513 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
cristy3ed852e2009-09-05 21:47:34 +00003514 {
3515 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003516 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003517 break;
3518 }
3519 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3520 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3521 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3522 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3523 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003524 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3525 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003526 break;
3527 }
3528 case HorizontalTileEdgeVirtualPixelMethod:
3529 {
3530 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3531 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003532 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003533 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003534 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3535 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003536 break;
3537 }
3538 case VerticalTileEdgeVirtualPixelMethod:
3539 {
3540 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3541 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003542 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003543 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003544 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3545 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003546 break;
3547 }
3548 }
3549 if (p == (const PixelPacket *) NULL)
3550 break;
3551 *q++=(*p);
cristyc3ec0d42010-04-07 01:18:08 +00003552 if ((indexes != (IndexPacket *) NULL) &&
3553 (virtual_indexes != (const IndexPacket *) NULL))
3554 *indexes++=(*virtual_indexes);
cristy3ed852e2009-09-05 21:47:34 +00003555 continue;
3556 }
3557 /*
3558 Transfer a run of pixels.
3559 */
3560 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,
cristybb503372010-05-27 20:51:26 +00003561 (size_t) length,1UL,virtual_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003562 if (p == (const PixelPacket *) NULL)
3563 break;
cristyc3ec0d42010-04-07 01:18:08 +00003564 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003565 (void) CopyMagickMemory(q,p,(size_t) length*sizeof(*p));
3566 q+=length;
cristyc3ec0d42010-04-07 01:18:08 +00003567 if ((indexes != (IndexPacket *) NULL) &&
3568 (virtual_indexes != (const IndexPacket *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003569 {
cristyc3ec0d42010-04-07 01:18:08 +00003570 (void) CopyMagickMemory(indexes,virtual_indexes,(size_t) length*
3571 sizeof(*virtual_indexes));
3572 indexes+=length;
cristy3ed852e2009-09-05 21:47:34 +00003573 }
3574 }
3575 }
3576 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3577 return(pixels);
3578}
3579
3580/*
3581%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3582% %
3583% %
3584% %
3585+ G e t V i r t u a l P i x e l C a c h e %
3586% %
3587% %
3588% %
3589%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3590%
3591% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3592% cache as defined by the geometry parameters. A pointer to the pixels
3593% is returned if the pixels are transferred, otherwise a NULL is returned.
3594%
3595% The format of the GetVirtualPixelCache() method is:
3596%
3597% const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003598% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3599% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003600% ExceptionInfo *exception)
3601%
3602% A description of each parameter follows:
3603%
3604% o image: the image.
3605%
3606% o virtual_pixel_method: the virtual pixel method.
3607%
3608% o x,y,columns,rows: These values define the perimeter of a region of
3609% pixels.
3610%
3611% o exception: return any errors or warnings in this structure.
3612%
3613*/
3614static const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003615 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3616 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003617{
3618 CacheInfo
3619 *cache_info;
3620
3621 const PixelPacket
3622 *pixels;
3623
cristybb503372010-05-27 20:51:26 +00003624 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003625 id;
3626
3627 if (image->debug != MagickFalse)
3628 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3629 cache_info=(CacheInfo *) image->cache;
3630 id=GetOpenMPThreadId();
cristybb503372010-05-27 20:51:26 +00003631 assert(id < (ssize_t) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00003632 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3633 cache_info->nexus_info[id],exception);
3634 return(pixels);
3635}
3636
3637/*
3638%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3639% %
3640% %
3641% %
3642% G e t V i r t u a l P i x e l Q u e u e %
3643% %
3644% %
3645% %
3646%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3647%
3648% GetVirtualPixelQueue() returns the virtual pixels associated with the
3649% last call to QueueAuthenticPixels() or GetVirtualPixels().
3650%
3651% The format of the GetVirtualPixelQueue() method is:
3652%
3653% const PixelPacket *GetVirtualPixelQueue(const Image image)
3654%
3655% A description of each parameter follows:
3656%
3657% o image: the image.
3658%
3659*/
3660MagickExport const PixelPacket *GetVirtualPixelQueue(const Image *image)
3661{
3662 CacheInfo
3663 *cache_info;
3664
3665 assert(image != (const Image *) NULL);
3666 assert(image->signature == MagickSignature);
3667 if (image->debug != MagickFalse)
3668 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3669 assert(image->cache != (Cache) NULL);
3670 cache_info=(CacheInfo *) image->cache;
3671 assert(cache_info->signature == MagickSignature);
3672 if (cache_info->methods.get_virtual_pixels_handler ==
3673 (GetVirtualPixelsHandler) NULL)
3674 return((PixelPacket *) NULL);
3675 return(cache_info->methods.get_virtual_pixels_handler(image));
3676}
3677
3678/*
3679%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3680% %
3681% %
3682% %
3683% G e t V i r t u a l P i x e l s %
3684% %
3685% %
3686% %
3687%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3688%
3689% GetVirtualPixels() returns an immutable pixel region. If the
3690% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003691% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003692% copy of the pixels or it may point to the original pixels in memory.
3693% Performance is maximized if the selected region is part of one row, or one
3694% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003695% (without a copy) if the image is in memory, or in a memory-mapped file. The
3696% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003697%
3698% Pixels accessed via the returned pointer represent a simple array of type
3699% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
3700% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access
3701% the black color component or to obtain the colormap indexes (of type
3702% IndexPacket) corresponding to the region.
3703%
3704% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3705%
3706% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3707% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3708% GetCacheViewAuthenticPixels() instead.
3709%
3710% The format of the GetVirtualPixels() method is:
3711%
cristybb503372010-05-27 20:51:26 +00003712% const PixelPacket *GetVirtualPixels(const Image *image,const ssize_t x,
3713% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003714% ExceptionInfo *exception)
3715%
3716% A description of each parameter follows:
3717%
3718% o image: the image.
3719%
3720% o x,y,columns,rows: These values define the perimeter of a region of
3721% pixels.
3722%
3723% o exception: return any errors or warnings in this structure.
3724%
3725*/
3726MagickExport const PixelPacket *GetVirtualPixels(const Image *image,
cristybb503372010-05-27 20:51:26 +00003727 const ssize_t x,const ssize_t y,const size_t columns,
3728 const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003729{
3730 CacheInfo
3731 *cache_info;
3732
3733 const PixelPacket
3734 *pixels;
3735
3736 assert(image != (const Image *) NULL);
3737 assert(image->signature == MagickSignature);
3738 if (image->debug != MagickFalse)
3739 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3740 assert(image->cache != (Cache) NULL);
3741 cache_info=(CacheInfo *) image->cache;
3742 assert(cache_info->signature == MagickSignature);
3743 if (cache_info->methods.get_virtual_pixel_handler ==
3744 (GetVirtualPixelHandler) NULL)
3745 return((const PixelPacket *) NULL);
3746 pixels=cache_info->methods.get_virtual_pixel_handler(image,
3747 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception);
3748 return(pixels);
3749}
3750
3751/*
3752%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3753% %
3754% %
3755% %
3756+ 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 %
3757% %
3758% %
3759% %
3760%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3761%
3762% GetVirtualPixelsCache() returns the pixels associated with the last call
3763% to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3764%
3765% The format of the GetVirtualPixelsCache() method is:
3766%
3767% PixelPacket *GetVirtualPixelsCache(const Image *image)
3768%
3769% A description of each parameter follows:
3770%
3771% o image: the image.
3772%
3773*/
3774static const PixelPacket *GetVirtualPixelsCache(const Image *image)
3775{
3776 CacheInfo
3777 *cache_info;
3778
3779 const PixelPacket
3780 *pixels;
3781
cristybb503372010-05-27 20:51:26 +00003782 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003783 id;
3784
3785 if (image->debug != MagickFalse)
3786 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3787 cache_info=(CacheInfo *) image->cache;
3788 id=GetOpenMPThreadId();
cristybb503372010-05-27 20:51:26 +00003789 assert(id < (ssize_t) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00003790 pixels=GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]);
3791 return(pixels);
3792}
3793
3794/*
3795%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3796% %
3797% %
3798% %
3799+ G e t V i r t u a l P i x e l s N e x u s %
3800% %
3801% %
3802% %
3803%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3804%
3805% GetVirtualPixelsNexus() returns the pixels associated with the specified
3806% cache nexus.
3807%
3808% The format of the GetVirtualPixelsNexus() method is:
3809%
3810% const IndexPacket *GetVirtualPixelsNexus(const Cache cache,
3811% NexusInfo *nexus_info)
3812%
3813% A description of each parameter follows:
3814%
3815% o cache: the pixel cache.
3816%
3817% o nexus_info: the cache nexus to return the colormap pixels.
3818%
3819*/
3820MagickExport const PixelPacket *GetVirtualPixelsNexus(const Cache cache,
3821 NexusInfo *nexus_info)
3822{
3823 CacheInfo
3824 *cache_info;
3825
3826 if (cache == (Cache) NULL)
3827 return((PixelPacket *) NULL);
3828 cache_info=(CacheInfo *) cache;
3829 assert(cache_info->signature == MagickSignature);
3830 if (cache_info->storage_class == UndefinedClass)
3831 return((PixelPacket *) NULL);
3832 return((const PixelPacket *) nexus_info->pixels);
3833}
3834
3835/*
3836%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3837% %
3838% %
3839% %
3840+ M a s k P i x e l C a c h e N e x u s %
3841% %
3842% %
3843% %
3844%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3845%
3846% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3847% The method returns MagickTrue if the pixel region is masked, otherwise
3848% MagickFalse.
3849%
3850% The format of the MaskPixelCacheNexus() method is:
3851%
3852% MagickBooleanType MaskPixelCacheNexus(Image *image,
3853% NexusInfo *nexus_info,ExceptionInfo *exception)
3854%
3855% A description of each parameter follows:
3856%
3857% o image: the image.
3858%
3859% o nexus_info: the cache nexus to clip.
3860%
3861% o exception: return any errors or warnings in this structure.
3862%
3863*/
3864
3865static inline void MagickPixelCompositeMask(const MagickPixelPacket *p,
3866 const MagickRealType alpha,const MagickPixelPacket *q,
3867 const MagickRealType beta,MagickPixelPacket *composite)
3868{
3869 MagickRealType
3870 gamma;
3871
3872 if (alpha == TransparentOpacity)
3873 {
3874 *composite=(*q);
3875 return;
3876 }
3877 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3878 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3879 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3880 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3881 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3882 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3883 composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
3884}
3885
3886static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3887 ExceptionInfo *exception)
3888{
3889 CacheInfo
3890 *cache_info;
3891
3892 MagickPixelPacket
3893 alpha,
3894 beta;
3895
3896 MagickSizeType
3897 number_pixels;
3898
3899 NexusInfo
3900 **clip_nexus,
3901 **image_nexus;
3902
3903 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003904 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003905
3906 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003907 *restrict nexus_indexes,
3908 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003909
cristybb503372010-05-27 20:51:26 +00003910 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003911 i;
3912
3913 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003914 *restrict p,
3915 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003916
3917 /*
3918 Apply clip mask.
3919 */
3920 if (image->debug != MagickFalse)
3921 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3922 if (image->mask == (Image *) NULL)
3923 return(MagickFalse);
3924 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
3925 if (cache_info == (Cache) NULL)
3926 return(MagickFalse);
3927 image_nexus=AcquirePixelCacheNexus(1);
3928 clip_nexus=AcquirePixelCacheNexus(1);
3929 if ((image_nexus == (NexusInfo **) NULL) ||
3930 (clip_nexus == (NexusInfo **) NULL))
3931 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy09449f72010-01-23 03:08:36 +00003932 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,
3933 nexus_info->region.y,nexus_info->region.width,nexus_info->region.height,
3934 image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003935 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
3936 q=nexus_info->pixels;
3937 nexus_indexes=nexus_info->indexes;
3938 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3939 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3940 nexus_info->region.height,clip_nexus[0],&image->exception);
3941 GetMagickPixelPacket(image,&alpha);
3942 GetMagickPixelPacket(image,&beta);
3943 number_pixels=(MagickSizeType) nexus_info->region.width*
3944 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +00003945 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +00003946 {
3947 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
3948 break;
3949 SetMagickPixelPacket(image,p,indexes+i,&alpha);
3950 SetMagickPixelPacket(image,q,nexus_indexes+i,&beta);
3951 MagickPixelCompositeMask(&beta,(MagickRealType) PixelIntensityToQuantum(r),
3952 &alpha,alpha.opacity,&beta);
cristyce70c172010-01-07 17:15:30 +00003953 q->red=ClampToQuantum(beta.red);
3954 q->green=ClampToQuantum(beta.green);
3955 q->blue=ClampToQuantum(beta.blue);
3956 q->opacity=ClampToQuantum(beta.opacity);
cristy3ed852e2009-09-05 21:47:34 +00003957 if (cache_info->active_index_channel != MagickFalse)
3958 nexus_indexes[i]=indexes[i];
3959 p++;
3960 q++;
3961 r++;
3962 }
3963 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3964 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +00003965 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003966 return(MagickFalse);
3967 return(MagickTrue);
3968}
3969
3970/*
3971%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3972% %
3973% %
3974% %
3975+ O p e n P i x e l C a c h e %
3976% %
3977% %
3978% %
3979%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3980%
3981% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3982% dimensions, allocating space for the image pixels and optionally the
3983% colormap indexes, and memory mapping the cache if it is disk based. The
3984% cache nexus array is initialized as well.
3985%
3986% The format of the OpenPixelCache() method is:
3987%
3988% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3989% ExceptionInfo *exception)
3990%
3991% A description of each parameter follows:
3992%
3993% o image: the image.
3994%
3995% o mode: ReadMode, WriteMode, or IOMode.
3996%
3997% o exception: return any errors or warnings in this structure.
3998%
3999*/
4000
cristyd43a46b2010-01-21 02:13:41 +00004001static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00004002{
4003 cache_info->mapped=MagickFalse;
4004 cache_info->pixels=(PixelPacket *) AcquireMagickMemory((size_t)
4005 cache_info->length);
4006 if (cache_info->pixels == (PixelPacket *) NULL)
4007 {
4008 cache_info->mapped=MagickTrue;
4009 cache_info->pixels=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
4010 cache_info->length);
4011 }
4012}
4013
4014static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
4015{
4016 CacheInfo
4017 *cache_info;
4018
4019 MagickOffsetType
4020 count,
4021 extent,
4022 offset;
4023
4024 cache_info=(CacheInfo *) image->cache;
4025 if (image->debug != MagickFalse)
4026 {
4027 char
4028 format[MaxTextExtent],
4029 message[MaxTextExtent];
4030
cristyb9080c92009-12-01 20:13:26 +00004031 (void) FormatMagickSize(length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00004032 (void) FormatMagickString(message,MaxTextExtent,
cristy2ce15c92010-03-12 14:03:41 +00004033 "extend %s (%s[%d], disk, %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00004034 cache_info->cache_filename,cache_info->file,format);
4035 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4036 }
4037 if (length != (MagickSizeType) ((MagickOffsetType) length))
4038 return(MagickFalse);
4039 extent=(MagickOffsetType) MagickSeek(cache_info->file,0,SEEK_END);
4040 if (extent < 0)
4041 return(MagickFalse);
4042 if ((MagickSizeType) extent >= length)
4043 return(MagickTrue);
4044 offset=(MagickOffsetType) length-1;
4045 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
4046 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
4047}
4048
4049static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
4050 ExceptionInfo *exception)
4051{
4052 char
4053 format[MaxTextExtent],
4054 message[MaxTextExtent];
4055
4056 CacheInfo
4057 *cache_info,
4058 source_info;
4059
4060 MagickSizeType
4061 length,
4062 number_pixels;
4063
4064 MagickStatusType
4065 status;
4066
4067 size_t
4068 packet_size;
4069
cristybb503372010-05-27 20:51:26 +00004070 size_t
cristy3ed852e2009-09-05 21:47:34 +00004071 columns;
4072
4073 if (image->debug != MagickFalse)
4074 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4075 if ((image->columns == 0) || (image->rows == 0))
4076 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
4077 cache_info=(CacheInfo *) image->cache;
4078 source_info=(*cache_info);
4079 source_info.file=(-1);
cristyf1d91242010-05-28 02:23:19 +00004080 (void) FormatMagickString(cache_info->filename,MaxTextExtent,"%s[%lu]",
4081 image->filename,(unsigned long) GetImageIndexInList(image));
cristy87528ea2009-09-10 14:53:56 +00004082 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +00004083 cache_info->rows=image->rows;
4084 cache_info->columns=image->columns;
4085 cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
4086 (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
cristy73724512010-04-12 14:43:14 +00004087 if (image->ping != MagickFalse)
4088 {
4089 cache_info->storage_class=image->storage_class;
4090 cache_info->colorspace=image->colorspace;
4091 cache_info->type=PingCache;
4092 cache_info->pixels=(PixelPacket *) NULL;
4093 cache_info->indexes=(IndexPacket *) NULL;
4094 cache_info->length=0;
4095 return(MagickTrue);
4096 }
cristy3ed852e2009-09-05 21:47:34 +00004097 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4098 packet_size=sizeof(PixelPacket);
4099 if (cache_info->active_index_channel != MagickFalse)
4100 packet_size+=sizeof(IndexPacket);
4101 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00004102 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00004103 if (cache_info->columns != columns)
4104 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4105 image->filename);
4106 cache_info->length=length;
4107 status=AcquireMagickResource(AreaResource,cache_info->length);
4108 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4109 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4110 {
4111 status=AcquireMagickResource(MemoryResource,cache_info->length);
4112 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4113 (cache_info->type == MemoryCache))
4114 {
cristyd43a46b2010-01-21 02:13:41 +00004115 AllocatePixelCachePixels(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004116 if (cache_info->pixels == (PixelPacket *) NULL)
4117 cache_info->pixels=source_info.pixels;
4118 else
4119 {
4120 /*
4121 Create memory pixel cache.
4122 */
4123 if (image->debug != MagickFalse)
4124 {
cristy97e7a572009-12-05 15:07:53 +00004125 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004126 format);
cristy3ed852e2009-09-05 21:47:34 +00004127 (void) FormatMagickString(message,MaxTextExtent,
cristy2ce15c92010-03-12 14:03:41 +00004128 "open %s (%s memory, %lux%lu %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00004129 cache_info->mapped != MagickFalse ? "anonymous" : "heap",
cristyf1d91242010-05-28 02:23:19 +00004130 (unsigned long) cache_info->columns,(unsigned long)
4131 cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004132 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4133 message);
4134 }
4135 cache_info->storage_class=image->storage_class;
4136 cache_info->colorspace=image->colorspace;
4137 cache_info->type=MemoryCache;
4138 cache_info->indexes=(IndexPacket *) NULL;
4139 if (cache_info->active_index_channel != MagickFalse)
4140 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4141 number_pixels);
4142 if (source_info.storage_class != UndefinedClass)
4143 {
4144 status|=ClonePixelCachePixels(cache_info,&source_info,
4145 exception);
4146 RelinquishPixelCachePixels(&source_info);
4147 }
4148 return(MagickTrue);
4149 }
4150 }
4151 RelinquishMagickResource(MemoryResource,cache_info->length);
4152 }
4153 /*
4154 Create pixel cache on disk.
4155 */
4156 status=AcquireMagickResource(DiskResource,cache_info->length);
4157 if (status == MagickFalse)
4158 {
4159 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4160 "CacheResourcesExhausted","`%s'",image->filename);
4161 return(MagickFalse);
4162 }
4163 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4164 {
4165 RelinquishMagickResource(DiskResource,cache_info->length);
4166 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4167 image->filename);
4168 return(MagickFalse);
4169 }
4170 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4171 cache_info->length);
4172 if (status == MagickFalse)
4173 {
4174 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4175 image->filename);
4176 return(MagickFalse);
4177 }
4178 cache_info->storage_class=image->storage_class;
4179 cache_info->colorspace=image->colorspace;
4180 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4181 status=AcquireMagickResource(AreaResource,cache_info->length);
4182 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4183 cache_info->type=DiskCache;
4184 else
4185 {
4186 status=AcquireMagickResource(MapResource,cache_info->length);
4187 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4188 (cache_info->type != MemoryCache))
4189 cache_info->type=DiskCache;
4190 else
4191 {
4192 cache_info->pixels=(PixelPacket *) MapBlob(cache_info->file,mode,
4193 cache_info->offset,(size_t) cache_info->length);
4194 if (cache_info->pixels == (PixelPacket *) NULL)
4195 {
4196 cache_info->pixels=source_info.pixels;
4197 cache_info->type=DiskCache;
4198 }
4199 else
4200 {
4201 /*
4202 Create file-backed memory-mapped pixel cache.
4203 */
4204 (void) ClosePixelCacheOnDisk(cache_info);
4205 cache_info->type=MapCache;
4206 cache_info->mapped=MagickTrue;
4207 cache_info->indexes=(IndexPacket *) NULL;
4208 if (cache_info->active_index_channel != MagickFalse)
4209 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4210 number_pixels);
4211 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4212 {
4213 status=ClonePixelCachePixels(cache_info,&source_info,
4214 exception);
4215 RelinquishPixelCachePixels(&source_info);
4216 }
4217 if (image->debug != MagickFalse)
4218 {
cristy97e7a572009-12-05 15:07:53 +00004219 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004220 format);
cristy3ed852e2009-09-05 21:47:34 +00004221 (void) FormatMagickString(message,MaxTextExtent,
cristy2ce15c92010-03-12 14:03:41 +00004222 "open %s (%s[%d], memory-mapped, %lux%lu %sB)",
cristy3ed852e2009-09-05 21:47:34 +00004223 cache_info->filename,cache_info->cache_filename,
cristyf1d91242010-05-28 02:23:19 +00004224 cache_info->file,(unsigned long) cache_info->columns,
4225 (unsigned long) cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004226 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4227 message);
4228 }
4229 return(MagickTrue);
4230 }
4231 }
4232 RelinquishMagickResource(MapResource,cache_info->length);
4233 }
4234 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4235 {
4236 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4237 RelinquishPixelCachePixels(&source_info);
4238 }
4239 if (image->debug != MagickFalse)
4240 {
cristyb9080c92009-12-01 20:13:26 +00004241 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00004242 (void) FormatMagickString(message,MaxTextExtent,
cristy2ce15c92010-03-12 14:03:41 +00004243 "open %s (%s[%d], disk, %lux%lu %sB)",cache_info->filename,
cristyf2faecf2010-05-28 19:19:36 +00004244 cache_info->cache_filename,cache_info->file,(unsigned long)
4245 cache_info->columns,(unsigned long) cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004246 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4247 }
4248 return(MagickTrue);
4249}
4250
4251/*
4252%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4253% %
4254% %
4255% %
4256+ P e r s i s t P i x e l C a c h e %
4257% %
4258% %
4259% %
4260%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4261%
4262% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4263% persistent pixel cache is one that resides on disk and is not destroyed
4264% when the program exits.
4265%
4266% The format of the PersistPixelCache() method is:
4267%
4268% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4269% const MagickBooleanType attach,MagickOffsetType *offset,
4270% ExceptionInfo *exception)
4271%
4272% A description of each parameter follows:
4273%
4274% o image: the image.
4275%
4276% o filename: the persistent pixel cache filename.
4277%
cristy01b7eb02009-09-10 23:10:14 +00004278% o attach: A value other than zero initializes the persistent pixel
4279% cache.
4280%
cristy3ed852e2009-09-05 21:47:34 +00004281% o initialize: A value other than zero initializes the persistent pixel
4282% cache.
4283%
4284% o offset: the offset in the persistent cache to store pixels.
4285%
4286% o exception: return any errors or warnings in this structure.
4287%
4288*/
4289MagickExport MagickBooleanType PersistPixelCache(Image *image,
4290 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4291 ExceptionInfo *exception)
4292{
4293 CacheInfo
4294 *cache_info,
4295 *clone_info;
4296
4297 Image
4298 clone_image;
4299
cristybb503372010-05-27 20:51:26 +00004300 ssize_t
cristy688f07b2009-09-27 15:19:13 +00004301 page_size;
cristy3ed852e2009-09-05 21:47:34 +00004302
4303 MagickBooleanType
4304 status;
4305
4306 assert(image != (Image *) NULL);
4307 assert(image->signature == MagickSignature);
4308 if (image->debug != MagickFalse)
4309 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4310 assert(image->cache != (void *) NULL);
4311 assert(filename != (const char *) NULL);
4312 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004313 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004314 cache_info=(CacheInfo *) image->cache;
4315 assert(cache_info->signature == MagickSignature);
4316 if (attach != MagickFalse)
4317 {
4318 /*
cristy01b7eb02009-09-10 23:10:14 +00004319 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004320 */
4321 if (image->debug != MagickFalse)
4322 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4323 "attach persistent cache");
4324 (void) CopyMagickString(cache_info->cache_filename,filename,
4325 MaxTextExtent);
4326 cache_info->type=DiskCache;
4327 cache_info->offset=(*offset);
4328 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4329 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004330 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004331 return(MagickTrue);
4332 }
cristy01b7eb02009-09-10 23:10:14 +00004333 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4334 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004335 {
cristyf84a1932010-01-03 18:00:18 +00004336 LockSemaphoreInfo(cache_info->semaphore);
cristy09449f72010-01-23 03:08:36 +00004337 if ((cache_info->mode != ReadMode) &&
4338 (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004339 (cache_info->reference_count == 1))
4340 {
4341 int
4342 status;
4343
4344 /*
cristy01b7eb02009-09-10 23:10:14 +00004345 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004346 */
4347 status=rename(cache_info->cache_filename,filename);
4348 if (status == 0)
4349 {
4350 (void) CopyMagickString(cache_info->cache_filename,filename,
4351 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004352 *offset+=cache_info->length+page_size-(cache_info->length %
4353 page_size);
cristyf84a1932010-01-03 18:00:18 +00004354 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004355 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004356 if (image->debug != MagickFalse)
4357 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4358 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004359 return(MagickTrue);
4360 }
4361 }
cristyf84a1932010-01-03 18:00:18 +00004362 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004363 }
4364 /*
cristy01b7eb02009-09-10 23:10:14 +00004365 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004366 */
4367 clone_image=(*image);
4368 clone_info=(CacheInfo *) clone_image.cache;
4369 image->cache=ClonePixelCache(cache_info);
4370 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4371 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4372 cache_info->type=DiskCache;
4373 cache_info->offset=(*offset);
4374 cache_info=(CacheInfo *) image->cache;
4375 status=ClonePixelCacheNexus(cache_info,clone_info,exception);
4376 if (status != MagickFalse)
4377 {
4378 status=OpenPixelCache(image,IOMode,exception);
4379 if (status != MagickFalse)
4380 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
4381 }
cristy688f07b2009-09-27 15:19:13 +00004382 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004383 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4384 return(status);
4385}
4386
4387/*
4388%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4389% %
4390% %
4391% %
4392+ Q u e u e A u t h e n t i c N e x u s %
4393% %
4394% %
4395% %
4396%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4397%
4398% QueueAuthenticNexus() allocates an region to store image pixels as defined
4399% by the region rectangle and returns a pointer to the region. This region is
4400% subsequently transferred from the pixel cache with
4401% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4402% pixels are transferred, otherwise a NULL is returned.
4403%
4404% The format of the QueueAuthenticNexus() method is:
4405%
cristy5f959472010-05-27 22:19:46 +00004406% PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
4407% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004408% NexusInfo *nexus_info,ExceptionInfo *exception)
4409%
4410% A description of each parameter follows:
4411%
4412% o image: the image.
4413%
4414% o x,y,columns,rows: These values define the perimeter of a region of
4415% pixels.
4416%
4417% o nexus_info: the cache nexus to set.
4418%
4419% o exception: return any errors or warnings in this structure.
4420%
4421*/
cristybb503372010-05-27 20:51:26 +00004422MagickExport PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
4423 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004424 NexusInfo *nexus_info,ExceptionInfo *exception)
4425{
4426 CacheInfo
4427 *cache_info;
4428
4429 MagickOffsetType
4430 offset;
4431
4432 MagickSizeType
4433 number_pixels;
4434
4435 RectangleInfo
4436 region;
4437
4438 /*
4439 Validate pixel cache geometry.
4440 */
4441 cache_info=(CacheInfo *) image->cache;
4442 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4443 {
4444 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4445 "NoPixelsDefinedInCache","`%s'",image->filename);
4446 return((PixelPacket *) NULL);
4447 }
cristybb503372010-05-27 20:51:26 +00004448 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4449 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004450 {
4451 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4452 "PixelsAreNotAuthentic","`%s'",image->filename);
4453 return((PixelPacket *) NULL);
4454 }
4455 offset=(MagickOffsetType) y*cache_info->columns+x;
4456 if (offset < 0)
4457 return((PixelPacket *) NULL);
4458 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4459 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4460 if ((MagickSizeType) offset >= number_pixels)
4461 return((PixelPacket *) NULL);
4462 /*
4463 Return pixel cache.
4464 */
4465 region.x=x;
4466 region.y=y;
4467 region.width=columns;
4468 region.height=rows;
4469 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4470}
4471
4472/*
4473%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4474% %
4475% %
4476% %
4477+ 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 %
4478% %
4479% %
4480% %
4481%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4482%
4483% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4484% defined by the region rectangle and returns a pointer to the region. This
4485% region is subsequently transferred from the pixel cache with
4486% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4487% pixels are transferred, otherwise a NULL is returned.
4488%
4489% The format of the QueueAuthenticPixelsCache() method is:
4490%
cristybb503372010-05-27 20:51:26 +00004491% PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4492% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004493% ExceptionInfo *exception)
4494%
4495% A description of each parameter follows:
4496%
4497% o image: the image.
4498%
4499% o x,y,columns,rows: These values define the perimeter of a region of
4500% pixels.
4501%
4502% o exception: return any errors or warnings in this structure.
4503%
4504*/
cristybb503372010-05-27 20:51:26 +00004505static PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4506 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004507 ExceptionInfo *exception)
4508{
4509 CacheInfo
4510 *cache_info;
4511
cristybb503372010-05-27 20:51:26 +00004512 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004513 id;
4514
4515 PixelPacket
4516 *pixels;
4517
4518 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickFalse,exception);
4519 if (cache_info == (Cache) NULL)
4520 return((PixelPacket *) NULL);
4521 id=GetOpenMPThreadId();
cristybb503372010-05-27 20:51:26 +00004522 assert(id < (ssize_t) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00004523 pixels=QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4524 exception);
4525 return(pixels);
4526}
4527
4528/*
4529%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4530% %
4531% %
4532% %
4533% Q u e u e A u t h e n t i c P i x e l s %
4534% %
4535% %
4536% %
4537%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4538%
4539% QueueAuthenticPixels() queues a mutable pixel region. If the region is
4540% successfully intialized a pointer to a PixelPacket array representing the
4541% region is returned, otherwise NULL is returned. The returned pointer may
4542% point to a temporary working buffer for the pixels or it may point to the
4543% final location of the pixels in memory.
4544%
4545% Write-only access means that any existing pixel values corresponding to
4546% the region are ignored. This is useful if the initial image is being
4547% created from scratch, or if the existing pixel values are to be
4548% completely replaced without need to refer to their pre-existing values.
4549% The application is free to read and write the pixel buffer returned by
4550% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4551% initialize the pixel array values. Initializing pixel array values is the
4552% application's responsibility.
4553%
4554% Performance is maximized if the selected region is part of one row, or
4555% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004556% pixels in-place (without a copy) if the image is in memory, or in a
4557% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004558% by the user.
4559%
4560% Pixels accessed via the returned pointer represent a simple array of type
4561% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
4562% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
4563% the black color component or the colormap indexes (of type IndexPacket)
4564% corresponding to the region. Once the PixelPacket (and/or IndexPacket)
4565% array has been updated, the changes must be saved back to the underlying
4566% image using SyncAuthenticPixels() or they may be lost.
4567%
4568% The format of the QueueAuthenticPixels() method is:
4569%
cristy5f959472010-05-27 22:19:46 +00004570% PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4571% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004572% ExceptionInfo *exception)
4573%
4574% A description of each parameter follows:
4575%
4576% o image: the image.
4577%
4578% o x,y,columns,rows: These values define the perimeter of a region of
4579% pixels.
4580%
4581% o exception: return any errors or warnings in this structure.
4582%
4583*/
cristybb503372010-05-27 20:51:26 +00004584MagickExport PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4585 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004586 ExceptionInfo *exception)
4587{
4588 CacheInfo
4589 *cache_info;
4590
4591 PixelPacket
4592 *pixels;
4593
4594 assert(image != (Image *) NULL);
4595 assert(image->signature == MagickSignature);
4596 if (image->debug != MagickFalse)
4597 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4598 assert(image->cache != (Cache) NULL);
4599 cache_info=(CacheInfo *) image->cache;
4600 assert(cache_info->signature == MagickSignature);
4601 if (cache_info->methods.queue_authentic_pixels_handler ==
4602 (QueueAuthenticPixelsHandler) NULL)
4603 return((PixelPacket *) NULL);
4604 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4605 rows,exception);
4606 return(pixels);
4607}
4608
4609/*
4610%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4611% %
4612% %
4613% %
4614+ R e a d P i x e l C a c h e I n d e x e s %
4615% %
4616% %
4617% %
4618%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4619%
4620% ReadPixelCacheIndexes() reads colormap indexes from the specified region of
4621% the pixel cache.
4622%
4623% The format of the ReadPixelCacheIndexes() method is:
4624%
4625% MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4626% NexusInfo *nexus_info,ExceptionInfo *exception)
4627%
4628% A description of each parameter follows:
4629%
4630% o cache_info: the pixel cache.
4631%
4632% o nexus_info: the cache nexus to read the colormap indexes.
4633%
4634% o exception: return any errors or warnings in this structure.
4635%
4636*/
4637static MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4638 NexusInfo *nexus_info,ExceptionInfo *exception)
4639{
4640 MagickOffsetType
4641 count,
4642 offset;
4643
4644 MagickSizeType
4645 length,
4646 number_pixels;
4647
4648 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004649 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004650
cristybb503372010-05-27 20:51:26 +00004651 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004652 y;
4653
cristybb503372010-05-27 20:51:26 +00004654 size_t
cristy3ed852e2009-09-05 21:47:34 +00004655 rows;
4656
4657 if (cache_info->debug != MagickFalse)
4658 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4659 cache_info->filename);
4660 if (cache_info->active_index_channel == MagickFalse)
4661 return(MagickFalse);
4662 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4663 return(MagickTrue);
4664 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4665 nexus_info->region.x;
4666 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
4667 rows=nexus_info->region.height;
4668 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004669 q=nexus_info->indexes;
4670 switch (cache_info->type)
4671 {
4672 case MemoryCache:
4673 case MapCache:
4674 {
4675 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004676 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004677
4678 /*
4679 Read indexes from memory.
4680 */
cristydd341db2010-03-04 19:06:38 +00004681 if ((cache_info->columns == nexus_info->region.width) &&
4682 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4683 {
4684 length=number_pixels;
4685 rows=1UL;
4686 }
cristy3ed852e2009-09-05 21:47:34 +00004687 p=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00004688 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004689 {
4690 (void) CopyMagickMemory(q,p,(size_t) length);
4691 p+=cache_info->columns;
4692 q+=nexus_info->region.width;
4693 }
4694 break;
4695 }
4696 case DiskCache:
4697 {
4698 /*
4699 Read indexes from disk.
4700 */
4701 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4702 {
4703 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4704 cache_info->cache_filename);
4705 return(MagickFalse);
4706 }
cristydd341db2010-03-04 19:06:38 +00004707 if ((cache_info->columns == nexus_info->region.width) &&
4708 (number_pixels < MagickMaxBufferExtent))
4709 {
4710 length=number_pixels;
4711 rows=1UL;
4712 }
cristy3ed852e2009-09-05 21:47:34 +00004713 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004714 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004715 {
4716 count=ReadPixelCacheRegion(cache_info,cache_info->offset+number_pixels*
4717 sizeof(PixelPacket)+offset*sizeof(*q),length,(unsigned char *) q);
4718 if ((MagickSizeType) count < length)
4719 break;
4720 offset+=cache_info->columns;
4721 q+=nexus_info->region.width;
4722 }
cristybb503372010-05-27 20:51:26 +00004723 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004724 {
4725 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4726 cache_info->cache_filename);
4727 return(MagickFalse);
4728 }
4729 break;
4730 }
4731 default:
4732 break;
4733 }
4734 if ((cache_info->debug != MagickFalse) &&
4735 (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4736 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
cristyf1d91242010-05-28 02:23:19 +00004737 cache_info->filename,(unsigned long) nexus_info->region.width,
4738 (unsigned long) nexus_info->region.height,(long) nexus_info->region.x,
4739 (long) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004740 return(MagickTrue);
4741}
4742
4743/*
4744%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4745% %
4746% %
4747% %
4748+ R e a d P i x e l C a c h e P i x e l s %
4749% %
4750% %
4751% %
4752%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4753%
4754% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4755% cache.
4756%
4757% The format of the ReadPixelCachePixels() method is:
4758%
4759% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4760% NexusInfo *nexus_info,ExceptionInfo *exception)
4761%
4762% A description of each parameter follows:
4763%
4764% o cache_info: the pixel cache.
4765%
4766% o nexus_info: the cache nexus to read the pixels.
4767%
4768% o exception: return any errors or warnings in this structure.
4769%
4770*/
4771static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4772 NexusInfo *nexus_info,ExceptionInfo *exception)
4773{
4774 MagickOffsetType
4775 count,
4776 offset;
4777
4778 MagickSizeType
4779 length,
4780 number_pixels;
4781
cristybb503372010-05-27 20:51:26 +00004782 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004783 y;
4784
4785 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004786 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004787
cristybb503372010-05-27 20:51:26 +00004788 size_t
cristy3ed852e2009-09-05 21:47:34 +00004789 rows;
4790
4791 if (cache_info->debug != MagickFalse)
4792 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4793 cache_info->filename);
4794 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4795 return(MagickTrue);
4796 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4797 nexus_info->region.x;
4798 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
4799 rows=nexus_info->region.height;
4800 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004801 q=nexus_info->pixels;
4802 switch (cache_info->type)
4803 {
4804 case MemoryCache:
4805 case MapCache:
4806 {
4807 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004808 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004809
4810 /*
4811 Read pixels from memory.
4812 */
cristydd341db2010-03-04 19:06:38 +00004813 if ((cache_info->columns == nexus_info->region.width) &&
4814 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4815 {
4816 length=number_pixels;
4817 rows=1UL;
4818 }
cristy3ed852e2009-09-05 21:47:34 +00004819 p=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00004820 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004821 {
4822 (void) CopyMagickMemory(q,p,(size_t) length);
4823 p+=cache_info->columns;
4824 q+=nexus_info->region.width;
4825 }
4826 break;
4827 }
4828 case DiskCache:
4829 {
4830 /*
4831 Read pixels from disk.
4832 */
4833 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4834 {
4835 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4836 cache_info->cache_filename);
4837 return(MagickFalse);
4838 }
cristydd341db2010-03-04 19:06:38 +00004839 if ((cache_info->columns == nexus_info->region.width) &&
4840 (number_pixels < MagickMaxBufferExtent))
4841 {
4842 length=number_pixels;
4843 rows=1UL;
4844 }
cristybb503372010-05-27 20:51:26 +00004845 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004846 {
4847 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4848 sizeof(*q),length,(unsigned char *) q);
4849 if ((MagickSizeType) count < length)
4850 break;
4851 offset+=cache_info->columns;
4852 q+=nexus_info->region.width;
4853 }
cristybb503372010-05-27 20:51:26 +00004854 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004855 {
4856 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4857 cache_info->cache_filename);
4858 return(MagickFalse);
4859 }
4860 break;
4861 }
4862 default:
4863 break;
4864 }
4865 if ((cache_info->debug != MagickFalse) &&
4866 (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4867 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
cristyf1d91242010-05-28 02:23:19 +00004868 cache_info->filename,(unsigned long) nexus_info->region.width,
4869 (unsigned long) nexus_info->region.height,(long) nexus_info->region.x,
4870 (long) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004871 return(MagickTrue);
4872}
4873
4874/*
4875%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4876% %
4877% %
4878% %
4879+ R e f e r e n c e P i x e l C a c h e %
4880% %
4881% %
4882% %
4883%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4884%
4885% ReferencePixelCache() increments the reference count associated with the
4886% pixel cache returning a pointer to the cache.
4887%
4888% The format of the ReferencePixelCache method is:
4889%
4890% Cache ReferencePixelCache(Cache cache_info)
4891%
4892% A description of each parameter follows:
4893%
4894% o cache_info: the pixel cache.
4895%
4896*/
4897MagickExport Cache ReferencePixelCache(Cache cache)
4898{
4899 CacheInfo
4900 *cache_info;
4901
4902 assert(cache != (Cache *) NULL);
4903 cache_info=(CacheInfo *) cache;
4904 assert(cache_info->signature == MagickSignature);
4905 if (cache_info->debug != MagickFalse)
4906 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4907 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00004908 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004909 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004910 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004911 return(cache_info);
4912}
4913
4914/*
4915%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4916% %
4917% %
4918% %
4919+ S e t P i x e l C a c h e M e t h o d s %
4920% %
4921% %
4922% %
4923%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4924%
4925% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4926%
4927% The format of the SetPixelCacheMethods() method is:
4928%
4929% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4930%
4931% A description of each parameter follows:
4932%
4933% o cache: the pixel cache.
4934%
4935% o cache_methods: Specifies a pointer to a CacheMethods structure.
4936%
4937*/
4938MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4939{
4940 CacheInfo
4941 *cache_info;
4942
4943 GetOneAuthenticPixelFromHandler
4944 get_one_authentic_pixel_from_handler;
4945
4946 GetOneVirtualPixelFromHandler
4947 get_one_virtual_pixel_from_handler;
4948
4949 /*
4950 Set cache pixel methods.
4951 */
4952 assert(cache != (Cache) NULL);
4953 assert(cache_methods != (CacheMethods *) NULL);
4954 cache_info=(CacheInfo *) cache;
4955 assert(cache_info->signature == MagickSignature);
4956 if (cache_info->debug != MagickFalse)
4957 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4958 cache_info->filename);
4959 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4960 cache_info->methods.get_virtual_pixel_handler=
4961 cache_methods->get_virtual_pixel_handler;
4962 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4963 cache_info->methods.destroy_pixel_handler=
4964 cache_methods->destroy_pixel_handler;
4965 if (cache_methods->get_virtual_indexes_from_handler !=
4966 (GetVirtualIndexesFromHandler) NULL)
4967 cache_info->methods.get_virtual_indexes_from_handler=
4968 cache_methods->get_virtual_indexes_from_handler;
4969 if (cache_methods->get_authentic_pixels_handler !=
4970 (GetAuthenticPixelsHandler) NULL)
4971 cache_info->methods.get_authentic_pixels_handler=
4972 cache_methods->get_authentic_pixels_handler;
4973 if (cache_methods->queue_authentic_pixels_handler !=
4974 (QueueAuthenticPixelsHandler) NULL)
4975 cache_info->methods.queue_authentic_pixels_handler=
4976 cache_methods->queue_authentic_pixels_handler;
4977 if (cache_methods->sync_authentic_pixels_handler !=
4978 (SyncAuthenticPixelsHandler) NULL)
4979 cache_info->methods.sync_authentic_pixels_handler=
4980 cache_methods->sync_authentic_pixels_handler;
4981 if (cache_methods->get_authentic_pixels_from_handler !=
4982 (GetAuthenticPixelsFromHandler) NULL)
4983 cache_info->methods.get_authentic_pixels_from_handler=
4984 cache_methods->get_authentic_pixels_from_handler;
4985 if (cache_methods->get_authentic_indexes_from_handler !=
4986 (GetAuthenticIndexesFromHandler) NULL)
4987 cache_info->methods.get_authentic_indexes_from_handler=
4988 cache_methods->get_authentic_indexes_from_handler;
4989 get_one_virtual_pixel_from_handler=
4990 cache_info->methods.get_one_virtual_pixel_from_handler;
4991 if (get_one_virtual_pixel_from_handler !=
4992 (GetOneVirtualPixelFromHandler) NULL)
4993 cache_info->methods.get_one_virtual_pixel_from_handler=
4994 cache_methods->get_one_virtual_pixel_from_handler;
4995 get_one_authentic_pixel_from_handler=
4996 cache_methods->get_one_authentic_pixel_from_handler;
4997 if (get_one_authentic_pixel_from_handler !=
4998 (GetOneAuthenticPixelFromHandler) NULL)
4999 cache_info->methods.get_one_authentic_pixel_from_handler=
5000 cache_methods->get_one_authentic_pixel_from_handler;
5001}
5002
5003/*
5004%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5005% %
5006% %
5007% %
5008+ S e t P i x e l C a c h e N e x u s P i x e l s %
5009% %
5010% %
5011% %
5012%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5013%
5014% SetPixelCacheNexusPixels() defines the region of the cache for the
5015% specified cache nexus.
5016%
5017% The format of the SetPixelCacheNexusPixels() method is:
5018%
5019% PixelPacket SetPixelCacheNexusPixels(const Image *image,
5020% const RectangleInfo *region,NexusInfo *nexus_info,
5021% ExceptionInfo *exception)
5022%
5023% A description of each parameter follows:
5024%
5025% o image: the image.
5026%
5027% o region: A pointer to the RectangleInfo structure that defines the
5028% region of this particular cache nexus.
5029%
5030% o nexus_info: the cache nexus to set.
5031%
5032% o exception: return any errors or warnings in this structure.
5033%
5034*/
5035static PixelPacket *SetPixelCacheNexusPixels(const Image *image,
5036 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
5037{
5038 CacheInfo
5039 *cache_info;
5040
5041 MagickBooleanType
5042 status;
5043
cristy3ed852e2009-09-05 21:47:34 +00005044 MagickSizeType
5045 length,
5046 number_pixels;
5047
5048 if (image->debug != MagickFalse)
5049 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5050 cache_info=(CacheInfo *) image->cache;
5051 assert(cache_info->signature == MagickSignature);
5052 if (cache_info->type == UndefinedCache)
5053 return((PixelPacket *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00005054 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00005055 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
5056 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00005057 {
cristybb503372010-05-27 20:51:26 +00005058 ssize_t
cristybad067a2010-02-15 17:20:55 +00005059 x,
5060 y;
cristy3ed852e2009-09-05 21:47:34 +00005061
cristyeaedf062010-05-29 22:36:02 +00005062 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
5063 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00005064 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5065 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristy731c3532010-02-15 15:40:03 +00005066 ((nexus_info->region.height == 1UL) ||
5067 ((nexus_info->region.x == 0) &&
5068 ((nexus_info->region.width == cache_info->columns) ||
5069 ((nexus_info->region.width % cache_info->columns) == 0)))))
5070 {
5071 MagickOffsetType
5072 offset;
5073
5074 /*
5075 Pixels are accessed directly from memory.
5076 */
5077 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5078 nexus_info->region.x;
5079 nexus_info->pixels=cache_info->pixels+offset;
5080 nexus_info->indexes=(IndexPacket *) NULL;
5081 if (cache_info->active_index_channel != MagickFalse)
5082 nexus_info->indexes=cache_info->indexes+offset;
5083 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00005084 }
5085 }
5086 /*
5087 Pixels are stored in a cache region until they are synced to the cache.
5088 */
5089 number_pixels=(MagickSizeType) nexus_info->region.width*
5090 nexus_info->region.height;
5091 length=number_pixels*sizeof(PixelPacket);
5092 if (cache_info->active_index_channel != MagickFalse)
5093 length+=number_pixels*sizeof(IndexPacket);
5094 if (nexus_info->cache == (PixelPacket *) NULL)
5095 {
5096 nexus_info->length=length;
5097 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5098 if (status == MagickFalse)
5099 return((PixelPacket *) NULL);
5100 }
5101 else
5102 if (nexus_info->length != length)
5103 {
5104 RelinquishCacheNexusPixels(nexus_info);
5105 nexus_info->length=length;
5106 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5107 if (status == MagickFalse)
5108 return((PixelPacket *) NULL);
5109 }
5110 nexus_info->pixels=nexus_info->cache;
5111 nexus_info->indexes=(IndexPacket *) NULL;
5112 if (cache_info->active_index_channel != MagickFalse)
5113 nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
5114 return(nexus_info->pixels);
5115}
5116
5117/*
5118%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5119% %
5120% %
5121% %
5122% 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 %
5123% %
5124% %
5125% %
5126%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5127%
5128% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5129% pixel cache and returns the previous setting. A virtual pixel is any pixel
5130% access that is outside the boundaries of the image cache.
5131%
5132% The format of the SetPixelCacheVirtualMethod() method is:
5133%
5134% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5135% const VirtualPixelMethod virtual_pixel_method)
5136%
5137% A description of each parameter follows:
5138%
5139% o image: the image.
5140%
5141% o virtual_pixel_method: choose the type of virtual pixel.
5142%
5143*/
5144MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5145 const VirtualPixelMethod virtual_pixel_method)
5146{
5147 CacheInfo
5148 *cache_info;
5149
5150 VirtualPixelMethod
5151 method;
5152
5153 assert(image != (Image *) NULL);
5154 assert(image->signature == MagickSignature);
5155 if (image->debug != MagickFalse)
5156 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5157 assert(image->cache != (Cache) NULL);
5158 cache_info=(CacheInfo *) image->cache;
5159 assert(cache_info->signature == MagickSignature);
5160 method=cache_info->virtual_pixel_method;
5161 cache_info->virtual_pixel_method=virtual_pixel_method;
5162 return(method);
5163}
5164
5165/*
5166%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5167% %
5168% %
5169% %
5170+ 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 %
5171% %
5172% %
5173% %
5174%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5175%
5176% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5177% in-memory or disk cache. The method returns MagickTrue if the pixel region
5178% is synced, otherwise MagickFalse.
5179%
5180% The format of the SyncAuthenticPixelCacheNexus() method is:
5181%
5182% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5183% NexusInfo *nexus_info,ExceptionInfo *exception)
5184%
5185% A description of each parameter follows:
5186%
5187% o image: the image.
5188%
5189% o nexus_info: the cache nexus to sync.
5190%
5191% o exception: return any errors or warnings in this structure.
5192%
5193*/
5194MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5195 NexusInfo *nexus_info,ExceptionInfo *exception)
5196{
5197 CacheInfo
5198 *cache_info;
5199
5200 MagickBooleanType
5201 status;
5202
5203 /*
5204 Transfer pixels to the cache.
5205 */
5206 assert(image != (Image *) NULL);
5207 assert(image->signature == MagickSignature);
5208 if (image->debug != MagickFalse)
5209 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5210 if (image->cache == (Cache) NULL)
5211 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5212 cache_info=(CacheInfo *) image->cache;
5213 if (cache_info->type == UndefinedCache)
5214 return(MagickFalse);
5215 if ((image->clip_mask != (Image *) NULL) &&
5216 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5217 return(MagickFalse);
5218 if ((image->mask != (Image *) NULL) &&
5219 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5220 return(MagickFalse);
5221 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5222 return(MagickTrue);
5223 assert(cache_info->signature == MagickSignature);
5224 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5225 if ((cache_info->active_index_channel != MagickFalse) &&
5226 (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
5227 return(MagickFalse);
5228 return(status);
5229}
5230
5231/*
5232%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5233% %
5234% %
5235% %
5236+ S y n c A u t h e n t i c P i x e l C a c h e %
5237% %
5238% %
5239% %
5240%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5241%
5242% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5243% or disk cache. The method returns MagickTrue if the pixel region is synced,
5244% otherwise MagickFalse.
5245%
5246% The format of the SyncAuthenticPixelsCache() method is:
5247%
5248% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5249% ExceptionInfo *exception)
5250%
5251% A description of each parameter follows:
5252%
5253% o image: the image.
5254%
5255% o exception: return any errors or warnings in this structure.
5256%
5257*/
5258static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5259 ExceptionInfo *exception)
5260{
5261 CacheInfo
5262 *cache_info;
5263
cristybb503372010-05-27 20:51:26 +00005264 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005265 id;
5266
5267 MagickBooleanType
5268 status;
5269
5270 cache_info=(CacheInfo *) image->cache;
5271 id=GetOpenMPThreadId();
cristybb503372010-05-27 20:51:26 +00005272 assert(id < (ssize_t) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00005273 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5274 exception);
5275 return(status);
5276}
5277
5278/*
5279%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5280% %
5281% %
5282% %
5283% S y n c A u t h e n t i c P i x e l s %
5284% %
5285% %
5286% %
5287%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5288%
5289% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5290% The method returns MagickTrue if the pixel region is flushed, otherwise
5291% MagickFalse.
5292%
5293% The format of the SyncAuthenticPixels() method is:
5294%
5295% MagickBooleanType SyncAuthenticPixels(Image *image,
5296% ExceptionInfo *exception)
5297%
5298% A description of each parameter follows:
5299%
5300% o image: the image.
5301%
5302% o exception: return any errors or warnings in this structure.
5303%
5304*/
5305MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5306 ExceptionInfo *exception)
5307{
5308 CacheInfo
5309 *cache_info;
5310
5311 assert(image != (Image *) NULL);
5312 assert(image->signature == MagickSignature);
5313 if (image->debug != MagickFalse)
5314 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5315 assert(image->cache != (Cache) NULL);
5316 cache_info=(CacheInfo *) image->cache;
5317 assert(cache_info->signature == MagickSignature);
5318 if (cache_info->methods.sync_authentic_pixels_handler ==
5319 (SyncAuthenticPixelsHandler) NULL)
5320 return(MagickFalse);
5321 return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
5322}
5323
5324/*
5325%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5326% %
5327% %
5328% %
5329+ W r i t e P i x e l C a c h e I n d e x e s %
5330% %
5331% %
5332% %
5333%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5334%
5335% WritePixelCacheIndexes() writes the colormap indexes to the specified
5336% region of the pixel cache.
5337%
5338% The format of the WritePixelCacheIndexes() method is:
5339%
5340% MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5341% NexusInfo *nexus_info,ExceptionInfo *exception)
5342%
5343% A description of each parameter follows:
5344%
5345% o cache_info: the pixel cache.
5346%
5347% o nexus_info: the cache nexus to write the colormap indexes.
5348%
5349% o exception: return any errors or warnings in this structure.
5350%
5351*/
5352static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5353 NexusInfo *nexus_info,ExceptionInfo *exception)
5354{
5355 MagickOffsetType
5356 count,
5357 offset;
5358
5359 MagickSizeType
5360 length,
5361 number_pixels;
5362
5363 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005364 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005365
cristybb503372010-05-27 20:51:26 +00005366 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005367 y;
5368
cristybb503372010-05-27 20:51:26 +00005369 size_t
cristy3ed852e2009-09-05 21:47:34 +00005370 rows;
5371
5372 if (cache_info->debug != MagickFalse)
5373 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
5374 cache_info->filename);
5375 if (cache_info->active_index_channel == MagickFalse)
5376 return(MagickFalse);
5377 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5378 return(MagickTrue);
5379 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5380 nexus_info->region.x;
5381 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
5382 rows=nexus_info->region.height;
5383 number_pixels=(MagickSizeType) length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005384 p=nexus_info->indexes;
5385 switch (cache_info->type)
5386 {
5387 case MemoryCache:
5388 case MapCache:
5389 {
5390 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005391 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005392
5393 /*
5394 Write indexes to memory.
5395 */
cristydd341db2010-03-04 19:06:38 +00005396 if ((cache_info->columns == nexus_info->region.width) &&
5397 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5398 {
5399 length=number_pixels;
5400 rows=1UL;
5401 }
cristy3ed852e2009-09-05 21:47:34 +00005402 q=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00005403 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005404 {
5405 (void) CopyMagickMemory(q,p,(size_t) length);
5406 p+=nexus_info->region.width;
5407 q+=cache_info->columns;
5408 }
5409 break;
5410 }
5411 case DiskCache:
5412 {
5413 /*
5414 Write indexes to disk.
5415 */
5416 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5417 {
5418 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5419 cache_info->cache_filename);
5420 return(MagickFalse);
5421 }
cristydd341db2010-03-04 19:06:38 +00005422 if ((cache_info->columns == nexus_info->region.width) &&
5423 (number_pixels < MagickMaxBufferExtent))
5424 {
5425 length=number_pixels;
5426 rows=1UL;
5427 }
cristy3ed852e2009-09-05 21:47:34 +00005428 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005429 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005430 {
5431 count=WritePixelCacheRegion(cache_info,cache_info->offset+number_pixels*
5432 sizeof(PixelPacket)+offset*sizeof(*p),length,
5433 (const unsigned char *) p);
5434 if ((MagickSizeType) count < length)
5435 break;
5436 p+=nexus_info->region.width;
5437 offset+=cache_info->columns;
5438 }
cristybb503372010-05-27 20:51:26 +00005439 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005440 {
5441 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5442 cache_info->cache_filename);
5443 return(MagickFalse);
5444 }
5445 break;
5446 }
5447 default:
5448 break;
5449 }
5450 if ((cache_info->debug != MagickFalse) &&
5451 (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5452 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
cristyf2faecf2010-05-28 19:19:36 +00005453 cache_info->filename,(unsigned long) nexus_info->region.width,
5454 (unsigned long) nexus_info->region.height,(long) nexus_info->region.x,
5455 (long) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005456 return(MagickTrue);
5457}
5458
5459/*
5460%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5461% %
5462% %
5463% %
5464+ W r i t e C a c h e P i x e l s %
5465% %
5466% %
5467% %
5468%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5469%
5470% WritePixelCachePixels() writes image pixels to the specified region of the
5471% pixel cache.
5472%
5473% The format of the WritePixelCachePixels() method is:
5474%
5475% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5476% NexusInfo *nexus_info,ExceptionInfo *exception)
5477%
5478% A description of each parameter follows:
5479%
5480% o cache_info: the pixel cache.
5481%
5482% o nexus_info: the cache nexus to write the pixels.
5483%
5484% o exception: return any errors or warnings in this structure.
5485%
5486*/
5487static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5488 NexusInfo *nexus_info,ExceptionInfo *exception)
5489{
5490 MagickOffsetType
5491 count,
5492 offset;
5493
5494 MagickSizeType
5495 length,
5496 number_pixels;
5497
cristy3ed852e2009-09-05 21:47:34 +00005498 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005499 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005500
cristybb503372010-05-27 20:51:26 +00005501 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005502 y;
5503
cristybb503372010-05-27 20:51:26 +00005504 size_t
cristy3ed852e2009-09-05 21:47:34 +00005505 rows;
5506
5507 if (cache_info->debug != MagickFalse)
5508 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
5509 cache_info->filename);
5510 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5511 return(MagickTrue);
5512 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5513 nexus_info->region.x;
5514 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
5515 rows=nexus_info->region.height;
5516 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005517 p=nexus_info->pixels;
5518 switch (cache_info->type)
5519 {
5520 case MemoryCache:
5521 case MapCache:
5522 {
5523 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005524 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005525
5526 /*
5527 Write pixels to memory.
5528 */
cristydd341db2010-03-04 19:06:38 +00005529 if ((cache_info->columns == nexus_info->region.width) &&
5530 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5531 {
5532 length=number_pixels;
5533 rows=1UL;
5534 }
cristy3ed852e2009-09-05 21:47:34 +00005535 q=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00005536 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005537 {
5538 (void) CopyMagickMemory(q,p,(size_t) length);
5539 p+=nexus_info->region.width;
5540 q+=cache_info->columns;
5541 }
5542 break;
5543 }
5544 case DiskCache:
5545 {
5546 /*
5547 Write pixels to disk.
5548 */
5549 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5550 {
5551 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5552 cache_info->cache_filename);
5553 return(MagickFalse);
5554 }
cristydd341db2010-03-04 19:06:38 +00005555 if ((cache_info->columns == nexus_info->region.width) &&
5556 (number_pixels < MagickMaxBufferExtent))
5557 {
5558 length=number_pixels;
5559 rows=1UL;
5560 }
cristybb503372010-05-27 20:51:26 +00005561 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005562 {
5563 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5564 sizeof(*p),length,(const unsigned char *) p);
5565 if ((MagickSizeType) count < length)
5566 break;
5567 p+=nexus_info->region.width;
5568 offset+=cache_info->columns;
5569 }
cristybb503372010-05-27 20:51:26 +00005570 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005571 {
5572 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5573 cache_info->cache_filename);
5574 return(MagickFalse);
5575 }
5576 break;
5577 }
5578 default:
5579 break;
5580 }
5581 if ((cache_info->debug != MagickFalse) &&
5582 (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5583 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
cristyf1d91242010-05-28 02:23:19 +00005584 cache_info->filename,(unsigned long) nexus_info->region.width,
5585 (unsigned long) nexus_info->region.height,(long) nexus_info->region.x,
5586 (long) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005587 return(MagickTrue);
5588}