blob: 33fdb6004aa314fa920f4fd11fe570b9618bd671 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% CCCC AAA CCCC H H EEEEE %
7% C A A C H H E %
8% C AAAAA C HHHHH EEE %
9% C A A C H H E %
10% CCCC A A CCCC H H EEEEE %
11% %
12% %
13% MagickCore Pixel Cache Methods %
14% %
15% Software Design %
16% John Cristy %
17% July 1999 %
18% %
19% %
cristy16af1cb2009-12-11 21:38:29 +000020% Copyright 1999-2010 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% http://www.imagemagick.org/script/license.php %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37%
38*/
39
40/*
41 Include declarations.
42*/
43#include "magick/studio.h"
44#include "magick/blob.h"
45#include "magick/blob-private.h"
46#include "magick/cache.h"
47#include "magick/cache-private.h"
48#include "magick/color-private.h"
49#include "magick/composite-private.h"
50#include "magick/exception.h"
51#include "magick/exception-private.h"
cristy365e58f2010-02-15 02:00:01 +000052#include "magick/geometry.h"
cristy3ed852e2009-09-05 21:47:34 +000053#include "magick/list.h"
54#include "magick/log.h"
55#include "magick/magick.h"
56#include "magick/memory_.h"
cristy4789f0d2010-01-10 00:01:06 +000057#include "magick/pixel.h"
cristy3ed852e2009-09-05 21:47:34 +000058#include "magick/pixel-private.h"
cristya21afde2010-07-02 00:45:40 +000059#include "magick/policy.h"
cristy3ed852e2009-09-05 21:47:34 +000060#include "magick/quantum.h"
61#include "magick/random_.h"
62#include "magick/resource_.h"
63#include "magick/semaphore.h"
64#include "magick/splay-tree.h"
65#include "magick/string_.h"
cristya21afde2010-07-02 00:45:40 +000066#include "magick/string-private.h"
cristy3ed852e2009-09-05 21:47:34 +000067#include "magick/thread-private.h"
68#include "magick/utility.h"
69#if defined(MAGICKCORE_ZLIB_DELEGATE)
70#include "zlib.h"
71#endif
72
73/*
cristy30097232010-07-01 02:16:30 +000074 Define declarations.
75*/
76#define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
77
78/*
cristy3ed852e2009-09-05 21:47:34 +000079 Typedef declarations.
80*/
81typedef struct _MagickModulo
82{
cristybb503372010-05-27 20:51:26 +000083 ssize_t
cristy3ed852e2009-09-05 21:47:34 +000084 quotient,
85 remainder;
86} MagickModulo;
87
88struct _NexusInfo
89{
90 MagickBooleanType
91 mapped;
92
93 RectangleInfo
94 region;
95
96 MagickSizeType
97 length;
98
99 PixelPacket
100 *cache,
101 *pixels;
102
103 IndexPacket
104 *indexes;
105
cristybb503372010-05-27 20:51:26 +0000106 size_t
cristy3ed852e2009-09-05 21:47:34 +0000107 signature;
108};
109
110/*
111 Forward declarations.
112*/
113#if defined(__cplusplus) || defined(c_plusplus)
114extern "C" {
115#endif
116
117static const IndexPacket
118 *GetVirtualIndexesFromCache(const Image *);
119
120static const PixelPacket
cristybb503372010-05-27 20:51:26 +0000121 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
cristy0158a4b2010-09-20 13:59:45 +0000122 const ssize_t,const size_t,const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000123 *GetVirtualPixelsCache(const Image *);
124
125static MagickBooleanType
cristy3ed852e2009-09-05 21:47:34 +0000126 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
127 ReadPixelCacheIndexes(CacheInfo *,NexusInfo *,ExceptionInfo *),
128 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
129 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
130 WritePixelCacheIndexes(CacheInfo *,NexusInfo *,ExceptionInfo *),
131 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
132
133static PixelPacket
cristybb503372010-05-27 20:51:26 +0000134 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
135 const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000136 *SetPixelCacheNexusPixels(const Image *,const RectangleInfo *,NexusInfo *,
cristya4af2e32010-03-08 00:51:56 +0000137 ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +0000138
139#if defined(__cplusplus) || defined(c_plusplus)
140}
141#endif
142
143/*
144 Global declarations.
145*/
146static volatile MagickBooleanType
147 instantiate_cache = MagickFalse;
148
149static SemaphoreInfo
150 *cache_semaphore = (SemaphoreInfo *) NULL;
151
152static SplayTreeInfo
153 *cache_resources = (SplayTreeInfo *) NULL;
cristy3ed852e2009-09-05 21:47:34 +0000154
155/*
156%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
157% %
158% %
159% %
160+ A c q u i r e P i x e l C a c h e %
161% %
162% %
163% %
164%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
165%
166% AcquirePixelCache() acquires a pixel cache.
167%
168% The format of the AcquirePixelCache() method is:
169%
cristybb503372010-05-27 20:51:26 +0000170% Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000171%
172% A description of each parameter follows:
173%
174% o number_threads: the number of nexus threads.
175%
176*/
cristybb503372010-05-27 20:51:26 +0000177MagickExport Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000178{
179 CacheInfo
180 *cache_info;
181
182 cache_info=(CacheInfo *) AcquireAlignedMemory(1,sizeof(*cache_info));
183 if (cache_info == (CacheInfo *) NULL)
184 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
185 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
186 cache_info->type=UndefinedCache;
cristy87528ea2009-09-10 14:53:56 +0000187 cache_info->mode=IOMode;
cristy3ed852e2009-09-05 21:47:34 +0000188 cache_info->colorspace=RGBColorspace;
189 cache_info->file=(-1);
190 cache_info->id=GetMagickThreadId();
191 cache_info->number_threads=number_threads;
192 if (number_threads == 0)
193 cache_info->number_threads=GetOpenMPMaximumThreads();
194 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
195 if (cache_info->nexus_info == (NexusInfo **) NULL)
196 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristy3ed852e2009-09-05 21:47:34 +0000197 cache_info->semaphore=AllocateSemaphoreInfo();
cristy93505cf2010-08-10 21:37:49 +0000198 cache_info->reference_count=1;
cristy3ed852e2009-09-05 21:47:34 +0000199 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*/
cristy2cd7a752010-08-23 00:48:54 +0000243MagickExport NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000244{
cristy3ed852e2009-09-05 21:47:34 +0000245 NexusInfo
246 **nexus_info;
247
cristye076a6e2010-08-15 19:59:43 +0000248 register ssize_t
249 i;
250
cristy3ed852e2009-09-05 21:47:34 +0000251 nexus_info=(NexusInfo **) AcquireAlignedMemory(number_threads,
252 sizeof(*nexus_info));
253 if (nexus_info == (NexusInfo **) NULL)
254 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristybb503372010-05-27 20:51:26 +0000255 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000256 {
257 nexus_info[i]=(NexusInfo *) AcquireAlignedMemory(1,sizeof(**nexus_info));
258 if (nexus_info[i] == (NexusInfo *) NULL)
259 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
260 (void) ResetMagickMemory(nexus_info[i],0,sizeof(*nexus_info[i]));
261 nexus_info[i]->signature=MagickSignature;
262 }
263 return(nexus_info);
264}
265
266/*
267%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
268% %
269% %
270% %
cristyd43a46b2010-01-21 02:13:41 +0000271+ A c q u i r e P i x e l C a c h e P i x e l s %
272% %
273% %
274% %
275%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
276%
277% AcquirePixelCachePixels() returns the pixels associated with the specified
278% image.
279%
280% The format of the AcquirePixelCachePixels() method is:
281%
282% const void *AcquirePixelCachePixels(const Image *image,
283% MagickSizeType *length,ExceptionInfo *exception)
284%
285% A description of each parameter follows:
286%
287% o image: the image.
288%
289% o length: the pixel cache length.
290%
291% o exception: return any errors or warnings in this structure.
292%
293*/
294MagickExport const void *AcquirePixelCachePixels(const Image *image,
295 MagickSizeType *length,ExceptionInfo *exception)
296{
297 CacheInfo
298 *cache_info;
299
300 assert(image != (const Image *) NULL);
301 assert(image->signature == MagickSignature);
cristyd43a46b2010-01-21 02:13:41 +0000302 assert(exception != (ExceptionInfo *) NULL);
303 assert(exception->signature == MagickSignature);
304 assert(image->cache != (Cache) NULL);
305 cache_info=(CacheInfo *) image->cache;
306 assert(cache_info->signature == MagickSignature);
307 *length=0;
308 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
309 return((const void *) NULL);
310 *length=cache_info->length;
311 return((const void *) cache_info->pixels);
312}
313
314/*
315%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
316% %
317% %
318% %
cristyf34a1452009-10-24 22:29:27 +0000319+ C a c h e C o m p o n e n t G e n e s i s %
320% %
321% %
322% %
323%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
324%
325% CacheComponentGenesis() instantiates the cache component.
326%
327% The format of the CacheComponentGenesis method is:
328%
329% MagickBooleanType CacheComponentGenesis(void)
330%
331*/
332MagickExport MagickBooleanType CacheComponentGenesis(void)
333{
cristy165b6092009-10-26 13:52:10 +0000334 AcquireSemaphoreInfo(&cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000335 return(MagickTrue);
336}
337
338/*
339%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
340% %
341% %
342% %
343+ C a c h e C o m p o n e n t T e r m i n u s %
344% %
345% %
346% %
347%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
348%
349% CacheComponentTerminus() destroys the cache component.
350%
351% The format of the CacheComponentTerminus() method is:
352%
353% CacheComponentTerminus(void)
354%
355*/
356MagickExport void CacheComponentTerminus(void)
357{
cristy18b17442009-10-25 18:36:48 +0000358 if (cache_semaphore == (SemaphoreInfo *) NULL)
359 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000360 LockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000361 if (cache_resources != (SplayTreeInfo *) NULL)
362 cache_resources=DestroySplayTree(cache_resources);
363 instantiate_cache=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +0000364 UnlockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000365 DestroySemaphoreInfo(&cache_semaphore);
366}
367
368/*
369%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
370% %
371% %
372% %
cristy3ed852e2009-09-05 21:47:34 +0000373+ C l i p P i x e l C a c h e N e x u s %
374% %
375% %
376% %
377%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
378%
379% ClipPixelCacheNexus() clips the cache nexus as defined by the image clip
380% mask. The method returns MagickTrue if the pixel region is clipped,
381% otherwise MagickFalse.
382%
383% The format of the ClipPixelCacheNexus() method is:
384%
385% MagickBooleanType ClipPixelCacheNexus(Image *image,NexusInfo *nexus_info,
386% ExceptionInfo *exception)
387%
388% A description of each parameter follows:
389%
390% o image: the image.
391%
392% o nexus_info: the cache nexus to clip.
393%
394% o exception: return any errors or warnings in this structure.
395%
396*/
397static MagickBooleanType ClipPixelCacheNexus(Image *image,
398 NexusInfo *nexus_info,ExceptionInfo *exception)
399{
400 CacheInfo
401 *cache_info;
402
403 MagickSizeType
404 number_pixels;
405
406 NexusInfo
407 **clip_nexus,
408 **image_nexus;
409
410 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000411 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +0000412
413 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +0000414 *restrict nexus_indexes,
415 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +0000416
cristy3ed852e2009-09-05 21:47:34 +0000417 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000418 *restrict p,
419 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000420
cristye076a6e2010-08-15 19:59:43 +0000421 register ssize_t
422 i;
423
cristy3ed852e2009-09-05 21:47:34 +0000424 /*
425 Apply clip mask.
426 */
427 if (image->debug != MagickFalse)
428 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
429 if (image->clip_mask == (Image *) NULL)
430 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +0000431 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +0000432 if (cache_info == (Cache) NULL)
433 return(MagickFalse);
434 image_nexus=AcquirePixelCacheNexus(1);
435 clip_nexus=AcquirePixelCacheNexus(1);
436 if ((image_nexus == (NexusInfo **) NULL) ||
437 (clip_nexus == (NexusInfo **) NULL))
438 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
439 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,nexus_info->region.y,
440 nexus_info->region.width,nexus_info->region.height,image_nexus[0],
441 exception);
cristy2036f5c2010-09-19 21:18:17 +0000442 indexes=GetPixelCacheNexusIndexes(cache_info,image_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +0000443 q=nexus_info->pixels;
444 nexus_indexes=nexus_info->indexes;
445 r=GetVirtualPixelsFromNexus(image->clip_mask,MaskVirtualPixelMethod,
446 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
447 nexus_info->region.height,clip_nexus[0],exception);
448 number_pixels=(MagickSizeType) nexus_info->region.width*
449 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +0000450 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000451 {
452 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
453 break;
454 if (PixelIntensityToQuantum(r) > ((Quantum) QuantumRange/2))
455 {
cristyce70c172010-01-07 17:15:30 +0000456 SetRedPixelComponent(q,GetRedPixelComponent(p));
457 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
458 SetBluePixelComponent(q,GetBluePixelComponent(p));
459 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
cristy3ed852e2009-09-05 21:47:34 +0000460 if (cache_info->active_index_channel != MagickFalse)
461 nexus_indexes[i]=indexes[i];
462 }
463 p++;
464 q++;
465 r++;
466 }
467 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
468 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +0000469 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +0000470 return(MagickFalse);
471 return(MagickTrue);
472}
473
474/*
475%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
476% %
477% %
478% %
479+ C l o n e P i x e l C a c h e %
480% %
481% %
482% %
483%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
484%
485% ClonePixelCache() clones a pixel cache.
486%
487% The format of the ClonePixelCache() method is:
488%
489% Cache ClonePixelCache(const Cache cache)
490%
491% A description of each parameter follows:
492%
493% o cache: the pixel cache.
494%
495*/
496MagickExport Cache ClonePixelCache(const Cache cache)
497{
498 CacheInfo
499 *clone_info;
500
501 const CacheInfo
502 *cache_info;
503
504 assert(cache != (const Cache) NULL);
505 cache_info=(const CacheInfo *) cache;
506 assert(cache_info->signature == MagickSignature);
507 if (cache_info->debug != MagickFalse)
508 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
509 cache_info->filename);
510 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
511 if (clone_info == (Cache) NULL)
512 return((Cache) NULL);
513 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
514 return((Cache ) clone_info);
515}
516
517/*
518%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
519% %
520% %
521% %
cristy60c44a82009-10-07 00:58:49 +0000522+ 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 +0000523% %
524% %
525% %
526%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
527% ClonePixelCachePixels() clones the source pixel cache to the destination
528% cache.
529%
530% The format of the ClonePixelCachePixels() method is:
531%
532% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
533% CacheInfo *source_info,ExceptionInfo *exception)
534%
535% A description of each parameter follows:
536%
537% o cache_info: the pixel cache.
538%
539% o source_info: the source pixel cache.
540%
541% o exception: return any errors or warnings in this structure.
542%
543*/
544
545static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
546{
547 int
548 status;
549
cristy5ee247a2010-02-12 15:42:34 +0000550 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000551 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000552 if (cache_info->file != -1)
553 status=close(cache_info->file);
cristy3ed852e2009-09-05 21:47:34 +0000554 cache_info->file=(-1);
555 RelinquishMagickResource(FileResource,1);
cristyf84a1932010-01-03 18:00:18 +0000556 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000557 return(status == -1 ? MagickFalse : MagickTrue);
558}
559
560static void LimitPixelCacheDescriptors(void)
561{
562 register CacheInfo
563 *p,
564 *q;
565
566 /*
567 Limit # of open file descriptors.
568 */
569 if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
570 return;
cristyf84a1932010-01-03 18:00:18 +0000571 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000572 if (cache_resources == (SplayTreeInfo *) NULL)
573 {
cristyf84a1932010-01-03 18:00:18 +0000574 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000575 return;
576 }
577 ResetSplayTreeIterator(cache_resources);
578 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
579 while (p != (CacheInfo *) NULL)
580 {
581 if ((p->type == DiskCache) && (p->file != -1))
cristy508d9312010-02-10 21:10:30 +0000582 break;
cristy3ed852e2009-09-05 21:47:34 +0000583 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
584 }
585 for (q=p; p != (CacheInfo *) NULL; )
586 {
587 if ((p->type == DiskCache) && (p->file != -1) &&
588 (p->timestamp < q->timestamp))
cristy508d9312010-02-10 21:10:30 +0000589 q=p;
cristy3ed852e2009-09-05 21:47:34 +0000590 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
591 }
592 if (q != (CacheInfo *) NULL)
cristy9e116922010-02-12 20:58:13 +0000593 {
594 /*
595 Close least recently used cache.
596 */
597 (void) close(q->file);
598 q->file=(-1);
599 }
cristyf84a1932010-01-03 18:00:18 +0000600 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000601}
602
603static inline MagickSizeType MagickMax(const MagickSizeType x,
604 const MagickSizeType y)
605{
606 if (x > y)
607 return(x);
608 return(y);
609}
610
611static inline MagickSizeType MagickMin(const MagickSizeType x,
612 const MagickSizeType y)
613{
614 if (x < y)
615 return(x);
616 return(y);
617}
618
619static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
620 const MapMode mode)
621{
622 int
623 file;
624
625 /*
626 Open pixel cache on disk.
627 */
cristyf84a1932010-01-03 18:00:18 +0000628 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000629 if (cache_info->file != -1)
630 {
cristyf84a1932010-01-03 18:00:18 +0000631 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000632 return(MagickTrue); /* cache already open */
633 }
634 LimitPixelCacheDescriptors();
635 if (*cache_info->cache_filename == '\0')
636 file=AcquireUniqueFileResource(cache_info->cache_filename);
637 else
638 switch (mode)
639 {
640 case ReadMode:
641 {
642 file=open(cache_info->cache_filename,O_RDONLY | O_BINARY);
643 break;
644 }
645 case WriteMode:
646 {
647 file=open(cache_info->cache_filename,O_WRONLY | O_CREAT | O_BINARY |
648 O_EXCL,S_MODE);
649 if (file == -1)
650 file=open(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
651 break;
652 }
653 case IOMode:
654 default:
655 {
656 file=open(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
657 O_EXCL,S_MODE);
658 if (file == -1)
659 file=open(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
660 break;
661 }
662 }
663 if (file == -1)
664 {
cristyf84a1932010-01-03 18:00:18 +0000665 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000666 return(MagickFalse);
667 }
668 (void) AcquireMagickResource(FileResource,1);
669 cache_info->file=file;
670 cache_info->timestamp=time(0);
cristyf84a1932010-01-03 18:00:18 +0000671 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000672 return(MagickTrue);
673}
674
675static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
676 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000677 unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000678{
679 register MagickOffsetType
680 i;
681
682 ssize_t
683 count;
684
cristy08a88202010-03-04 19:18:05 +0000685 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000686#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000687 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000688 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
689 {
cristyf84a1932010-01-03 18:00:18 +0000690 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000691 return((MagickOffsetType) -1);
692 }
693#endif
694 count=0;
695 for (i=0; i < (MagickOffsetType) length; i+=count)
696 {
697#if !defined(MAGICKCORE_HAVE_PREAD)
698 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
699 (MagickSizeType) SSIZE_MAX));
700#else
701 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
702 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
703#endif
704 if (count > 0)
705 continue;
706 count=0;
707 if (errno != EINTR)
708 {
709 i=(-1);
710 break;
711 }
712 }
713#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000714 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000715#endif
716 return(i);
717}
718
719static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
720 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000721 const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000722{
723 register MagickOffsetType
724 i;
725
726 ssize_t
727 count;
728
cristy08a88202010-03-04 19:18:05 +0000729 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000730#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000731 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000732 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
733 {
cristyf84a1932010-01-03 18:00:18 +0000734 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000735 return((MagickOffsetType) -1);
736 }
737#endif
738 count=0;
739 for (i=0; i < (MagickOffsetType) length; i+=count)
740 {
741#if !defined(MAGICKCORE_HAVE_PWRITE)
742 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
743 (MagickSizeType) SSIZE_MAX));
744#else
745 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
746 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
747#endif
748 if (count > 0)
749 continue;
750 count=0;
751 if (errno != EINTR)
752 {
753 i=(-1);
754 break;
755 }
756 }
757#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000758 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000759#endif
760 return(i);
761}
762
763static MagickBooleanType CloneDiskToDiskPixelCache(CacheInfo *clone_info,
764 CacheInfo *cache_info,ExceptionInfo *exception)
765{
766 MagickOffsetType
767 count,
768 offset,
769 source_offset;
770
771 MagickSizeType
772 length;
773
cristy3ed852e2009-09-05 21:47:34 +0000774 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000775 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +0000776
cristye076a6e2010-08-15 19:59:43 +0000777 register ssize_t
778 y;
779
cristybb503372010-05-27 20:51:26 +0000780 size_t
cristy3ed852e2009-09-05 21:47:34 +0000781 columns,
782 rows;
783
784 if (cache_info->debug != MagickFalse)
785 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
786 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
787 {
788 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
789 clone_info->cache_filename);
790 return(MagickFalse);
791 }
792 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
793 {
794 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
795 cache_info->cache_filename);
796 return(MagickFalse);
797 }
cristybb503372010-05-27 20:51:26 +0000798 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
799 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +0000800 if ((clone_info->active_index_channel != MagickFalse) &&
801 (cache_info->active_index_channel != MagickFalse))
802 {
803 register IndexPacket
804 *indexes;
805
806 /*
807 Clone cache indexes.
808 */
809 length=MagickMax(clone_info->columns,cache_info->columns)*
810 sizeof(*indexes);
811 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
812 if (indexes == (IndexPacket *) NULL)
813 {
814 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
815 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
816 return(MagickFalse);
817 }
818 (void) ResetMagickMemory(indexes,0,(size_t) length);
819 length=columns*sizeof(*indexes);
820 source_offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
821 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
822 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
823 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +0000824 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000825 {
826 source_offset-=cache_info->columns*sizeof(*indexes);
827 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
828 length,(unsigned char *) indexes);
829 if ((MagickSizeType) count != length)
830 break;
831 offset-=clone_info->columns*sizeof(*indexes);
832 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
833 (unsigned char *) indexes);
834 if ((MagickSizeType) count != length)
835 break;
836 }
cristybb503372010-05-27 20:51:26 +0000837 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000838 {
839 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
840 ThrowFileException(exception,CacheError,"UnableToCloneCache",
841 cache_info->cache_filename);
842 return(MagickFalse);
843 }
844 if (clone_info->columns > cache_info->columns)
845 {
846 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
847 (void) ResetMagickMemory(indexes,0,(size_t) length);
848 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
849 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +0000850 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000851 {
852 offset-=clone_info->columns*sizeof(*indexes);
853 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
854 length,(unsigned char *) indexes);
855 if ((MagickSizeType) count != length)
856 break;
857 }
cristybb503372010-05-27 20:51:26 +0000858 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000859 {
860 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
861 ThrowFileException(exception,CacheError,"UnableToCloneCache",
862 cache_info->cache_filename);
863 return(MagickFalse);
864 }
865 }
866 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
867 }
868 /*
869 Clone cache pixels.
870 */
871 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
872 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
873 if (pixels == (PixelPacket *) NULL)
874 {
875 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
876 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
877 return(MagickFalse);
878 }
879 (void) ResetMagickMemory(pixels,0,(size_t) length);
880 length=columns*sizeof(*pixels);
881 source_offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
882 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +0000883 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000884 {
885 source_offset-=cache_info->columns*sizeof(*pixels);
886 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
887 length,(unsigned char *) pixels);
888 if ((MagickSizeType) count != length)
889 break;
890 offset-=clone_info->columns*sizeof(*pixels);
891 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
892 (unsigned char *) pixels);
893 if ((MagickSizeType) count != length)
894 break;
895 }
cristybb503372010-05-27 20:51:26 +0000896 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000897 {
898 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
899 ThrowFileException(exception,CacheError,"UnableToCloneCache",
900 cache_info->cache_filename);
901 return(MagickFalse);
902 }
903 if (clone_info->columns > cache_info->columns)
904 {
905 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
906 sizeof(*pixels);
907 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
908 (void) ResetMagickMemory(pixels,0,(size_t) length);
cristybb503372010-05-27 20:51:26 +0000909 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000910 {
911 offset-=clone_info->columns*sizeof(*pixels);
912 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
913 (unsigned char *) pixels);
914 if ((MagickSizeType) count != length)
915 break;
916 }
cristybb503372010-05-27 20:51:26 +0000917 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000918 {
919 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
920 ThrowFileException(exception,CacheError,"UnableToCloneCache",
921 cache_info->cache_filename);
922 return(MagickFalse);
923 }
924 }
925 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
926 return(MagickTrue);
927}
928
929static MagickBooleanType CloneDiskToMemoryPixelCache(CacheInfo *clone_info,
930 CacheInfo *cache_info,ExceptionInfo *exception)
931{
932 MagickOffsetType
933 count,
934 offset;
935
936 MagickSizeType
937 length;
938
cristy3ed852e2009-09-05 21:47:34 +0000939 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000940 *restrict pixels,
941 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000942
cristye076a6e2010-08-15 19:59:43 +0000943 register ssize_t
944 y;
945
cristybb503372010-05-27 20:51:26 +0000946 size_t
cristy3ed852e2009-09-05 21:47:34 +0000947 columns,
948 rows;
949
950 if (cache_info->debug != MagickFalse)
951 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
952 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
953 {
954 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
955 cache_info->cache_filename);
956 return(MagickFalse);
957 }
cristybb503372010-05-27 20:51:26 +0000958 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
959 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +0000960 if ((clone_info->active_index_channel != MagickFalse) &&
961 (cache_info->active_index_channel != MagickFalse))
962 {
963 register IndexPacket
964 *indexes,
965 *q;
966
967 /*
968 Clone cache indexes.
969 */
970 length=MagickMax(clone_info->columns,cache_info->columns)*
971 sizeof(*indexes);
972 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
973 if (indexes == (IndexPacket *) NULL)
974 {
975 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
976 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
977 return(MagickFalse);
978 }
979 (void) ResetMagickMemory(indexes,0,(size_t) length);
980 length=columns*sizeof(IndexPacket);
981 offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
982 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
983 q=clone_info->indexes+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +0000984 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000985 {
986 offset-=cache_info->columns*sizeof(IndexPacket);
987 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,
988 length,(unsigned char *) indexes);
989 if ((MagickSizeType) count != length)
990 break;
991 q-=clone_info->columns;
cristy8f036fe2010-09-18 02:02:00 +0000992 (void) memcpy(q,indexes,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +0000993 if ((MagickSizeType) count != length)
994 break;
995 }
cristybb503372010-05-27 20:51:26 +0000996 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000997 {
998 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
999 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1000 cache_info->cache_filename);
1001 return(MagickFalse);
1002 }
1003 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1004 }
1005 /*
1006 Clone cache pixels.
1007 */
1008 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1009 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1010 if (pixels == (PixelPacket *) NULL)
1011 {
1012 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1013 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1014 return(MagickFalse);
1015 }
1016 (void) ResetMagickMemory(pixels,0,(size_t) length);
1017 length=columns*sizeof(*pixels);
1018 offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
1019 q=clone_info->pixels+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001020 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001021 {
1022 offset-=cache_info->columns*sizeof(*pixels);
1023 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,length,
1024 (unsigned char *) pixels);
1025 if ((MagickSizeType) count != length)
1026 break;
1027 q-=clone_info->columns;
cristy8f036fe2010-09-18 02:02:00 +00001028 (void) memcpy(q,pixels,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00001029 }
cristybb503372010-05-27 20:51:26 +00001030 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001031 {
1032 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1033 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1034 cache_info->cache_filename);
1035 return(MagickFalse);
1036 }
1037 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1038 return(MagickTrue);
1039}
1040
1041static MagickBooleanType CloneMemoryToDiskPixelCache(CacheInfo *clone_info,
1042 CacheInfo *cache_info,ExceptionInfo *exception)
1043{
1044 MagickOffsetType
1045 count,
1046 offset;
1047
1048 MagickSizeType
1049 length;
1050
cristy3ed852e2009-09-05 21:47:34 +00001051 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001052 *restrict p,
1053 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +00001054
cristye076a6e2010-08-15 19:59:43 +00001055 register ssize_t
1056 y;
1057
cristybb503372010-05-27 20:51:26 +00001058 size_t
cristy3ed852e2009-09-05 21:47:34 +00001059 columns,
1060 rows;
1061
1062 if (cache_info->debug != MagickFalse)
1063 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
1064 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
1065 {
1066 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1067 clone_info->cache_filename);
1068 return(MagickFalse);
1069 }
cristybb503372010-05-27 20:51:26 +00001070 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1071 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001072 if ((clone_info->active_index_channel != MagickFalse) &&
1073 (cache_info->active_index_channel != MagickFalse))
1074 {
1075 register IndexPacket
1076 *p,
1077 *indexes;
1078
1079 /*
1080 Clone cache indexes.
1081 */
1082 length=MagickMax(clone_info->columns,cache_info->columns)*
1083 sizeof(*indexes);
1084 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1085 if (indexes == (IndexPacket *) NULL)
1086 {
1087 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1088 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1089 return(MagickFalse);
1090 }
1091 (void) ResetMagickMemory(indexes,0,(size_t) length);
1092 length=columns*sizeof(*indexes);
1093 p=cache_info->indexes+cache_info->columns*rows;
1094 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1095 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +00001096 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001097 {
1098 p-=cache_info->columns;
cristy8f036fe2010-09-18 02:02:00 +00001099 (void) memcpy(indexes,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00001100 offset-=clone_info->columns*sizeof(*indexes);
1101 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1102 (unsigned char *) indexes);
1103 if ((MagickSizeType) count != length)
1104 break;
1105 }
cristybb503372010-05-27 20:51:26 +00001106 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001107 {
1108 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1109 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1110 cache_info->cache_filename);
1111 return(MagickFalse);
1112 }
1113 if (clone_info->columns > cache_info->columns)
1114 {
1115 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
1116 (void) ResetMagickMemory(indexes,0,(size_t) length);
1117 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1118 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +00001119 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001120 {
1121 offset-=clone_info->columns*sizeof(*indexes);
1122 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
1123 length,(unsigned char *) indexes);
1124 if ((MagickSizeType) count != length)
1125 break;
1126 }
cristybb503372010-05-27 20:51:26 +00001127 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001128 {
1129 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1130 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1131 cache_info->cache_filename);
1132 return(MagickFalse);
1133 }
1134 }
1135 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1136 }
1137 /*
1138 Clone cache pixels.
1139 */
1140 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1141 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1142 if (pixels == (PixelPacket *) NULL)
1143 {
1144 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1145 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1146 return(MagickFalse);
1147 }
1148 (void) ResetMagickMemory(pixels,0,(size_t) length);
1149 length=columns*sizeof(*pixels);
1150 p=cache_info->pixels+cache_info->columns*rows;
1151 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +00001152 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001153 {
1154 p-=cache_info->columns;
cristy8f036fe2010-09-18 02:02:00 +00001155 (void) memcpy(pixels,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00001156 offset-=clone_info->columns*sizeof(*pixels);
1157 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1158 (unsigned char *) pixels);
1159 if ((MagickSizeType) count != length)
1160 break;
1161 }
cristybb503372010-05-27 20:51:26 +00001162 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001163 {
1164 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1165 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1166 cache_info->cache_filename);
1167 return(MagickFalse);
1168 }
1169 if (clone_info->columns > cache_info->columns)
1170 {
1171 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
1172 sizeof(*pixels);
1173 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1174 (void) ResetMagickMemory(pixels,0,(size_t) length);
cristybb503372010-05-27 20:51:26 +00001175 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001176 {
1177 offset-=clone_info->columns*sizeof(*pixels);
1178 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1179 (unsigned char *) pixels);
1180 if ((MagickSizeType) count != length)
1181 break;
1182 }
cristybb503372010-05-27 20:51:26 +00001183 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001184 {
1185 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1186 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1187 cache_info->cache_filename);
1188 return(MagickFalse);
1189 }
1190 }
1191 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1192 return(MagickTrue);
1193}
1194
1195static MagickBooleanType CloneMemoryToMemoryPixelCache(CacheInfo *clone_info,
1196 CacheInfo *cache_info,ExceptionInfo *magick_unused(exception))
1197{
cristy3ed852e2009-09-05 21:47:34 +00001198 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001199 *restrict pixels,
1200 *restrict source_pixels;
cristy3ed852e2009-09-05 21:47:34 +00001201
cristye076a6e2010-08-15 19:59:43 +00001202 register ssize_t
1203 y;
cristy3ed852e2009-09-05 21:47:34 +00001204
cristybb503372010-05-27 20:51:26 +00001205 size_t
cristy3ed852e2009-09-05 21:47:34 +00001206 columns,
cristye076a6e2010-08-15 19:59:43 +00001207 length,
cristy3ed852e2009-09-05 21:47:34 +00001208 rows;
1209
1210 if (cache_info->debug != MagickFalse)
1211 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
cristybb503372010-05-27 20:51:26 +00001212 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1213 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001214 if ((clone_info->active_index_channel != MagickFalse) &&
1215 (cache_info->active_index_channel != MagickFalse))
1216 {
1217 register IndexPacket
1218 *indexes,
1219 *source_indexes;
1220
1221 /*
1222 Clone cache indexes.
1223 */
1224 length=columns*sizeof(*indexes);
1225 if (clone_info->columns == cache_info->columns)
cristy8f036fe2010-09-18 02:02:00 +00001226 (void) memcpy(clone_info->indexes,cache_info->indexes,length*rows);
cristy3ed852e2009-09-05 21:47:34 +00001227 else
1228 {
1229 source_indexes=cache_info->indexes+cache_info->columns*rows;
1230 indexes=clone_info->indexes+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001231 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001232 {
1233 source_indexes-=cache_info->columns;
1234 indexes-=clone_info->columns;
cristy8f036fe2010-09-18 02:02:00 +00001235 (void) memcpy(indexes,source_indexes,length);
cristy3ed852e2009-09-05 21:47:34 +00001236 }
1237 if (clone_info->columns > cache_info->columns)
1238 {
1239 length=(clone_info->columns-cache_info->columns)*
1240 sizeof(*indexes);
1241 indexes=clone_info->indexes+clone_info->columns*rows+
1242 cache_info->columns;
cristybb503372010-05-27 20:51:26 +00001243 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001244 {
1245 indexes-=clone_info->columns;
1246 (void) ResetMagickMemory(indexes,0,length);
1247 }
1248 }
1249 }
1250 }
1251 /*
1252 Clone cache pixels.
1253 */
1254 length=columns*sizeof(*pixels);
1255 if (clone_info->columns == cache_info->columns)
cristy8f036fe2010-09-18 02:02:00 +00001256 (void) memcpy(clone_info->pixels,cache_info->pixels,length*rows);
cristy3ed852e2009-09-05 21:47:34 +00001257 else
1258 {
1259 source_pixels=cache_info->pixels+cache_info->columns*rows;
1260 pixels=clone_info->pixels+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001261 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001262 {
1263 source_pixels-=cache_info->columns;
1264 pixels-=clone_info->columns;
cristy8f036fe2010-09-18 02:02:00 +00001265 (void) memcpy(pixels,source_pixels,length);
cristy3ed852e2009-09-05 21:47:34 +00001266 }
1267 if (clone_info->columns > cache_info->columns)
1268 {
1269 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1270 pixels=clone_info->pixels+clone_info->columns*rows+
1271 cache_info->columns;
cristybb503372010-05-27 20:51:26 +00001272 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001273 {
1274 pixels-=clone_info->columns;
1275 (void) ResetMagickMemory(pixels,0,length);
1276 }
1277 }
1278 }
1279 return(MagickTrue);
1280}
1281
1282static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1283 CacheInfo *cache_info,ExceptionInfo *exception)
1284{
1285 if ((clone_info->type != DiskCache) && (cache_info->type != DiskCache))
1286 return(CloneMemoryToMemoryPixelCache(clone_info,cache_info,exception));
1287 if ((clone_info->type == DiskCache) && (cache_info->type == DiskCache))
1288 return(CloneDiskToDiskPixelCache(clone_info,cache_info,exception));
1289 if (cache_info->type == DiskCache)
1290 return(CloneDiskToMemoryPixelCache(clone_info,cache_info,exception));
1291 return(CloneMemoryToDiskPixelCache(clone_info,cache_info,exception));
1292}
1293
1294/*
1295%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1296% %
1297% %
1298% %
1299+ C l o n e P i x e l C a c h e M e t h o d s %
1300% %
1301% %
1302% %
1303%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1304%
1305% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1306% another.
1307%
1308% The format of the ClonePixelCacheMethods() method is:
1309%
1310% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1311%
1312% A description of each parameter follows:
1313%
1314% o clone: Specifies a pointer to a Cache structure.
1315%
1316% o cache: the pixel cache.
1317%
1318*/
1319MagickExport void ClonePixelCacheMethods(Cache clone,const Cache cache)
1320{
1321 CacheInfo
1322 *cache_info,
1323 *source_info;
1324
1325 assert(clone != (Cache) NULL);
1326 source_info=(CacheInfo *) clone;
1327 assert(source_info->signature == MagickSignature);
1328 if (source_info->debug != MagickFalse)
1329 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1330 source_info->filename);
1331 assert(cache != (Cache) NULL);
1332 cache_info=(CacheInfo *) cache;
1333 assert(cache_info->signature == MagickSignature);
1334 source_info->methods=cache_info->methods;
1335}
1336
1337/*
1338%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1339% %
1340% %
1341% %
1342+ D e s t r o y I m a g e P i x e l C a c h e %
1343% %
1344% %
1345% %
1346%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1347%
1348% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1349%
1350% The format of the DestroyImagePixelCache() method is:
1351%
1352% void DestroyImagePixelCache(Image *image)
1353%
1354% A description of each parameter follows:
1355%
1356% o image: the image.
1357%
1358*/
1359static void DestroyImagePixelCache(Image *image)
1360{
1361 assert(image != (Image *) NULL);
1362 assert(image->signature == MagickSignature);
1363 if (image->debug != MagickFalse)
1364 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1365 if (image->cache == (void *) NULL)
1366 return;
1367 image->cache=DestroyPixelCache(image->cache);
1368}
1369
1370/*
1371%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1372% %
1373% %
1374% %
1375+ D e s t r o y I m a g e P i x e l s %
1376% %
1377% %
1378% %
1379%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1380%
1381% DestroyImagePixels() deallocates memory associated with the pixel cache.
1382%
1383% The format of the DestroyImagePixels() method is:
1384%
1385% void DestroyImagePixels(Image *image)
1386%
1387% A description of each parameter follows:
1388%
1389% o image: the image.
1390%
1391*/
1392MagickExport void DestroyImagePixels(Image *image)
1393{
1394 CacheInfo
1395 *cache_info;
1396
1397 assert(image != (const Image *) NULL);
1398 assert(image->signature == MagickSignature);
1399 if (image->debug != MagickFalse)
1400 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1401 assert(image->cache != (Cache) NULL);
1402 cache_info=(CacheInfo *) image->cache;
1403 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001404 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1405 {
1406 cache_info->methods.destroy_pixel_handler(image);
1407 return;
1408 }
cristy2036f5c2010-09-19 21:18:17 +00001409 image->cache=DestroyPixelCache(image->cache);
cristy3ed852e2009-09-05 21:47:34 +00001410}
1411
1412/*
1413%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1414% %
1415% %
1416% %
1417+ D e s t r o y P i x e l C a c h e %
1418% %
1419% %
1420% %
1421%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1422%
1423% DestroyPixelCache() deallocates memory associated with the pixel cache.
1424%
1425% The format of the DestroyPixelCache() method is:
1426%
1427% Cache DestroyPixelCache(Cache cache)
1428%
1429% A description of each parameter follows:
1430%
1431% o cache: the pixel cache.
1432%
1433*/
1434
1435static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1436{
1437 switch (cache_info->type)
1438 {
1439 case MemoryCache:
1440 {
1441 if (cache_info->mapped == MagickFalse)
1442 cache_info->pixels=(PixelPacket *) RelinquishMagickMemory(
1443 cache_info->pixels);
1444 else
1445 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,
1446 (size_t) cache_info->length);
1447 RelinquishMagickResource(MemoryResource,cache_info->length);
1448 break;
1449 }
1450 case MapCache:
1451 {
1452 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,(size_t)
1453 cache_info->length);
1454 RelinquishMagickResource(MapResource,cache_info->length);
1455 }
1456 case DiskCache:
1457 {
1458 if (cache_info->file != -1)
1459 (void) ClosePixelCacheOnDisk(cache_info);
1460 RelinquishMagickResource(DiskResource,cache_info->length);
1461 break;
1462 }
1463 default:
1464 break;
1465 }
1466 cache_info->type=UndefinedCache;
1467 cache_info->mapped=MagickFalse;
1468 cache_info->indexes=(IndexPacket *) NULL;
1469}
1470
1471MagickExport Cache DestroyPixelCache(Cache cache)
1472{
1473 CacheInfo
1474 *cache_info;
1475
cristy3ed852e2009-09-05 21:47:34 +00001476 assert(cache != (Cache) NULL);
1477 cache_info=(CacheInfo *) cache;
1478 assert(cache_info->signature == MagickSignature);
1479 if (cache_info->debug != MagickFalse)
1480 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1481 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001482 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001483 cache_info->reference_count--;
1484 if (cache_info->reference_count != 0)
1485 {
cristyf84a1932010-01-03 18:00:18 +00001486 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001487 return((Cache) NULL);
1488 }
cristyf84a1932010-01-03 18:00:18 +00001489 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001490 if (cache_resources != (SplayTreeInfo *) NULL)
1491 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
cristy5b8de732009-09-10 23:50:40 +00001492 if (cache_info->debug != MagickFalse)
1493 {
1494 char
1495 message[MaxTextExtent];
1496
1497 (void) FormatMagickString(message,MaxTextExtent,"destroy %s",
1498 cache_info->filename);
1499 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1500 }
cristyc2e1bdd2009-09-10 23:43:34 +00001501 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1502 (cache_info->type != DiskCache)))
1503 RelinquishPixelCachePixels(cache_info);
1504 else
1505 {
1506 RelinquishPixelCachePixels(cache_info);
1507 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1508 }
cristy3ed852e2009-09-05 21:47:34 +00001509 *cache_info->cache_filename='\0';
1510 if (cache_info->nexus_info != (NexusInfo **) NULL)
1511 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1512 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001513 if (cache_info->random_info != (RandomInfo *) NULL)
1514 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001515 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1516 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1517 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1518 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001519 cache_info->signature=(~MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001520 cache_info=(CacheInfo *) RelinquishAlignedMemory(cache_info);
1521 cache=(Cache) NULL;
1522 return(cache);
1523}
1524
1525/*
1526%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1527% %
1528% %
1529% %
1530+ D e s t r o y P i x e l C a c h e N e x u s %
1531% %
1532% %
1533% %
1534%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1535%
1536% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1537%
1538% The format of the DestroyPixelCacheNexus() method is:
1539%
1540% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001541% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001542%
1543% A description of each parameter follows:
1544%
1545% o nexus_info: the nexus to destroy.
1546%
1547% o number_threads: the number of nexus threads.
1548%
1549*/
1550
1551static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1552{
1553 if (nexus_info->mapped == MagickFalse)
1554 (void) RelinquishMagickMemory(nexus_info->cache);
1555 else
1556 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1557 nexus_info->cache=(PixelPacket *) NULL;
1558 nexus_info->pixels=(PixelPacket *) NULL;
1559 nexus_info->indexes=(IndexPacket *) NULL;
1560 nexus_info->length=0;
1561 nexus_info->mapped=MagickFalse;
1562}
1563
1564MagickExport NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001565 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001566{
cristybb503372010-05-27 20:51:26 +00001567 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001568 i;
1569
1570 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001571 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001572 {
1573 if (nexus_info[i]->cache != (PixelPacket *) NULL)
1574 RelinquishCacheNexusPixels(nexus_info[i]);
1575 nexus_info[i]->signature=(~MagickSignature);
1576 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
1577 }
1578 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
1579 return(nexus_info);
1580}
1581
1582/*
1583%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1584% %
1585% %
1586% %
cristy3ed852e2009-09-05 21:47:34 +00001587+ 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 %
1588% %
1589% %
1590% %
1591%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1592%
1593% GetAuthenticIndexesFromCache() returns the indexes associated with the last
1594% call to QueueAuthenticPixelsCache() or GetAuthenticPixelsCache().
1595%
1596% The format of the GetAuthenticIndexesFromCache() method is:
1597%
1598% IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1599%
1600% A description of each parameter follows:
1601%
1602% o image: the image.
1603%
1604*/
1605static IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1606{
1607 CacheInfo
1608 *cache_info;
1609
cristy5c9e6f22010-09-17 17:31:01 +00001610 const int
1611 id = GetOpenMPThreadId();
1612
cristy3ed852e2009-09-05 21:47:34 +00001613 cache_info=(CacheInfo *) image->cache;
cristy6ebe97c2010-07-03 01:17:28 +00001614 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001615 return(GetPixelCacheNexusIndexes(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001616}
1617
1618/*
1619%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1620% %
1621% %
1622% %
1623% G e t A u t h e n t i c I n d e x Q u e u e %
1624% %
1625% %
1626% %
1627%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1628%
1629% GetAuthenticIndexQueue() returns the authentic black channel or the colormap
1630% indexes associated with the last call to QueueAuthenticPixels() or
1631% GetVirtualPixels(). NULL is returned if the black channel or colormap
1632% indexes are not available.
1633%
1634% The format of the GetAuthenticIndexQueue() method is:
1635%
1636% IndexPacket *GetAuthenticIndexQueue(const Image *image)
1637%
1638% A description of each parameter follows:
1639%
1640% o image: the image.
1641%
1642*/
1643MagickExport IndexPacket *GetAuthenticIndexQueue(const Image *image)
1644{
1645 CacheInfo
1646 *cache_info;
1647
cristy2036f5c2010-09-19 21:18:17 +00001648 const int
1649 id = GetOpenMPThreadId();
1650
cristy3ed852e2009-09-05 21:47:34 +00001651 assert(image != (const Image *) NULL);
1652 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001653 assert(image->cache != (Cache) NULL);
1654 cache_info=(CacheInfo *) image->cache;
1655 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001656 if (cache_info->methods.get_authentic_indexes_from_handler !=
cristy3ed852e2009-09-05 21:47:34 +00001657 (GetAuthenticIndexesFromHandler) NULL)
cristyd317f372010-09-18 01:42:20 +00001658 return(cache_info->methods.get_authentic_indexes_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001659 assert(id < (int) cache_info->number_threads);
1660 return(GetPixelCacheNexusIndexes(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001661}
1662
1663/*
1664%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1665% %
1666% %
1667% %
1668+ 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 %
1669% %
1670% %
1671% %
1672%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1673%
1674% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1675% disk pixel cache as defined by the geometry parameters. A pointer to the
1676% pixels is returned if the pixels are transferred, otherwise a NULL is
1677% returned.
1678%
1679% The format of the GetAuthenticPixelCacheNexus() method is:
1680%
cristybb503372010-05-27 20:51:26 +00001681% PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1682% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001683% NexusInfo *nexus_info,ExceptionInfo *exception)
1684%
1685% A description of each parameter follows:
1686%
1687% o image: the image.
1688%
1689% o x,y,columns,rows: These values define the perimeter of a region of
1690% pixels.
1691%
1692% o nexus_info: the cache nexus to return.
1693%
1694% o exception: return any errors or warnings in this structure.
1695%
1696*/
1697
1698static inline MagickBooleanType IsNexusInCore(const CacheInfo *cache_info,
1699 NexusInfo *nexus_info)
1700{
1701 MagickOffsetType
1702 offset;
1703
cristy73724512010-04-12 14:43:14 +00001704 if (cache_info->type == PingCache)
1705 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001706 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1707 nexus_info->region.x;
1708 if (nexus_info->pixels != (cache_info->pixels+offset))
1709 return(MagickFalse);
1710 return(MagickTrue);
1711}
1712
cristye076a6e2010-08-15 19:59:43 +00001713MagickExport PixelPacket *GetAuthenticPixelCacheNexus(Image *image,
1714 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001715 NexusInfo *nexus_info,ExceptionInfo *exception)
1716{
1717 CacheInfo
1718 *cache_info;
1719
1720 PixelPacket
1721 *pixels;
1722
1723 /*
1724 Transfer pixels from the cache.
1725 */
1726 assert(image != (Image *) NULL);
1727 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001728 pixels=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
1729 if (pixels == (PixelPacket *) NULL)
1730 return((PixelPacket *) NULL);
1731 cache_info=(CacheInfo *) image->cache;
1732 assert(cache_info->signature == MagickSignature);
1733 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
1734 return(pixels);
1735 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1736 return((PixelPacket *) NULL);
1737 if (cache_info->active_index_channel != MagickFalse)
1738 if (ReadPixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse)
1739 return((PixelPacket *) NULL);
1740 return(pixels);
1741}
1742
1743/*
1744%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1745% %
1746% %
1747% %
1748+ 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 %
1749% %
1750% %
1751% %
1752%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1753%
1754% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1755% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1756%
1757% The format of the GetAuthenticPixelsFromCache() method is:
1758%
1759% PixelPacket *GetAuthenticPixelsFromCache(const Image image)
1760%
1761% A description of each parameter follows:
1762%
1763% o image: the image.
1764%
1765*/
1766static PixelPacket *GetAuthenticPixelsFromCache(const Image *image)
1767{
1768 CacheInfo
1769 *cache_info;
1770
cristy5c9e6f22010-09-17 17:31:01 +00001771 const int
1772 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001773
cristy3ed852e2009-09-05 21:47:34 +00001774 cache_info=(CacheInfo *) image->cache;
cristy6ebe97c2010-07-03 01:17:28 +00001775 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001776 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001777}
1778
1779/*
1780%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1781% %
1782% %
1783% %
1784% G e t A u t h e n t i c P i x e l Q u e u e %
1785% %
1786% %
1787% %
1788%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1789%
1790% GetAuthenticPixelQueue() returns the authentic pixels associated with the
1791% last call to QueueAuthenticPixels() or GetAuthenticPixels().
1792%
1793% The format of the GetAuthenticPixelQueue() method is:
1794%
1795% PixelPacket *GetAuthenticPixelQueue(const Image image)
1796%
1797% A description of each parameter follows:
1798%
1799% o image: the image.
1800%
1801*/
1802MagickExport PixelPacket *GetAuthenticPixelQueue(const Image *image)
1803{
1804 CacheInfo
1805 *cache_info;
1806
cristy2036f5c2010-09-19 21:18:17 +00001807 const int
1808 id = GetOpenMPThreadId();
1809
cristy3ed852e2009-09-05 21:47:34 +00001810 assert(image != (const Image *) NULL);
1811 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001812 assert(image->cache != (Cache) NULL);
1813 cache_info=(CacheInfo *) image->cache;
1814 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001815 if (cache_info->methods.get_authentic_pixels_from_handler !=
1816 (GetAuthenticPixelsFromHandler) NULL)
1817 return(cache_info->methods.get_authentic_pixels_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00001818 assert(id < (int) cache_info->number_threads);
1819 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001820}
1821
1822/*
1823%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1824% %
1825% %
1826% %
1827% G e t A u t h e n t i c P i x e l s %
1828% %
1829% %
1830% %
1831%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1832%
1833% GetAuthenticPixels() obtains a pixel region for read/write access. If the
1834% region is successfully accessed, a pointer to a PixelPacket array
1835% representing the region is returned, otherwise NULL is returned.
1836%
1837% The returned pointer may point to a temporary working copy of the pixels
1838% or it may point to the original pixels in memory. Performance is maximized
1839% if the selected region is part of one row, or one or more full rows, since
1840% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001841% if the image is in memory, or in a memory-mapped file. The returned pointer
1842% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001843%
1844% Pixels accessed via the returned pointer represent a simple array of type
1845% PixelPacket. If the image type is CMYK or if the storage class is
1846% PseduoClass, call GetAuthenticIndexQueue() after invoking
1847% GetAuthenticPixels() to obtain the black color component or colormap indexes
1848% (of type IndexPacket) corresponding to the region. Once the PixelPacket
1849% (and/or IndexPacket) array has been updated, the changes must be saved back
1850% to the underlying image using SyncAuthenticPixels() or they may be lost.
1851%
1852% The format of the GetAuthenticPixels() method is:
1853%
cristy5f959472010-05-27 22:19:46 +00001854% PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1855% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001856% ExceptionInfo *exception)
1857%
1858% A description of each parameter follows:
1859%
1860% o image: the image.
1861%
1862% o x,y,columns,rows: These values define the perimeter of a region of
1863% pixels.
1864%
1865% o exception: return any errors or warnings in this structure.
1866%
1867*/
cristybb503372010-05-27 20:51:26 +00001868MagickExport PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1869 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001870 ExceptionInfo *exception)
1871{
1872 CacheInfo
1873 *cache_info;
1874
cristy2036f5c2010-09-19 21:18:17 +00001875 const int
1876 id = GetOpenMPThreadId();
1877
cristy3ed852e2009-09-05 21:47:34 +00001878 assert(image != (Image *) NULL);
1879 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001880 assert(image->cache != (Cache) NULL);
1881 cache_info=(CacheInfo *) image->cache;
1882 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00001883 if (cache_info->methods.get_authentic_pixels_handler !=
1884 (GetAuthenticPixelsHandler) NULL)
1885 return(cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1886 rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00001887 assert(id < (int) cache_info->number_threads);
1888 return(GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1889 cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00001890}
1891
1892/*
1893%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1894% %
1895% %
1896% %
1897+ G e t A u t h e n t i c P i x e l s C a c h e %
1898% %
1899% %
1900% %
1901%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1902%
1903% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1904% as defined by the geometry parameters. A pointer to the pixels is returned
1905% if the pixels are transferred, otherwise a NULL is returned.
1906%
1907% The format of the GetAuthenticPixelsCache() method is:
1908%
cristybb503372010-05-27 20:51:26 +00001909% PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1910% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001911% ExceptionInfo *exception)
1912%
1913% A description of each parameter follows:
1914%
1915% o image: the image.
1916%
1917% o x,y,columns,rows: These values define the perimeter of a region of
1918% pixels.
1919%
1920% o exception: return any errors or warnings in this structure.
1921%
1922*/
cristybb503372010-05-27 20:51:26 +00001923static PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1924 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001925 ExceptionInfo *exception)
1926{
1927 CacheInfo
1928 *cache_info;
1929
cristy5c9e6f22010-09-17 17:31:01 +00001930 const int
1931 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001932
cristy77ff0282010-09-13 00:51:10 +00001933 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001934 if (cache_info == (Cache) NULL)
1935 return((PixelPacket *) NULL);
cristy6ebe97c2010-07-03 01:17:28 +00001936 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00001937 return(GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1938 cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00001939}
1940
1941/*
1942%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1943% %
1944% %
1945% %
1946+ G e t I m a g e E x t e n t %
1947% %
1948% %
1949% %
1950%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1951%
1952% GetImageExtent() returns the extent of the pixels associated with the
1953% last call to QueueAuthenticPixels() or GetAuthenticPixels().
1954%
1955% The format of the GetImageExtent() method is:
1956%
1957% MagickSizeType GetImageExtent(const Image *image)
1958%
1959% A description of each parameter follows:
1960%
1961% o image: the image.
1962%
1963*/
1964MagickExport MagickSizeType GetImageExtent(const Image *image)
1965{
1966 CacheInfo
1967 *cache_info;
1968
cristy5c9e6f22010-09-17 17:31:01 +00001969 const int
1970 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00001971
cristy3ed852e2009-09-05 21:47:34 +00001972 assert(image != (Image *) NULL);
1973 assert(image->signature == MagickSignature);
1974 if (image->debug != MagickFalse)
1975 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1976 assert(image->cache != (Cache) NULL);
1977 cache_info=(CacheInfo *) image->cache;
1978 assert(cache_info->signature == MagickSignature);
cristy6ebe97c2010-07-03 01:17:28 +00001979 assert(id < (int) cache_info->number_threads);
cristy2036f5c2010-09-19 21:18:17 +00001980 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00001981}
1982
1983/*
1984%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1985% %
1986% %
1987% %
1988+ G e t I m a g e P i x e l C a c h e %
1989% %
1990% %
1991% %
1992%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1993%
1994% GetImagePixelCache() ensures that there is only a single reference to the
1995% pixel cache to be modified, updating the provided cache pointer to point to
1996% a clone of the original pixel cache if necessary.
1997%
1998% The format of the GetImagePixelCache method is:
1999%
2000% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2001% ExceptionInfo *exception)
2002%
2003% A description of each parameter follows:
2004%
2005% o image: the image.
2006%
2007% o clone: any value other than MagickFalse clones the cache pixels.
2008%
2009% o exception: return any errors or warnings in this structure.
2010%
2011*/
cristy3ed852e2009-09-05 21:47:34 +00002012static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
2013{
2014 CacheInfo
2015 *cache_info;
2016
2017 /*
2018 Does the image match the pixel cache morphology?
2019 */
2020 cache_info=(CacheInfo *) image->cache;
2021 if ((image->storage_class != cache_info->storage_class) ||
2022 (image->colorspace != cache_info->colorspace) ||
2023 (image->columns != cache_info->columns) ||
2024 (image->rows != cache_info->rows) ||
2025 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2026 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2027 return(MagickFalse);
2028 return(MagickTrue);
2029}
2030
cristy77ff0282010-09-13 00:51:10 +00002031static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2032 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002033{
2034 CacheInfo
2035 *cache_info;
2036
cristy3ed852e2009-09-05 21:47:34 +00002037 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00002038 destroy,
cristy3ed852e2009-09-05 21:47:34 +00002039 status;
2040
cristy50a10922010-02-15 18:35:25 +00002041 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00002042 cpu_throttle = 0,
2043 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00002044 time_limit = 0;
2045
cristy1ea34962010-07-01 19:49:21 +00002046 static time_t
cristya21afde2010-07-02 00:45:40 +00002047 cache_genesis = 0;
cristy1ea34962010-07-01 19:49:21 +00002048
cristyc4f9f132010-03-04 18:50:01 +00002049 status=MagickTrue;
2050 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00002051 if (cpu_throttle == 0)
2052 {
2053 char
2054 *limit;
2055
2056 /*
2057 Set CPU throttle in milleseconds.
2058 */
2059 cpu_throttle=MagickResourceInfinity;
2060 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2061 if (limit == (char *) NULL)
2062 limit=GetPolicyValue("throttle");
2063 if (limit != (char *) NULL)
2064 {
2065 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2066 limit=DestroyString(limit);
2067 }
2068 }
2069 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2070 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00002071 if (time_limit == 0)
2072 {
cristy6ebe97c2010-07-03 01:17:28 +00002073 /*
2074 Set the exire time in seconds.
2075 */
cristy1ea34962010-07-01 19:49:21 +00002076 time_limit=GetMagickResourceLimit(TimeResource);
cristya21afde2010-07-02 00:45:40 +00002077 cache_genesis=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00002078 }
2079 if ((time_limit != MagickResourceInfinity) &&
cristya21afde2010-07-02 00:45:40 +00002080 ((MagickSizeType) (time((time_t *) NULL)-cache_genesis) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00002081 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00002082 assert(image->cache != (Cache) NULL);
2083 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002084 destroy=MagickFalse;
cristy01b7eb02009-09-10 23:10:14 +00002085 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002086 {
cristyaaa0cb62010-02-15 17:47:27 +00002087 LockSemaphoreInfo(cache_info->semaphore);
2088 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002089 {
cristyaaa0cb62010-02-15 17:47:27 +00002090 Image
2091 clone_image;
2092
2093 CacheInfo
2094 *clone_info;
2095
2096 /*
2097 Clone pixel cache.
2098 */
2099 clone_image=(*image);
cristy93505cf2010-08-10 21:37:49 +00002100 clone_image.semaphore=AllocateSemaphoreInfo();
2101 clone_image.reference_count=1;
cristyaaa0cb62010-02-15 17:47:27 +00002102 clone_image.cache=ClonePixelCache(cache_info);
2103 clone_info=(CacheInfo *) clone_image.cache;
cristyabd6e372010-09-15 19:11:26 +00002104 status=OpenPixelCache(&clone_image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00002105 if (status != MagickFalse)
2106 {
cristyabd6e372010-09-15 19:11:26 +00002107 if (clone != MagickFalse)
2108 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002109 if (status != MagickFalse)
2110 {
cristyabd6e372010-09-15 19:11:26 +00002111 destroy=MagickTrue;
2112 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00002113 }
2114 }
cristy93505cf2010-08-10 21:37:49 +00002115 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002116 }
cristyaaa0cb62010-02-15 17:47:27 +00002117 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002118 }
cristy4320e0e2009-09-10 15:00:08 +00002119 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002120 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002121 if (status != MagickFalse)
2122 {
2123 /*
2124 Ensure the image matches the pixel cache morphology.
2125 */
2126 image->taint=MagickTrue;
2127 image->type=UndefinedType;
cristydd438462010-05-06 13:44:04 +00002128 if (image->colorspace == GRAYColorspace)
2129 image->colorspace=RGBColorspace;
cristy3ed852e2009-09-05 21:47:34 +00002130 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2131 status=OpenPixelCache(image,IOMode,exception);
2132 }
cristyf84a1932010-01-03 18:00:18 +00002133 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002134 if (status == MagickFalse)
2135 return((Cache) NULL);
2136 return(image->cache);
2137}
2138
2139/*
2140%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2141% %
2142% %
2143% %
2144% G e t O n e A u t h e n t i c P i x e l %
2145% %
2146% %
2147% %
2148%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2149%
2150% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2151% location. The image background color is returned if an error occurs.
2152%
2153% The format of the GetOneAuthenticPixel() method is:
2154%
cristybb503372010-05-27 20:51:26 +00002155% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2156% const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002157%
2158% A description of each parameter follows:
2159%
2160% o image: the image.
2161%
2162% o x,y: These values define the location of the pixel to return.
2163%
2164% o pixel: return a pixel at the specified (x,y) location.
2165%
2166% o exception: return any errors or warnings in this structure.
2167%
2168*/
cristyacbbb7c2010-06-30 18:56:48 +00002169MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2170 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002171{
2172 CacheInfo
2173 *cache_info;
2174
cristy2036f5c2010-09-19 21:18:17 +00002175 PixelPacket
2176 *pixels;
2177
cristy3ed852e2009-09-05 21:47:34 +00002178 assert(image != (Image *) NULL);
2179 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002180 assert(image->cache != (Cache) NULL);
2181 cache_info=(CacheInfo *) image->cache;
2182 assert(cache_info->signature == MagickSignature);
2183 *pixel=image->background_color;
cristyd317f372010-09-18 01:42:20 +00002184 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2185 (GetOneAuthenticPixelFromHandler) NULL)
2186 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2187 pixel,exception));
cristy2036f5c2010-09-19 21:18:17 +00002188 *pixel=image->background_color;
2189 pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2190 if (pixels == (PixelPacket *) NULL)
2191 return(MagickFalse);
2192 *pixel=(*pixels);
2193 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002194}
2195
2196/*
2197%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2198% %
2199% %
2200% %
2201+ 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 %
2202% %
2203% %
2204% %
2205%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2206%
2207% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2208% location. The image background color is returned if an error occurs.
2209%
2210% The format of the GetOneAuthenticPixelFromCache() method is:
2211%
2212% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy5f959472010-05-27 22:19:46 +00002213% const ssize_t x,const ssize_t y,PixelPacket *pixel,
2214% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002215%
2216% A description of each parameter follows:
2217%
2218% o image: the image.
2219%
2220% o x,y: These values define the location of the pixel to return.
2221%
2222% o pixel: return a pixel at the specified (x,y) location.
2223%
2224% o exception: return any errors or warnings in this structure.
2225%
2226*/
2227static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristybb503372010-05-27 20:51:26 +00002228 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002229{
cristy0158a4b2010-09-20 13:59:45 +00002230 CacheInfo
2231 *cache_info;
2232
2233 const int
2234 id = GetOpenMPThreadId();
2235
cristy3ed852e2009-09-05 21:47:34 +00002236 PixelPacket
2237 *pixels;
2238
cristy0158a4b2010-09-20 13:59:45 +00002239 assert(image != (const Image *) NULL);
2240 assert(image->signature == MagickSignature);
2241 assert(image->cache != (Cache) NULL);
2242 cache_info=(CacheInfo *) image->cache;
2243 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002244 *pixel=image->background_color;
cristy0158a4b2010-09-20 13:59:45 +00002245 assert(id < (int) cache_info->number_threads);
2246 pixels=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,
2247 cache_info->nexus_info[id],exception);
cristy3ed852e2009-09-05 21:47:34 +00002248 if (pixels == (PixelPacket *) NULL)
2249 return(MagickFalse);
2250 *pixel=(*pixels);
2251 return(MagickTrue);
2252}
2253
2254/*
2255%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2256% %
2257% %
2258% %
2259% G e t O n e V i r t u a l M a g i c k P i x e l %
2260% %
2261% %
2262% %
2263%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2264%
2265% GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2266% location. The image background color is returned if an error occurs. If
2267% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2268%
2269% The format of the GetOneVirtualMagickPixel() method is:
2270%
2271% MagickBooleanType GetOneVirtualMagickPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002272% const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
cristy3ed852e2009-09-05 21:47:34 +00002273% ExceptionInfo exception)
2274%
2275% A description of each parameter follows:
2276%
2277% o image: the image.
2278%
2279% o x,y: these values define the location of the pixel to return.
2280%
2281% o pixel: return a pixel at the specified (x,y) location.
2282%
2283% o exception: return any errors or warnings in this structure.
2284%
2285*/
2286MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
cristyacbbb7c2010-06-30 18:56:48 +00002287 const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
2288 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002289{
2290 CacheInfo
2291 *cache_info;
2292
cristy0158a4b2010-09-20 13:59:45 +00002293 const int
2294 id = GetOpenMPThreadId();
2295
cristy3ed852e2009-09-05 21:47:34 +00002296 register const IndexPacket
2297 *indexes;
2298
2299 register const PixelPacket
cristy0158a4b2010-09-20 13:59:45 +00002300 *pixels;
cristy3ed852e2009-09-05 21:47:34 +00002301
2302 assert(image != (const Image *) NULL);
2303 assert(image->signature == MagickSignature);
2304 assert(image->cache != (Cache) NULL);
2305 cache_info=(CacheInfo *) image->cache;
2306 assert(cache_info->signature == MagickSignature);
2307 GetMagickPixelPacket(image,pixel);
cristy0158a4b2010-09-20 13:59:45 +00002308 assert(id < (int) cache_info->number_threads);
2309 pixels=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2310 1UL,1UL,cache_info->nexus_info[id],exception);
2311 if (pixels == (const PixelPacket *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002312 return(MagickFalse);
cristy0158a4b2010-09-20 13:59:45 +00002313 indexes=GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]);
2314 SetMagickPixelPacket(image,pixels,indexes,pixel);
cristy3ed852e2009-09-05 21:47:34 +00002315 return(MagickTrue);
2316}
2317
2318/*
2319%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2320% %
2321% %
2322% %
2323% G e t O n e V i r t u a l M e t h o d P i x e l %
2324% %
2325% %
2326% %
2327%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2328%
2329% GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2330% location as defined by specified pixel method. The image background color
2331% is returned if an error occurs. If you plan to modify the pixel, use
2332% GetOneAuthenticPixel() instead.
2333%
2334% The format of the GetOneVirtualMethodPixel() method is:
2335%
2336% MagickBooleanType GetOneVirtualMethodPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002337% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2338% const ssize_t y,Pixelpacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002339%
2340% A description of each parameter follows:
2341%
2342% o image: the image.
2343%
2344% o virtual_pixel_method: the virtual pixel method.
2345%
2346% o x,y: These values define the location of the pixel to return.
2347%
2348% o pixel: return a pixel at the specified (x,y) location.
2349%
2350% o exception: return any errors or warnings in this structure.
2351%
2352*/
2353MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002354 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002355 PixelPacket *pixel,ExceptionInfo *exception)
2356{
cristy3ed852e2009-09-05 21:47:34 +00002357 CacheInfo
2358 *cache_info;
2359
cristy0158a4b2010-09-20 13:59:45 +00002360 const int
2361 id = GetOpenMPThreadId();
2362
cristy2036f5c2010-09-19 21:18:17 +00002363 const PixelPacket
2364 *pixels;
2365
cristy3ed852e2009-09-05 21:47:34 +00002366 assert(image != (const Image *) NULL);
2367 assert(image->signature == MagickSignature);
2368 assert(image->cache != (Cache) NULL);
2369 cache_info=(CacheInfo *) image->cache;
2370 assert(cache_info->signature == MagickSignature);
2371 *pixel=image->background_color;
cristyd317f372010-09-18 01:42:20 +00002372 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2373 (GetOneVirtualPixelFromHandler) NULL)
2374 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2375 virtual_pixel_method,x,y,pixel,exception));
cristy2036f5c2010-09-19 21:18:17 +00002376 *pixel=image->background_color;
cristy0158a4b2010-09-20 13:59:45 +00002377 assert(id < (int) cache_info->number_threads);
2378 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2379 cache_info->nexus_info[id],exception);
cristy2036f5c2010-09-19 21:18:17 +00002380 if (pixels == (const PixelPacket *) NULL)
2381 return(MagickFalse);
2382 *pixel=(*pixels);
2383 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002384}
2385
2386/*
2387%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2388% %
2389% %
2390% %
2391% G e t O n e V i r t u a l P i x e l %
2392% %
2393% %
2394% %
2395%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2396%
2397% GetOneVirtualPixel() returns a single virtual pixel at the specified
2398% (x,y) location. The image background color is returned if an error occurs.
2399% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2400%
2401% The format of the GetOneVirtualPixel() method is:
2402%
cristybb503372010-05-27 20:51:26 +00002403% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2404% const ssize_t y,PixelPacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002405%
2406% A description of each parameter follows:
2407%
2408% o image: the image.
2409%
2410% o x,y: These values define the location of the pixel to return.
2411%
2412% o pixel: return a pixel at the specified (x,y) location.
2413%
2414% o exception: return any errors or warnings in this structure.
2415%
2416*/
2417MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002418 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002419{
cristy3ed852e2009-09-05 21:47:34 +00002420 CacheInfo
2421 *cache_info;
2422
cristy0158a4b2010-09-20 13:59:45 +00002423 const int
2424 id = GetOpenMPThreadId();
2425
cristy2036f5c2010-09-19 21:18:17 +00002426 const PixelPacket
2427 *pixels;
2428
cristy3ed852e2009-09-05 21:47:34 +00002429 assert(image != (const Image *) NULL);
2430 assert(image->signature == MagickSignature);
2431 assert(image->cache != (Cache) NULL);
2432 cache_info=(CacheInfo *) image->cache;
2433 assert(cache_info->signature == MagickSignature);
2434 *pixel=image->background_color;
cristyd317f372010-09-18 01:42:20 +00002435 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2436 (GetOneVirtualPixelFromHandler) NULL)
2437 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2438 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
cristy0158a4b2010-09-20 13:59:45 +00002439 assert(id < (int) cache_info->number_threads);
2440 pixels=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2441 1UL,1UL,cache_info->nexus_info[id],exception);
cristy2036f5c2010-09-19 21:18:17 +00002442 if (pixels == (const PixelPacket *) NULL)
2443 return(MagickFalse);
2444 *pixel=(*pixels);
2445 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00002446}
2447
2448/*
2449%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2450% %
2451% %
2452% %
2453+ 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 %
2454% %
2455% %
2456% %
2457%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2458%
2459% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2460% specified (x,y) location. The image background color is returned if an
2461% error occurs.
2462%
2463% The format of the GetOneVirtualPixelFromCache() method is:
2464%
2465% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristybb503372010-05-27 20:51:26 +00002466% const VirtualPixelPacket method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002467% PixelPacket *pixel,ExceptionInfo *exception)
2468%
2469% A description of each parameter follows:
2470%
2471% o image: the image.
2472%
2473% o virtual_pixel_method: the virtual pixel method.
2474%
2475% o x,y: These values define the location of the pixel to return.
2476%
2477% o pixel: return a pixel at the specified (x,y) location.
2478%
2479% o exception: return any errors or warnings in this structure.
2480%
2481*/
2482static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002483 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002484 PixelPacket *pixel,ExceptionInfo *exception)
2485{
cristy0158a4b2010-09-20 13:59:45 +00002486 CacheInfo
2487 *cache_info;
2488
2489 const int
2490 id = GetOpenMPThreadId();
2491
cristy3ed852e2009-09-05 21:47:34 +00002492 const PixelPacket
2493 *pixels;
2494
2495 *pixel=image->background_color;
cristy0158a4b2010-09-20 13:59:45 +00002496 cache_info=(CacheInfo *) image->cache;
2497 assert(id < (int) cache_info->number_threads);
2498 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2499 cache_info->nexus_info[id],exception);
cristy3ed852e2009-09-05 21:47:34 +00002500 if (pixels == (const PixelPacket *) NULL)
2501 return(MagickFalse);
2502 *pixel=(*pixels);
2503 return(MagickTrue);
2504}
2505
2506/*
2507%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2508% %
2509% %
2510% %
2511+ G e t P i x e l C a c h e C o l o r s p a c e %
2512% %
2513% %
2514% %
2515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2516%
2517% GetPixelCacheColorspace() returns the class type of the pixel cache.
2518%
2519% The format of the GetPixelCacheColorspace() method is:
2520%
2521% Colorspace GetPixelCacheColorspace(Cache cache)
2522%
2523% A description of each parameter follows:
2524%
2525% o cache: the pixel cache.
2526%
2527*/
2528MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
2529{
2530 CacheInfo
2531 *cache_info;
2532
2533 assert(cache != (Cache) NULL);
2534 cache_info=(CacheInfo *) cache;
2535 assert(cache_info->signature == MagickSignature);
2536 if (cache_info->debug != MagickFalse)
2537 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2538 cache_info->filename);
2539 return(cache_info->colorspace);
2540}
2541
2542/*
2543%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2544% %
2545% %
2546% %
2547+ G e t P i x e l C a c h e M e t h o d s %
2548% %
2549% %
2550% %
2551%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2552%
2553% GetPixelCacheMethods() initializes the CacheMethods structure.
2554%
2555% The format of the GetPixelCacheMethods() method is:
2556%
2557% void GetPixelCacheMethods(CacheMethods *cache_methods)
2558%
2559% A description of each parameter follows:
2560%
2561% o cache_methods: Specifies a pointer to a CacheMethods structure.
2562%
2563*/
2564MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
2565{
2566 assert(cache_methods != (CacheMethods *) NULL);
2567 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2568 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2569 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2570 cache_methods->get_virtual_indexes_from_handler=GetVirtualIndexesFromCache;
2571 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2572 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2573 cache_methods->get_authentic_indexes_from_handler=
2574 GetAuthenticIndexesFromCache;
2575 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2576 cache_methods->get_one_authentic_pixel_from_handler=
2577 GetOneAuthenticPixelFromCache;
2578 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2579 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2580 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2581}
2582
2583/*
2584%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2585% %
2586% %
2587% %
2588+ G e t P i x e l C a c h e N e x u s E x t e n t %
2589% %
2590% %
2591% %
2592%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2593%
2594% GetPixelCacheNexusExtent() returns the extent of the pixels associated with
2595% the last call to SetPixelCacheNexusPixels() or GetPixelCacheNexusPixels().
2596%
2597% The format of the GetPixelCacheNexusExtent() method is:
2598%
2599% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2600% NexusInfo *nexus_info)
2601%
2602% A description of each parameter follows:
2603%
2604% o nexus_info: the nexus info.
2605%
2606*/
2607MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2608 NexusInfo *nexus_info)
2609{
2610 CacheInfo
2611 *cache_info;
2612
2613 MagickSizeType
2614 extent;
2615
cristy0158a4b2010-09-20 13:59:45 +00002616 assert(cache != (Cache) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002617 cache_info=(CacheInfo *) cache;
2618 assert(cache_info->signature == MagickSignature);
2619 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2620 if (extent == 0)
2621 return((MagickSizeType) cache_info->columns*cache_info->rows);
2622 return(extent);
2623}
2624
2625/*
2626%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2627% %
2628% %
2629% %
2630+ 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 %
2631% %
2632% %
2633% %
2634%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2635%
2636% GetPixelCacheNexusIndexes() returns the indexes associated with the
2637% specified cache nexus.
2638%
2639% The format of the GetPixelCacheNexusIndexes() method is:
2640%
2641% IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2642% NexusInfo *nexus_info)
2643%
2644% A description of each parameter follows:
2645%
2646% o cache: the pixel cache.
2647%
2648% o nexus_info: the cache nexus to return the colormap indexes.
2649%
2650*/
2651MagickExport IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2652 NexusInfo *nexus_info)
2653{
2654 CacheInfo
2655 *cache_info;
2656
2657 if (cache == (Cache) NULL)
2658 return((IndexPacket *) NULL);
2659 cache_info=(CacheInfo *) cache;
2660 assert(cache_info->signature == MagickSignature);
2661 if (cache_info->storage_class == UndefinedClass)
2662 return((IndexPacket *) NULL);
2663 return(nexus_info->indexes);
2664}
2665
2666/*
2667%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2668% %
2669% %
2670% %
2671+ G e t P i x e l C a c h e N e x u s P i x e l s %
2672% %
2673% %
2674% %
2675%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2676%
2677% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2678% cache nexus.
2679%
2680% The format of the GetPixelCacheNexusPixels() method is:
2681%
2682% PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2683% NexusInfo *nexus_info)
2684%
2685% A description of each parameter follows:
2686%
2687% o cache: the pixel cache.
2688%
2689% o nexus_info: the cache nexus to return the pixels.
2690%
2691*/
2692MagickExport PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2693 NexusInfo *nexus_info)
2694{
2695 CacheInfo
2696 *cache_info;
2697
2698 if (cache == (Cache) NULL)
2699 return((PixelPacket *) NULL);
2700 cache_info=(CacheInfo *) cache;
2701 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002702 if (cache_info->storage_class == UndefinedClass)
2703 return((PixelPacket *) NULL);
2704 return(nexus_info->pixels);
2705}
2706
2707/*
2708%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2709% %
2710% %
2711% %
cristy056ba772010-01-02 23:33:54 +00002712+ G e t P i x e l C a c h e P i x e l s %
2713% %
2714% %
2715% %
2716%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2717%
2718% GetPixelCachePixels() returns the pixels associated with the specified image.
2719%
2720% The format of the GetPixelCachePixels() method is:
2721%
cristyf84a1932010-01-03 18:00:18 +00002722% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2723% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002724%
2725% A description of each parameter follows:
2726%
2727% o image: the image.
2728%
2729% o length: the pixel cache length.
2730%
cristyf84a1932010-01-03 18:00:18 +00002731% o exception: return any errors or warnings in this structure.
2732%
cristy056ba772010-01-02 23:33:54 +00002733*/
cristyf84a1932010-01-03 18:00:18 +00002734MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2735 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002736{
2737 CacheInfo
2738 *cache_info;
2739
2740 assert(image != (const Image *) NULL);
2741 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002742 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00002743 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002744 assert(cache_info->signature == MagickSignature);
2745 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002746 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002747 return((void *) NULL);
2748 *length=cache_info->length;
2749 return((void *) cache_info->pixels);
2750}
2751
2752/*
2753%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2754% %
2755% %
2756% %
cristyb32b90a2009-09-07 21:45:48 +00002757+ 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 +00002758% %
2759% %
2760% %
2761%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2762%
2763% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2764%
2765% The format of the GetPixelCacheStorageClass() method is:
2766%
2767% ClassType GetPixelCacheStorageClass(Cache cache)
2768%
2769% A description of each parameter follows:
2770%
2771% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2772%
2773% o cache: the pixel cache.
2774%
2775*/
2776MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
2777{
2778 CacheInfo
2779 *cache_info;
2780
2781 assert(cache != (Cache) NULL);
2782 cache_info=(CacheInfo *) cache;
2783 assert(cache_info->signature == MagickSignature);
2784 if (cache_info->debug != MagickFalse)
2785 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2786 cache_info->filename);
2787 return(cache_info->storage_class);
2788}
2789
2790/*
2791%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2792% %
2793% %
2794% %
cristyb32b90a2009-09-07 21:45:48 +00002795+ G e t P i x e l C a c h e T i l e S i z e %
2796% %
2797% %
2798% %
2799%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2800%
2801% GetPixelCacheTileSize() returns the pixel cache tile size.
2802%
2803% The format of the GetPixelCacheTileSize() method is:
2804%
cristybb503372010-05-27 20:51:26 +00002805% void GetPixelCacheTileSize(const Image *image,size_t *width,
2806% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002807%
2808% A description of each parameter follows:
2809%
2810% o image: the image.
2811%
2812% o width: the optimize cache tile width in pixels.
2813%
2814% o height: the optimize cache tile height in pixels.
2815%
2816*/
cristybb503372010-05-27 20:51:26 +00002817MagickExport void GetPixelCacheTileSize(const Image *image,size_t *width,
2818 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002819{
2820 CacheInfo
2821 *cache_info;
2822
2823 assert(image != (Image *) NULL);
2824 assert(image->signature == MagickSignature);
2825 if (image->debug != MagickFalse)
2826 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2827 assert(image->cache != (Cache) NULL);
2828 cache_info=(CacheInfo *) image->cache;
2829 assert(cache_info->signature == MagickSignature);
2830 *width=2048UL/sizeof(PixelPacket);
2831 if (GetPixelCacheType(image) == DiskCache)
cristydaa97692009-09-13 02:10:35 +00002832 *width=8192UL/sizeof(PixelPacket);
cristyb32b90a2009-09-07 21:45:48 +00002833 *height=(*width);
2834}
2835
2836/*
2837%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2838% %
2839% %
2840% %
2841+ G e t P i x e l C a c h e T y p e %
2842% %
2843% %
2844% %
2845%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2846%
2847% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2848%
2849% The format of the GetPixelCacheType() method is:
2850%
2851% CacheType GetPixelCacheType(const Image *image)
2852%
2853% A description of each parameter follows:
2854%
2855% o image: the image.
2856%
2857*/
2858MagickExport CacheType GetPixelCacheType(const Image *image)
2859{
2860 CacheInfo
2861 *cache_info;
2862
2863 assert(image != (Image *) NULL);
2864 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002865 assert(image->cache != (Cache) NULL);
2866 cache_info=(CacheInfo *) image->cache;
2867 assert(cache_info->signature == MagickSignature);
2868 return(cache_info->type);
2869}
2870
2871/*
2872%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2873% %
2874% %
2875% %
cristy3ed852e2009-09-05 21:47:34 +00002876+ 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 %
2877% %
2878% %
2879% %
2880%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2881%
2882% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2883% pixel cache. A virtual pixel is any pixel access that is outside the
2884% boundaries of the image cache.
2885%
2886% The format of the GetPixelCacheVirtualMethod() method is:
2887%
2888% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2889%
2890% A description of each parameter follows:
2891%
2892% o image: the image.
2893%
2894*/
2895MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2896{
2897 CacheInfo
2898 *cache_info;
2899
2900 assert(image != (Image *) NULL);
2901 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002902 assert(image->cache != (Cache) NULL);
2903 cache_info=(CacheInfo *) image->cache;
2904 assert(cache_info->signature == MagickSignature);
2905 return(cache_info->virtual_pixel_method);
2906}
2907
2908/*
2909%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2910% %
2911% %
2912% %
2913+ 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 %
2914% %
2915% %
2916% %
2917%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2918%
2919% GetVirtualIndexesFromCache() returns the indexes associated with the last
2920% call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2921%
2922% The format of the GetVirtualIndexesFromCache() method is:
2923%
2924% IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2925%
2926% A description of each parameter follows:
2927%
2928% o image: the image.
2929%
2930*/
2931static const IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2932{
2933 CacheInfo
2934 *cache_info;
2935
cristy5c9e6f22010-09-17 17:31:01 +00002936 const int
2937 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00002938
cristy3ed852e2009-09-05 21:47:34 +00002939 cache_info=(CacheInfo *) image->cache;
cristy6ebe97c2010-07-03 01:17:28 +00002940 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00002941 return(GetVirtualIndexesFromNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00002942}
2943
2944/*
2945%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2946% %
2947% %
2948% %
2949+ 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 %
2950% %
2951% %
2952% %
2953%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2954%
2955% GetVirtualIndexesFromNexus() returns the indexes associated with the
2956% specified cache nexus.
2957%
2958% The format of the GetVirtualIndexesFromNexus() method is:
2959%
2960% const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2961% NexusInfo *nexus_info)
2962%
2963% A description of each parameter follows:
2964%
2965% o cache: the pixel cache.
2966%
2967% o nexus_info: the cache nexus to return the colormap indexes.
2968%
2969*/
2970MagickExport const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2971 NexusInfo *nexus_info)
2972{
2973 CacheInfo
2974 *cache_info;
2975
2976 if (cache == (Cache) NULL)
2977 return((IndexPacket *) NULL);
2978 cache_info=(CacheInfo *) cache;
2979 assert(cache_info->signature == MagickSignature);
2980 if (cache_info->storage_class == UndefinedClass)
2981 return((IndexPacket *) NULL);
2982 return(nexus_info->indexes);
2983}
2984
2985/*
2986%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2987% %
2988% %
2989% %
2990% G e t V i r t u a l I n d e x Q u e u e %
2991% %
2992% %
2993% %
2994%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2995%
2996% GetVirtualIndexQueue() returns the virtual black channel or the
2997% colormap indexes associated with the last call to QueueAuthenticPixels() or
2998% GetVirtualPixels(). NULL is returned if the black channel or colormap
2999% indexes are not available.
3000%
3001% The format of the GetVirtualIndexQueue() method is:
3002%
3003% const IndexPacket *GetVirtualIndexQueue(const Image *image)
3004%
3005% A description of each parameter follows:
3006%
3007% o image: the image.
3008%
3009*/
3010MagickExport const IndexPacket *GetVirtualIndexQueue(const Image *image)
3011{
3012 CacheInfo
3013 *cache_info;
3014
cristy2036f5c2010-09-19 21:18:17 +00003015 const int
3016 id = GetOpenMPThreadId();
3017
cristy3ed852e2009-09-05 21:47:34 +00003018 assert(image != (const Image *) NULL);
3019 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003020 assert(image->cache != (Cache) NULL);
3021 cache_info=(CacheInfo *) image->cache;
3022 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003023 if (cache_info->methods.get_virtual_indexes_from_handler !=
3024 (GetVirtualIndexesFromHandler) NULL)
3025 return(cache_info->methods.get_virtual_indexes_from_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003026 assert(id < (int) cache_info->number_threads);
3027 return(GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003028}
3029
3030/*
3031%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3032% %
3033% %
3034% %
3035+ 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 %
3036% %
3037% %
3038% %
3039%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3040%
3041% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3042% pixel cache as defined by the geometry parameters. A pointer to the pixels
3043% is returned if the pixels are transferred, otherwise a NULL is returned.
3044%
3045% The format of the GetVirtualPixelsFromNexus() method is:
3046%
3047% PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003048% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00003049% const size_t columns,const size_t rows,NexusInfo *nexus_info,
3050% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003051%
3052% A description of each parameter follows:
3053%
3054% o image: the image.
3055%
3056% o virtual_pixel_method: the virtual pixel method.
3057%
3058% o x,y,columns,rows: These values define the perimeter of a region of
3059% pixels.
3060%
3061% o nexus_info: the cache nexus to acquire.
3062%
3063% o exception: return any errors or warnings in this structure.
3064%
3065*/
3066
cristybb503372010-05-27 20:51:26 +00003067static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003068 DitherMatrix[64] =
3069 {
3070 0, 48, 12, 60, 3, 51, 15, 63,
3071 32, 16, 44, 28, 35, 19, 47, 31,
3072 8, 56, 4, 52, 11, 59, 7, 55,
3073 40, 24, 36, 20, 43, 27, 39, 23,
3074 2, 50, 14, 62, 1, 49, 13, 61,
3075 34, 18, 46, 30, 33, 17, 45, 29,
3076 10, 58, 6, 54, 9, 57, 5, 53,
3077 42, 26, 38, 22, 41, 25, 37, 21
3078 };
3079
cristybb503372010-05-27 20:51:26 +00003080static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003081{
cristybb503372010-05-27 20:51:26 +00003082 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003083 index;
3084
3085 index=x+DitherMatrix[x & 0x07]-32L;
3086 if (index < 0L)
3087 return(0L);
cristybb503372010-05-27 20:51:26 +00003088 if (index >= (ssize_t) columns)
3089 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00003090 return(index);
3091}
3092
cristybb503372010-05-27 20:51:26 +00003093static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003094{
cristybb503372010-05-27 20:51:26 +00003095 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003096 index;
3097
3098 index=y+DitherMatrix[y & 0x07]-32L;
3099 if (index < 0L)
3100 return(0L);
cristybb503372010-05-27 20:51:26 +00003101 if (index >= (ssize_t) rows)
3102 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00003103 return(index);
3104}
3105
cristybb503372010-05-27 20:51:26 +00003106static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003107{
3108 if (x < 0L)
3109 return(0L);
cristybb503372010-05-27 20:51:26 +00003110 if (x >= (ssize_t) columns)
3111 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003112 return(x);
3113}
3114
cristybb503372010-05-27 20:51:26 +00003115static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003116{
3117 if (y < 0L)
3118 return(0L);
cristybb503372010-05-27 20:51:26 +00003119 if (y >= (ssize_t) rows)
3120 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003121 return(y);
3122}
3123
cristybb503372010-05-27 20:51:26 +00003124static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003125{
cristybb503372010-05-27 20:51:26 +00003126 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003127}
3128
cristybb503372010-05-27 20:51:26 +00003129static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003130{
cristybb503372010-05-27 20:51:26 +00003131 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003132}
3133
3134/*
3135 VirtualPixelModulo() computes the remainder of dividing offset by extent. It
3136 returns not only the quotient (tile the offset falls in) but also the positive
3137 remainer within that tile such that 0 <= remainder < extent. This method is
3138 essentially a ldiv() using a floored modulo division rather than the normal
3139 default truncated modulo division.
3140*/
cristybb503372010-05-27 20:51:26 +00003141static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3142 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003143{
3144 MagickModulo
3145 modulo;
3146
cristybb503372010-05-27 20:51:26 +00003147 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003148 if (offset < 0L)
3149 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003150 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003151 return(modulo);
3152}
3153
3154MagickExport const PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003155 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3156 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003157 ExceptionInfo *exception)
3158{
3159 CacheInfo
3160 *cache_info;
3161
cristyc3ec0d42010-04-07 01:18:08 +00003162 IndexPacket
3163 virtual_index;
3164
cristy3ed852e2009-09-05 21:47:34 +00003165 MagickOffsetType
3166 offset;
3167
3168 MagickSizeType
3169 length,
3170 number_pixels;
3171
3172 NexusInfo
3173 **virtual_nexus;
3174
3175 PixelPacket
3176 *pixels,
3177 virtual_pixel;
3178
3179 RectangleInfo
3180 region;
3181
3182 register const IndexPacket
cristyc3ec0d42010-04-07 01:18:08 +00003183 *restrict virtual_indexes;
cristy3ed852e2009-09-05 21:47:34 +00003184
3185 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003186 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003187
3188 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003189 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003190
cristye076a6e2010-08-15 19:59:43 +00003191 register PixelPacket
3192 *restrict q;
3193
cristybb503372010-05-27 20:51:26 +00003194 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003195 u,
3196 v;
3197
cristy3ed852e2009-09-05 21:47:34 +00003198 /*
3199 Acquire pixels.
3200 */
cristy3ed852e2009-09-05 21:47:34 +00003201 cache_info=(CacheInfo *) image->cache;
cristy4cfbb3f2010-03-14 20:40:23 +00003202 if (cache_info->type == UndefinedCache)
cristy3ed852e2009-09-05 21:47:34 +00003203 return((const PixelPacket *) NULL);
3204 region.x=x;
3205 region.y=y;
3206 region.width=columns;
3207 region.height=rows;
3208 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
3209 if (pixels == (PixelPacket *) NULL)
3210 return((const PixelPacket *) NULL);
cristydf415c82010-03-11 16:47:50 +00003211 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3212 nexus_info->region.x;
3213 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3214 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003215 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3216 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003217 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3218 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003219 {
3220 MagickBooleanType
3221 status;
3222
3223 /*
3224 Pixel request is inside cache extents.
3225 */
3226 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
3227 return(pixels);
3228 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3229 if (status == MagickFalse)
3230 return((const PixelPacket *) NULL);
3231 if ((cache_info->storage_class == PseudoClass) ||
3232 (cache_info->colorspace == CMYKColorspace))
3233 {
3234 status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
3235 if (status == MagickFalse)
3236 return((const PixelPacket *) NULL);
3237 }
3238 return(pixels);
3239 }
3240 /*
3241 Pixel request is outside cache extents.
3242 */
3243 q=pixels;
3244 indexes=GetPixelCacheNexusIndexes(cache_info,nexus_info);
3245 virtual_nexus=AcquirePixelCacheNexus(1);
3246 if (virtual_nexus == (NexusInfo **) NULL)
3247 {
3248 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3249 "UnableToGetCacheNexus","`%s'",image->filename);
3250 return((const PixelPacket *) NULL);
3251 }
3252 switch (virtual_pixel_method)
3253 {
3254 case BlackVirtualPixelMethod:
3255 {
cristy4789f0d2010-01-10 00:01:06 +00003256 SetRedPixelComponent(&virtual_pixel,0);
3257 SetGreenPixelComponent(&virtual_pixel,0);
3258 SetBluePixelComponent(&virtual_pixel,0);
3259 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003260 break;
3261 }
3262 case GrayVirtualPixelMethod:
3263 {
cristy4789f0d2010-01-10 00:01:06 +00003264 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3265 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3266 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3267 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003268 break;
3269 }
3270 case TransparentVirtualPixelMethod:
3271 {
cristy4789f0d2010-01-10 00:01:06 +00003272 SetRedPixelComponent(&virtual_pixel,0);
3273 SetGreenPixelComponent(&virtual_pixel,0);
3274 SetBluePixelComponent(&virtual_pixel,0);
3275 SetOpacityPixelComponent(&virtual_pixel,TransparentOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003276 break;
3277 }
3278 case MaskVirtualPixelMethod:
3279 case WhiteVirtualPixelMethod:
3280 {
cristy4789f0d2010-01-10 00:01:06 +00003281 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3282 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3283 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3284 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003285 break;
3286 }
3287 default:
3288 {
3289 virtual_pixel=image->background_color;
3290 break;
3291 }
3292 }
cristyc3ec0d42010-04-07 01:18:08 +00003293 virtual_index=0;
cristybb503372010-05-27 20:51:26 +00003294 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003295 {
cristybb503372010-05-27 20:51:26 +00003296 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003297 {
3298 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003299 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003300 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3301 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003302 {
3303 MagickModulo
3304 x_modulo,
3305 y_modulo;
3306
3307 /*
3308 Transfer a single pixel.
3309 */
3310 length=(MagickSizeType) 1;
3311 switch (virtual_pixel_method)
3312 {
3313 case BackgroundVirtualPixelMethod:
3314 case ConstantVirtualPixelMethod:
3315 case BlackVirtualPixelMethod:
3316 case GrayVirtualPixelMethod:
3317 case TransparentVirtualPixelMethod:
3318 case MaskVirtualPixelMethod:
3319 case WhiteVirtualPixelMethod:
3320 {
3321 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003322 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003323 break;
3324 }
3325 case EdgeVirtualPixelMethod:
3326 default:
3327 {
3328 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003329 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003330 1UL,1UL,virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003331 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3332 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003333 break;
3334 }
3335 case RandomVirtualPixelMethod:
3336 {
3337 if (cache_info->random_info == (RandomInfo *) NULL)
3338 cache_info->random_info=AcquireRandomInfo();
3339 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003340 RandomX(cache_info->random_info,cache_info->columns),
3341 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003342 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003343 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3344 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003345 break;
3346 }
3347 case DitherVirtualPixelMethod:
3348 {
3349 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003350 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003351 1UL,1UL,virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003352 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3353 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003354 break;
3355 }
3356 case TileVirtualPixelMethod:
3357 {
3358 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3359 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3360 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3361 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3362 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003363 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3364 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003365 break;
3366 }
3367 case MirrorVirtualPixelMethod:
3368 {
3369 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3370 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003371 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003372 x_modulo.remainder-1L;
3373 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3374 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003375 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003376 y_modulo.remainder-1L;
3377 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3378 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3379 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003380 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3381 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003382 break;
3383 }
3384 case CheckerTileVirtualPixelMethod:
3385 {
3386 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3387 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3388 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3389 {
3390 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003391 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003392 break;
3393 }
3394 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3395 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3396 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003397 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3398 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003399 break;
3400 }
3401 case HorizontalTileVirtualPixelMethod:
3402 {
cristybb503372010-05-27 20:51:26 +00003403 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003404 {
3405 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003406 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003407 break;
3408 }
3409 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3410 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3411 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3412 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3413 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003414 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3415 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003416 break;
3417 }
3418 case VerticalTileVirtualPixelMethod:
3419 {
cristybb503372010-05-27 20:51:26 +00003420 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
cristy3ed852e2009-09-05 21:47:34 +00003421 {
3422 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003423 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003424 break;
3425 }
3426 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3427 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3428 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3429 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3430 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003431 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3432 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003433 break;
3434 }
3435 case HorizontalTileEdgeVirtualPixelMethod:
3436 {
3437 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3438 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003439 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003440 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003441 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3442 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003443 break;
3444 }
3445 case VerticalTileEdgeVirtualPixelMethod:
3446 {
3447 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3448 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003449 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003450 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003451 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3452 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003453 break;
3454 }
3455 }
3456 if (p == (const PixelPacket *) NULL)
3457 break;
3458 *q++=(*p);
cristyc3ec0d42010-04-07 01:18:08 +00003459 if ((indexes != (IndexPacket *) NULL) &&
3460 (virtual_indexes != (const IndexPacket *) NULL))
3461 *indexes++=(*virtual_indexes);
cristy3ed852e2009-09-05 21:47:34 +00003462 continue;
3463 }
3464 /*
3465 Transfer a run of pixels.
3466 */
3467 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,
cristybb503372010-05-27 20:51:26 +00003468 (size_t) length,1UL,virtual_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003469 if (p == (const PixelPacket *) NULL)
3470 break;
cristyc3ec0d42010-04-07 01:18:08 +00003471 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,virtual_nexus[0]);
cristy8f036fe2010-09-18 02:02:00 +00003472 (void) memcpy(q,p,(size_t) length*sizeof(*p));
cristy3ed852e2009-09-05 21:47:34 +00003473 q+=length;
cristyc3ec0d42010-04-07 01:18:08 +00003474 if ((indexes != (IndexPacket *) NULL) &&
3475 (virtual_indexes != (const IndexPacket *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003476 {
cristy8f036fe2010-09-18 02:02:00 +00003477 (void) memcpy(indexes,virtual_indexes,(size_t) length*
cristyc3ec0d42010-04-07 01:18:08 +00003478 sizeof(*virtual_indexes));
3479 indexes+=length;
cristy3ed852e2009-09-05 21:47:34 +00003480 }
3481 }
3482 }
3483 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3484 return(pixels);
3485}
3486
3487/*
3488%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3489% %
3490% %
3491% %
3492+ G e t V i r t u a l P i x e l C a c h e %
3493% %
3494% %
3495% %
3496%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3497%
3498% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3499% cache as defined by the geometry parameters. A pointer to the pixels
3500% is returned if the pixels are transferred, otherwise a NULL is returned.
3501%
3502% The format of the GetVirtualPixelCache() method is:
3503%
3504% const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003505% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3506% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003507% ExceptionInfo *exception)
3508%
3509% A description of each parameter follows:
3510%
3511% o image: the image.
3512%
3513% o virtual_pixel_method: the virtual pixel method.
3514%
3515% o x,y,columns,rows: These values define the perimeter of a region of
3516% pixels.
3517%
3518% o exception: return any errors or warnings in this structure.
3519%
3520*/
3521static const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003522 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3523 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003524{
3525 CacheInfo
cristyd317f372010-09-18 01:42:20 +00003526 *cache_info;
cristy3ed852e2009-09-05 21:47:34 +00003527
cristy5c9e6f22010-09-17 17:31:01 +00003528 const int
3529 id = GetOpenMPThreadId();
3530
cristy3ed852e2009-09-05 21:47:34 +00003531 cache_info=(CacheInfo *) image->cache;
cristy6ebe97c2010-07-03 01:17:28 +00003532 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003533 return(GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3534 cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00003535}
3536
3537/*
3538%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3539% %
3540% %
3541% %
3542% G e t V i r t u a l P i x e l Q u e u e %
3543% %
3544% %
3545% %
3546%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3547%
3548% GetVirtualPixelQueue() returns the virtual pixels associated with the
3549% last call to QueueAuthenticPixels() or GetVirtualPixels().
3550%
3551% The format of the GetVirtualPixelQueue() method is:
3552%
3553% const PixelPacket *GetVirtualPixelQueue(const Image image)
3554%
3555% A description of each parameter follows:
3556%
3557% o image: the image.
3558%
3559*/
3560MagickExport const PixelPacket *GetVirtualPixelQueue(const Image *image)
3561{
3562 CacheInfo
3563 *cache_info;
3564
cristy2036f5c2010-09-19 21:18:17 +00003565 const int
3566 id = GetOpenMPThreadId();
3567
cristy3ed852e2009-09-05 21:47:34 +00003568 assert(image != (const Image *) NULL);
3569 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003570 assert(image->cache != (Cache) NULL);
3571 cache_info=(CacheInfo *) image->cache;
3572 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003573 if (cache_info->methods.get_virtual_pixels_handler !=
3574 (GetVirtualPixelsHandler) NULL)
3575 return(cache_info->methods.get_virtual_pixels_handler(image));
cristy2036f5c2010-09-19 21:18:17 +00003576 assert(id < (int) cache_info->number_threads);
3577 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003578}
3579
3580/*
3581%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3582% %
3583% %
3584% %
3585% G e t V i r t u a l P i x e l s %
3586% %
3587% %
3588% %
3589%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3590%
3591% GetVirtualPixels() returns an immutable pixel region. If the
3592% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003593% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003594% copy of the pixels or it may point to the original pixels in memory.
3595% Performance is maximized if the selected region is part of one row, or one
3596% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003597% (without a copy) if the image is in memory, or in a memory-mapped file. The
3598% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003599%
3600% Pixels accessed via the returned pointer represent a simple array of type
3601% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
3602% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access
3603% the black color component or to obtain the colormap indexes (of type
3604% IndexPacket) corresponding to the region.
3605%
3606% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3607%
3608% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3609% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3610% GetCacheViewAuthenticPixels() instead.
3611%
3612% The format of the GetVirtualPixels() method is:
3613%
cristybb503372010-05-27 20:51:26 +00003614% const PixelPacket *GetVirtualPixels(const Image *image,const ssize_t x,
3615% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003616% ExceptionInfo *exception)
3617%
3618% A description of each parameter follows:
3619%
3620% o image: the image.
3621%
3622% o x,y,columns,rows: These values define the perimeter of a region of
3623% pixels.
3624%
3625% o exception: return any errors or warnings in this structure.
3626%
3627*/
3628MagickExport const PixelPacket *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003629 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3630 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003631{
3632 CacheInfo
3633 *cache_info;
3634
cristy2036f5c2010-09-19 21:18:17 +00003635 const int
3636 id = GetOpenMPThreadId();
3637
cristy3ed852e2009-09-05 21:47:34 +00003638 assert(image != (const Image *) NULL);
3639 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003640 assert(image->cache != (Cache) NULL);
3641 cache_info=(CacheInfo *) image->cache;
3642 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00003643 if (cache_info->methods.get_virtual_pixel_handler !=
3644 (GetVirtualPixelHandler) NULL)
3645 return(cache_info->methods.get_virtual_pixel_handler(image,
3646 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00003647 assert(id < (int) cache_info->number_threads);
3648 return(GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3649 columns,rows,cache_info->nexus_info[id],exception));
cristy3ed852e2009-09-05 21:47:34 +00003650}
3651
3652/*
3653%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3654% %
3655% %
3656% %
3657+ 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 %
3658% %
3659% %
3660% %
3661%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3662%
3663% GetVirtualPixelsCache() returns the pixels associated with the last call
3664% to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3665%
3666% The format of the GetVirtualPixelsCache() method is:
3667%
3668% PixelPacket *GetVirtualPixelsCache(const Image *image)
3669%
3670% A description of each parameter follows:
3671%
3672% o image: the image.
3673%
3674*/
3675static const PixelPacket *GetVirtualPixelsCache(const Image *image)
3676{
3677 CacheInfo
3678 *cache_info;
3679
cristy5c9e6f22010-09-17 17:31:01 +00003680 const int
3681 id = GetOpenMPThreadId();
3682
cristy3ed852e2009-09-05 21:47:34 +00003683 cache_info=(CacheInfo *) image->cache;
cristy6ebe97c2010-07-03 01:17:28 +00003684 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00003685 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
cristy3ed852e2009-09-05 21:47:34 +00003686}
3687
3688/*
3689%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3690% %
3691% %
3692% %
3693+ G e t V i r t u a l P i x e l s N e x u s %
3694% %
3695% %
3696% %
3697%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3698%
3699% GetVirtualPixelsNexus() returns the pixels associated with the specified
3700% cache nexus.
3701%
3702% The format of the GetVirtualPixelsNexus() method is:
3703%
3704% const IndexPacket *GetVirtualPixelsNexus(const Cache cache,
3705% NexusInfo *nexus_info)
3706%
3707% A description of each parameter follows:
3708%
3709% o cache: the pixel cache.
3710%
3711% o nexus_info: the cache nexus to return the colormap pixels.
3712%
3713*/
3714MagickExport const PixelPacket *GetVirtualPixelsNexus(const Cache cache,
3715 NexusInfo *nexus_info)
3716{
3717 CacheInfo
3718 *cache_info;
3719
3720 if (cache == (Cache) NULL)
3721 return((PixelPacket *) NULL);
3722 cache_info=(CacheInfo *) cache;
3723 assert(cache_info->signature == MagickSignature);
3724 if (cache_info->storage_class == UndefinedClass)
3725 return((PixelPacket *) NULL);
3726 return((const PixelPacket *) nexus_info->pixels);
3727}
3728
3729/*
3730%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3731% %
3732% %
3733% %
3734+ M a s k P i x e l C a c h e N e x u s %
3735% %
3736% %
3737% %
3738%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3739%
3740% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3741% The method returns MagickTrue if the pixel region is masked, otherwise
3742% MagickFalse.
3743%
3744% The format of the MaskPixelCacheNexus() method is:
3745%
3746% MagickBooleanType MaskPixelCacheNexus(Image *image,
3747% NexusInfo *nexus_info,ExceptionInfo *exception)
3748%
3749% A description of each parameter follows:
3750%
3751% o image: the image.
3752%
3753% o nexus_info: the cache nexus to clip.
3754%
3755% o exception: return any errors or warnings in this structure.
3756%
3757*/
3758
3759static inline void MagickPixelCompositeMask(const MagickPixelPacket *p,
3760 const MagickRealType alpha,const MagickPixelPacket *q,
3761 const MagickRealType beta,MagickPixelPacket *composite)
3762{
3763 MagickRealType
3764 gamma;
3765
3766 if (alpha == TransparentOpacity)
3767 {
3768 *composite=(*q);
3769 return;
3770 }
3771 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3772 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3773 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3774 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3775 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3776 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3777 composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
3778}
3779
3780static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3781 ExceptionInfo *exception)
3782{
3783 CacheInfo
3784 *cache_info;
3785
3786 MagickPixelPacket
3787 alpha,
3788 beta;
3789
3790 MagickSizeType
3791 number_pixels;
3792
3793 NexusInfo
3794 **clip_nexus,
3795 **image_nexus;
3796
3797 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003798 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003799
3800 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003801 *restrict nexus_indexes,
3802 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003803
cristy3ed852e2009-09-05 21:47:34 +00003804 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003805 *restrict p,
3806 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003807
cristye076a6e2010-08-15 19:59:43 +00003808 register ssize_t
3809 i;
3810
cristy3ed852e2009-09-05 21:47:34 +00003811 /*
3812 Apply clip mask.
3813 */
3814 if (image->debug != MagickFalse)
3815 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3816 if (image->mask == (Image *) NULL)
3817 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +00003818 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00003819 if (cache_info == (Cache) NULL)
3820 return(MagickFalse);
3821 image_nexus=AcquirePixelCacheNexus(1);
3822 clip_nexus=AcquirePixelCacheNexus(1);
3823 if ((image_nexus == (NexusInfo **) NULL) ||
3824 (clip_nexus == (NexusInfo **) NULL))
3825 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy09449f72010-01-23 03:08:36 +00003826 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,
3827 nexus_info->region.y,nexus_info->region.width,nexus_info->region.height,
3828 image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003829 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
3830 q=nexus_info->pixels;
3831 nexus_indexes=nexus_info->indexes;
3832 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3833 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3834 nexus_info->region.height,clip_nexus[0],&image->exception);
3835 GetMagickPixelPacket(image,&alpha);
3836 GetMagickPixelPacket(image,&beta);
3837 number_pixels=(MagickSizeType) nexus_info->region.width*
3838 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +00003839 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +00003840 {
3841 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
3842 break;
3843 SetMagickPixelPacket(image,p,indexes+i,&alpha);
3844 SetMagickPixelPacket(image,q,nexus_indexes+i,&beta);
3845 MagickPixelCompositeMask(&beta,(MagickRealType) PixelIntensityToQuantum(r),
3846 &alpha,alpha.opacity,&beta);
cristyce70c172010-01-07 17:15:30 +00003847 q->red=ClampToQuantum(beta.red);
3848 q->green=ClampToQuantum(beta.green);
3849 q->blue=ClampToQuantum(beta.blue);
3850 q->opacity=ClampToQuantum(beta.opacity);
cristy3ed852e2009-09-05 21:47:34 +00003851 if (cache_info->active_index_channel != MagickFalse)
3852 nexus_indexes[i]=indexes[i];
3853 p++;
3854 q++;
3855 r++;
3856 }
3857 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3858 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +00003859 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003860 return(MagickFalse);
3861 return(MagickTrue);
3862}
3863
3864/*
3865%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3866% %
3867% %
3868% %
3869+ O p e n P i x e l C a c h e %
3870% %
3871% %
3872% %
3873%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3874%
3875% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3876% dimensions, allocating space for the image pixels and optionally the
3877% colormap indexes, and memory mapping the cache if it is disk based. The
3878% cache nexus array is initialized as well.
3879%
3880% The format of the OpenPixelCache() method is:
3881%
3882% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3883% ExceptionInfo *exception)
3884%
3885% A description of each parameter follows:
3886%
3887% o image: the image.
3888%
3889% o mode: ReadMode, WriteMode, or IOMode.
3890%
3891% o exception: return any errors or warnings in this structure.
3892%
3893*/
3894
cristyd43a46b2010-01-21 02:13:41 +00003895static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003896{
3897 cache_info->mapped=MagickFalse;
3898 cache_info->pixels=(PixelPacket *) AcquireMagickMemory((size_t)
3899 cache_info->length);
3900 if (cache_info->pixels == (PixelPacket *) NULL)
3901 {
3902 cache_info->mapped=MagickTrue;
3903 cache_info->pixels=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
3904 cache_info->length);
3905 }
3906}
3907
3908static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3909{
3910 CacheInfo
3911 *cache_info;
3912
3913 MagickOffsetType
3914 count,
3915 extent,
3916 offset;
3917
3918 cache_info=(CacheInfo *) image->cache;
3919 if (image->debug != MagickFalse)
3920 {
3921 char
3922 format[MaxTextExtent],
3923 message[MaxTextExtent];
3924
cristyb9080c92009-12-01 20:13:26 +00003925 (void) FormatMagickSize(length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00003926 (void) FormatMagickString(message,MaxTextExtent,
cristy2ce15c92010-03-12 14:03:41 +00003927 "extend %s (%s[%d], disk, %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003928 cache_info->cache_filename,cache_info->file,format);
3929 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3930 }
3931 if (length != (MagickSizeType) ((MagickOffsetType) length))
3932 return(MagickFalse);
3933 extent=(MagickOffsetType) MagickSeek(cache_info->file,0,SEEK_END);
3934 if (extent < 0)
3935 return(MagickFalse);
3936 if ((MagickSizeType) extent >= length)
3937 return(MagickTrue);
3938 offset=(MagickOffsetType) length-1;
3939 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3940 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3941}
3942
3943static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3944 ExceptionInfo *exception)
3945{
3946 char
3947 format[MaxTextExtent],
3948 message[MaxTextExtent];
3949
3950 CacheInfo
3951 *cache_info,
3952 source_info;
3953
3954 MagickSizeType
3955 length,
3956 number_pixels;
3957
3958 MagickStatusType
3959 status;
3960
3961 size_t
cristye076a6e2010-08-15 19:59:43 +00003962 columns,
cristy3ed852e2009-09-05 21:47:34 +00003963 packet_size;
3964
cristy3ed852e2009-09-05 21:47:34 +00003965 if (image->debug != MagickFalse)
3966 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3967 if ((image->columns == 0) || (image->rows == 0))
3968 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3969 cache_info=(CacheInfo *) image->cache;
3970 source_info=(*cache_info);
3971 source_info.file=(-1);
cristye8c25f92010-06-03 00:53:06 +00003972 (void) FormatMagickString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3973 image->filename,(double) GetImageIndexInList(image));
cristy87528ea2009-09-10 14:53:56 +00003974 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +00003975 cache_info->rows=image->rows;
3976 cache_info->columns=image->columns;
3977 cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
3978 (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
cristy73724512010-04-12 14:43:14 +00003979 if (image->ping != MagickFalse)
3980 {
3981 cache_info->storage_class=image->storage_class;
3982 cache_info->colorspace=image->colorspace;
3983 cache_info->type=PingCache;
3984 cache_info->pixels=(PixelPacket *) NULL;
3985 cache_info->indexes=(IndexPacket *) NULL;
3986 cache_info->length=0;
3987 return(MagickTrue);
3988 }
cristy3ed852e2009-09-05 21:47:34 +00003989 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3990 packet_size=sizeof(PixelPacket);
3991 if (cache_info->active_index_channel != MagickFalse)
3992 packet_size+=sizeof(IndexPacket);
3993 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00003994 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00003995 if (cache_info->columns != columns)
3996 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3997 image->filename);
3998 cache_info->length=length;
3999 status=AcquireMagickResource(AreaResource,cache_info->length);
4000 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4001 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4002 {
4003 status=AcquireMagickResource(MemoryResource,cache_info->length);
4004 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4005 (cache_info->type == MemoryCache))
4006 {
cristyd43a46b2010-01-21 02:13:41 +00004007 AllocatePixelCachePixels(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004008 if (cache_info->pixels == (PixelPacket *) NULL)
4009 cache_info->pixels=source_info.pixels;
4010 else
4011 {
4012 /*
4013 Create memory pixel cache.
4014 */
4015 if (image->debug != MagickFalse)
4016 {
cristy97e7a572009-12-05 15:07:53 +00004017 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004018 format);
cristy3ed852e2009-09-05 21:47:34 +00004019 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004020 "open %s (%s memory, %.20gx%.20g %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00004021 cache_info->mapped != MagickFalse ? "anonymous" : "heap",
cristye8c25f92010-06-03 00:53:06 +00004022 (double) cache_info->columns,(double) cache_info->rows,
4023 format);
cristy3ed852e2009-09-05 21:47:34 +00004024 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4025 message);
4026 }
4027 cache_info->storage_class=image->storage_class;
4028 cache_info->colorspace=image->colorspace;
4029 cache_info->type=MemoryCache;
4030 cache_info->indexes=(IndexPacket *) NULL;
4031 if (cache_info->active_index_channel != MagickFalse)
4032 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4033 number_pixels);
4034 if (source_info.storage_class != UndefinedClass)
4035 {
4036 status|=ClonePixelCachePixels(cache_info,&source_info,
4037 exception);
4038 RelinquishPixelCachePixels(&source_info);
4039 }
4040 return(MagickTrue);
4041 }
4042 }
4043 RelinquishMagickResource(MemoryResource,cache_info->length);
4044 }
4045 /*
4046 Create pixel cache on disk.
4047 */
4048 status=AcquireMagickResource(DiskResource,cache_info->length);
4049 if (status == MagickFalse)
4050 {
4051 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4052 "CacheResourcesExhausted","`%s'",image->filename);
4053 return(MagickFalse);
4054 }
4055 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4056 {
4057 RelinquishMagickResource(DiskResource,cache_info->length);
4058 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4059 image->filename);
4060 return(MagickFalse);
4061 }
4062 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4063 cache_info->length);
4064 if (status == MagickFalse)
4065 {
4066 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4067 image->filename);
4068 return(MagickFalse);
4069 }
4070 cache_info->storage_class=image->storage_class;
4071 cache_info->colorspace=image->colorspace;
4072 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4073 status=AcquireMagickResource(AreaResource,cache_info->length);
4074 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4075 cache_info->type=DiskCache;
4076 else
4077 {
4078 status=AcquireMagickResource(MapResource,cache_info->length);
4079 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4080 (cache_info->type != MemoryCache))
4081 cache_info->type=DiskCache;
4082 else
4083 {
4084 cache_info->pixels=(PixelPacket *) MapBlob(cache_info->file,mode,
4085 cache_info->offset,(size_t) cache_info->length);
4086 if (cache_info->pixels == (PixelPacket *) NULL)
4087 {
4088 cache_info->pixels=source_info.pixels;
4089 cache_info->type=DiskCache;
4090 }
4091 else
4092 {
4093 /*
4094 Create file-backed memory-mapped pixel cache.
4095 */
4096 (void) ClosePixelCacheOnDisk(cache_info);
4097 cache_info->type=MapCache;
4098 cache_info->mapped=MagickTrue;
4099 cache_info->indexes=(IndexPacket *) NULL;
4100 if (cache_info->active_index_channel != MagickFalse)
4101 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4102 number_pixels);
4103 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4104 {
4105 status=ClonePixelCachePixels(cache_info,&source_info,
4106 exception);
4107 RelinquishPixelCachePixels(&source_info);
4108 }
4109 if (image->debug != MagickFalse)
4110 {
cristy97e7a572009-12-05 15:07:53 +00004111 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004112 format);
cristy3ed852e2009-09-05 21:47:34 +00004113 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004114 "open %s (%s[%d], memory-mapped, %.20gx%.20g %sB)",
cristy3ed852e2009-09-05 21:47:34 +00004115 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004116 cache_info->file,(double) cache_info->columns,(double)
4117 cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004118 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4119 message);
4120 }
4121 return(MagickTrue);
4122 }
4123 }
4124 RelinquishMagickResource(MapResource,cache_info->length);
4125 }
4126 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4127 {
4128 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4129 RelinquishPixelCachePixels(&source_info);
4130 }
4131 if (image->debug != MagickFalse)
4132 {
cristyb9080c92009-12-01 20:13:26 +00004133 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00004134 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004135 "open %s (%s[%d], disk, %.20gx%.20g %sB)",cache_info->filename,
4136 cache_info->cache_filename,cache_info->file,(double)
4137 cache_info->columns,(double) cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004138 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4139 }
4140 return(MagickTrue);
4141}
4142
4143/*
4144%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4145% %
4146% %
4147% %
4148+ P e r s i s t P i x e l C a c h e %
4149% %
4150% %
4151% %
4152%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4153%
4154% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4155% persistent pixel cache is one that resides on disk and is not destroyed
4156% when the program exits.
4157%
4158% The format of the PersistPixelCache() method is:
4159%
4160% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4161% const MagickBooleanType attach,MagickOffsetType *offset,
4162% ExceptionInfo *exception)
4163%
4164% A description of each parameter follows:
4165%
4166% o image: the image.
4167%
4168% o filename: the persistent pixel cache filename.
4169%
cristy01b7eb02009-09-10 23:10:14 +00004170% o attach: A value other than zero initializes the persistent pixel
4171% cache.
4172%
cristy3ed852e2009-09-05 21:47:34 +00004173% o initialize: A value other than zero initializes the persistent pixel
4174% cache.
4175%
4176% o offset: the offset in the persistent cache to store pixels.
4177%
4178% o exception: return any errors or warnings in this structure.
4179%
4180*/
4181MagickExport MagickBooleanType PersistPixelCache(Image *image,
4182 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4183 ExceptionInfo *exception)
4184{
4185 CacheInfo
4186 *cache_info,
4187 *clone_info;
4188
4189 Image
4190 clone_image;
4191
cristy3ed852e2009-09-05 21:47:34 +00004192 MagickBooleanType
4193 status;
4194
cristye076a6e2010-08-15 19:59:43 +00004195 ssize_t
4196 page_size;
4197
cristy3ed852e2009-09-05 21:47:34 +00004198 assert(image != (Image *) NULL);
4199 assert(image->signature == MagickSignature);
4200 if (image->debug != MagickFalse)
4201 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4202 assert(image->cache != (void *) NULL);
4203 assert(filename != (const char *) NULL);
4204 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004205 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004206 cache_info=(CacheInfo *) image->cache;
4207 assert(cache_info->signature == MagickSignature);
4208 if (attach != MagickFalse)
4209 {
4210 /*
cristy01b7eb02009-09-10 23:10:14 +00004211 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004212 */
4213 if (image->debug != MagickFalse)
4214 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy9605f5f2010-09-20 18:27:40 +00004215 "attach persistent pixel cache");
cristy3ed852e2009-09-05 21:47:34 +00004216 (void) CopyMagickString(cache_info->cache_filename,filename,
4217 MaxTextExtent);
4218 cache_info->type=DiskCache;
4219 cache_info->offset=(*offset);
cristyde8c9c52010-09-20 18:56:24 +00004220 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00004221 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004222 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristyde8c9c52010-09-20 18:56:24 +00004223 return(SetImageExtent(image,0,0));
cristy3ed852e2009-09-05 21:47:34 +00004224 }
cristy01b7eb02009-09-10 23:10:14 +00004225 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4226 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004227 {
cristyf84a1932010-01-03 18:00:18 +00004228 LockSemaphoreInfo(cache_info->semaphore);
cristy09449f72010-01-23 03:08:36 +00004229 if ((cache_info->mode != ReadMode) &&
4230 (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004231 (cache_info->reference_count == 1))
4232 {
4233 int
4234 status;
4235
4236 /*
cristy01b7eb02009-09-10 23:10:14 +00004237 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004238 */
cristy9605f5f2010-09-20 18:27:40 +00004239 if (image->debug != MagickFalse)
4240 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4241 "usurp resident persistent pixel cache");
cristy3ed852e2009-09-05 21:47:34 +00004242 status=rename(cache_info->cache_filename,filename);
4243 if (status == 0)
4244 {
4245 (void) CopyMagickString(cache_info->cache_filename,filename,
4246 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004247 *offset+=cache_info->length+page_size-(cache_info->length %
4248 page_size);
cristyf84a1932010-01-03 18:00:18 +00004249 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004250 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004251 return(MagickTrue);
4252 }
4253 }
cristyf84a1932010-01-03 18:00:18 +00004254 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004255 }
4256 /*
cristy01b7eb02009-09-10 23:10:14 +00004257 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004258 */
cristy9605f5f2010-09-20 18:27:40 +00004259 if (image->debug != MagickFalse)
4260 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4261 "clone persistent pixel cache");
cristy3ed852e2009-09-05 21:47:34 +00004262 clone_image=(*image);
4263 clone_info=(CacheInfo *) clone_image.cache;
4264 image->cache=ClonePixelCache(cache_info);
4265 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4266 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4267 cache_info->type=DiskCache;
4268 cache_info->offset=(*offset);
4269 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004270 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004271 if (status != MagickFalse)
cristy51fdd112010-09-20 18:09:27 +00004272 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
cristy688f07b2009-09-27 15:19:13 +00004273 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004274 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4275 return(status);
4276}
4277
4278/*
4279%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4280% %
4281% %
4282% %
4283+ Q u e u e A u t h e n t i c N e x u s %
4284% %
4285% %
4286% %
4287%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4288%
4289% QueueAuthenticNexus() allocates an region to store image pixels as defined
4290% by the region rectangle and returns a pointer to the region. This region is
4291% subsequently transferred from the pixel cache with
4292% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4293% pixels are transferred, otherwise a NULL is returned.
4294%
4295% The format of the QueueAuthenticNexus() method is:
4296%
cristy5f959472010-05-27 22:19:46 +00004297% PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
4298% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004299% NexusInfo *nexus_info,ExceptionInfo *exception)
4300%
4301% A description of each parameter follows:
4302%
4303% o image: the image.
4304%
4305% o x,y,columns,rows: These values define the perimeter of a region of
4306% pixels.
4307%
4308% o nexus_info: the cache nexus to set.
4309%
4310% o exception: return any errors or warnings in this structure.
4311%
4312*/
cristybb503372010-05-27 20:51:26 +00004313MagickExport PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy30097232010-07-01 02:16:30 +00004314 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
4315 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004316{
4317 CacheInfo
4318 *cache_info;
4319
4320 MagickOffsetType
4321 offset;
4322
4323 MagickSizeType
4324 number_pixels;
4325
4326 RectangleInfo
4327 region;
4328
4329 /*
4330 Validate pixel cache geometry.
4331 */
cristy77ff0282010-09-13 00:51:10 +00004332 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
4333 if (cache_info == (Cache) NULL)
4334 return((PixelPacket *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004335 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4336 {
4337 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4338 "NoPixelsDefinedInCache","`%s'",image->filename);
4339 return((PixelPacket *) NULL);
4340 }
cristybb503372010-05-27 20:51:26 +00004341 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4342 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004343 {
4344 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4345 "PixelsAreNotAuthentic","`%s'",image->filename);
4346 return((PixelPacket *) NULL);
4347 }
4348 offset=(MagickOffsetType) y*cache_info->columns+x;
4349 if (offset < 0)
4350 return((PixelPacket *) NULL);
4351 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4352 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4353 if ((MagickSizeType) offset >= number_pixels)
4354 return((PixelPacket *) NULL);
4355 /*
4356 Return pixel cache.
4357 */
4358 region.x=x;
4359 region.y=y;
4360 region.width=columns;
4361 region.height=rows;
4362 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4363}
4364
4365/*
4366%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4367% %
4368% %
4369% %
4370+ 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 %
4371% %
4372% %
4373% %
4374%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4375%
4376% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4377% defined by the region rectangle and returns a pointer to the region. This
4378% region is subsequently transferred from the pixel cache with
4379% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4380% pixels are transferred, otherwise a NULL is returned.
4381%
4382% The format of the QueueAuthenticPixelsCache() method is:
4383%
cristybb503372010-05-27 20:51:26 +00004384% PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4385% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004386% ExceptionInfo *exception)
4387%
4388% A description of each parameter follows:
4389%
4390% o image: the image.
4391%
4392% o x,y,columns,rows: These values define the perimeter of a region of
4393% pixels.
4394%
4395% o exception: return any errors or warnings in this structure.
4396%
4397*/
cristybb503372010-05-27 20:51:26 +00004398static PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4399 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004400 ExceptionInfo *exception)
4401{
4402 CacheInfo
4403 *cache_info;
4404
cristy5c9e6f22010-09-17 17:31:01 +00004405 const int
4406 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00004407
cristy77ff0282010-09-13 00:51:10 +00004408 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00004409 if (cache_info == (Cache) NULL)
4410 return((PixelPacket *) NULL);
cristy6ebe97c2010-07-03 01:17:28 +00004411 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00004412 return(QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4413 exception));
cristy3ed852e2009-09-05 21:47:34 +00004414}
4415
4416/*
4417%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4418% %
4419% %
4420% %
4421% Q u e u e A u t h e n t i c P i x e l s %
4422% %
4423% %
4424% %
4425%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4426%
4427% QueueAuthenticPixels() queues a mutable pixel region. If the region is
4428% successfully intialized a pointer to a PixelPacket array representing the
4429% region is returned, otherwise NULL is returned. The returned pointer may
4430% point to a temporary working buffer for the pixels or it may point to the
4431% final location of the pixels in memory.
4432%
4433% Write-only access means that any existing pixel values corresponding to
4434% the region are ignored. This is useful if the initial image is being
4435% created from scratch, or if the existing pixel values are to be
4436% completely replaced without need to refer to their pre-existing values.
4437% The application is free to read and write the pixel buffer returned by
4438% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4439% initialize the pixel array values. Initializing pixel array values is the
4440% application's responsibility.
4441%
4442% Performance is maximized if the selected region is part of one row, or
4443% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004444% pixels in-place (without a copy) if the image is in memory, or in a
4445% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004446% by the user.
4447%
4448% Pixels accessed via the returned pointer represent a simple array of type
4449% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
4450% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
4451% the black color component or the colormap indexes (of type IndexPacket)
4452% corresponding to the region. Once the PixelPacket (and/or IndexPacket)
4453% array has been updated, the changes must be saved back to the underlying
4454% image using SyncAuthenticPixels() or they may be lost.
4455%
4456% The format of the QueueAuthenticPixels() method is:
4457%
cristy5f959472010-05-27 22:19:46 +00004458% PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4459% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004460% ExceptionInfo *exception)
4461%
4462% A description of each parameter follows:
4463%
4464% o image: the image.
4465%
4466% o x,y,columns,rows: These values define the perimeter of a region of
4467% pixels.
4468%
4469% o exception: return any errors or warnings in this structure.
4470%
4471*/
cristybb503372010-05-27 20:51:26 +00004472MagickExport PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4473 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004474 ExceptionInfo *exception)
4475{
4476 CacheInfo
4477 *cache_info;
4478
cristy2036f5c2010-09-19 21:18:17 +00004479 const int
4480 id = GetOpenMPThreadId();
4481
cristy3ed852e2009-09-05 21:47:34 +00004482 assert(image != (Image *) NULL);
4483 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004484 assert(image->cache != (Cache) NULL);
4485 cache_info=(CacheInfo *) image->cache;
4486 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00004487 if (cache_info->methods.queue_authentic_pixels_handler !=
4488 (QueueAuthenticPixelsHandler) NULL)
4489 return(cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4490 rows,exception));
cristy2036f5c2010-09-19 21:18:17 +00004491 assert(id < (int) cache_info->number_threads);
4492 return(QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4493 exception));
cristy3ed852e2009-09-05 21:47:34 +00004494}
4495
4496/*
4497%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4498% %
4499% %
4500% %
4501+ R e a d P i x e l C a c h e I n d e x e s %
4502% %
4503% %
4504% %
4505%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4506%
4507% ReadPixelCacheIndexes() reads colormap indexes from the specified region of
4508% the pixel cache.
4509%
4510% The format of the ReadPixelCacheIndexes() method is:
4511%
4512% MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4513% NexusInfo *nexus_info,ExceptionInfo *exception)
4514%
4515% A description of each parameter follows:
4516%
4517% o cache_info: the pixel cache.
4518%
4519% o nexus_info: the cache nexus to read the colormap indexes.
4520%
4521% o exception: return any errors or warnings in this structure.
4522%
4523*/
4524static MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4525 NexusInfo *nexus_info,ExceptionInfo *exception)
4526{
4527 MagickOffsetType
4528 count,
4529 offset;
4530
4531 MagickSizeType
4532 length,
4533 number_pixels;
4534
4535 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004536 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004537
cristybb503372010-05-27 20:51:26 +00004538 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004539 y;
4540
cristybb503372010-05-27 20:51:26 +00004541 size_t
cristy3ed852e2009-09-05 21:47:34 +00004542 rows;
4543
cristy3ed852e2009-09-05 21:47:34 +00004544 if (cache_info->active_index_channel == MagickFalse)
4545 return(MagickFalse);
4546 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4547 return(MagickTrue);
4548 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4549 nexus_info->region.x;
4550 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
4551 rows=nexus_info->region.height;
4552 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004553 q=nexus_info->indexes;
4554 switch (cache_info->type)
4555 {
4556 case MemoryCache:
4557 case MapCache:
4558 {
4559 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004560 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004561
4562 /*
4563 Read indexes from memory.
4564 */
cristydd341db2010-03-04 19:06:38 +00004565 if ((cache_info->columns == nexus_info->region.width) &&
4566 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4567 {
4568 length=number_pixels;
4569 rows=1UL;
4570 }
cristy3ed852e2009-09-05 21:47:34 +00004571 p=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00004572 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004573 {
cristy8f036fe2010-09-18 02:02:00 +00004574 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00004575 p+=cache_info->columns;
4576 q+=nexus_info->region.width;
4577 }
4578 break;
4579 }
4580 case DiskCache:
4581 {
4582 /*
4583 Read indexes from disk.
4584 */
4585 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4586 {
4587 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4588 cache_info->cache_filename);
4589 return(MagickFalse);
4590 }
cristydd341db2010-03-04 19:06:38 +00004591 if ((cache_info->columns == nexus_info->region.width) &&
4592 (number_pixels < MagickMaxBufferExtent))
4593 {
4594 length=number_pixels;
4595 rows=1UL;
4596 }
cristy3ed852e2009-09-05 21:47:34 +00004597 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004598 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004599 {
4600 count=ReadPixelCacheRegion(cache_info,cache_info->offset+number_pixels*
4601 sizeof(PixelPacket)+offset*sizeof(*q),length,(unsigned char *) q);
4602 if ((MagickSizeType) count < length)
4603 break;
4604 offset+=cache_info->columns;
4605 q+=nexus_info->region.width;
4606 }
cristybb503372010-05-27 20:51:26 +00004607 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004608 {
4609 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4610 cache_info->cache_filename);
4611 return(MagickFalse);
4612 }
4613 break;
4614 }
4615 default:
4616 break;
4617 }
4618 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004619 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004620 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004621 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004622 nexus_info->region.width,(double) nexus_info->region.height,(double)
4623 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004624 return(MagickTrue);
4625}
4626
4627/*
4628%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4629% %
4630% %
4631% %
4632+ R e a d P i x e l C a c h e P i x e l s %
4633% %
4634% %
4635% %
4636%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4637%
4638% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4639% cache.
4640%
4641% The format of the ReadPixelCachePixels() method is:
4642%
4643% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4644% NexusInfo *nexus_info,ExceptionInfo *exception)
4645%
4646% A description of each parameter follows:
4647%
4648% o cache_info: the pixel cache.
4649%
4650% o nexus_info: the cache nexus to read the pixels.
4651%
4652% o exception: return any errors or warnings in this structure.
4653%
4654*/
4655static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4656 NexusInfo *nexus_info,ExceptionInfo *exception)
4657{
4658 MagickOffsetType
4659 count,
4660 offset;
4661
4662 MagickSizeType
4663 length,
4664 number_pixels;
4665
cristy3ed852e2009-09-05 21:47:34 +00004666 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004667 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004668
cristye076a6e2010-08-15 19:59:43 +00004669 register ssize_t
4670 y;
4671
cristybb503372010-05-27 20:51:26 +00004672 size_t
cristy3ed852e2009-09-05 21:47:34 +00004673 rows;
4674
cristy3ed852e2009-09-05 21:47:34 +00004675 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4676 return(MagickTrue);
4677 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4678 nexus_info->region.x;
4679 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
4680 rows=nexus_info->region.height;
4681 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004682 q=nexus_info->pixels;
4683 switch (cache_info->type)
4684 {
4685 case MemoryCache:
4686 case MapCache:
4687 {
4688 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004689 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004690
4691 /*
4692 Read pixels from memory.
4693 */
cristydd341db2010-03-04 19:06:38 +00004694 if ((cache_info->columns == nexus_info->region.width) &&
4695 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4696 {
4697 length=number_pixels;
4698 rows=1UL;
4699 }
cristy3ed852e2009-09-05 21:47:34 +00004700 p=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00004701 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004702 {
cristy8f036fe2010-09-18 02:02:00 +00004703 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00004704 p+=cache_info->columns;
4705 q+=nexus_info->region.width;
4706 }
4707 break;
4708 }
4709 case DiskCache:
4710 {
4711 /*
4712 Read pixels from disk.
4713 */
4714 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4715 {
4716 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4717 cache_info->cache_filename);
4718 return(MagickFalse);
4719 }
cristydd341db2010-03-04 19:06:38 +00004720 if ((cache_info->columns == nexus_info->region.width) &&
4721 (number_pixels < MagickMaxBufferExtent))
4722 {
4723 length=number_pixels;
4724 rows=1UL;
4725 }
cristybb503372010-05-27 20:51:26 +00004726 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004727 {
4728 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4729 sizeof(*q),length,(unsigned char *) q);
4730 if ((MagickSizeType) count < length)
4731 break;
4732 offset+=cache_info->columns;
4733 q+=nexus_info->region.width;
4734 }
cristybb503372010-05-27 20:51:26 +00004735 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004736 {
4737 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4738 cache_info->cache_filename);
4739 return(MagickFalse);
4740 }
4741 break;
4742 }
4743 default:
4744 break;
4745 }
4746 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004747 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004748 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004749 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004750 nexus_info->region.width,(double) nexus_info->region.height,(double)
4751 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004752 return(MagickTrue);
4753}
4754
4755/*
4756%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4757% %
4758% %
4759% %
4760+ R e f e r e n c e P i x e l C a c h e %
4761% %
4762% %
4763% %
4764%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4765%
4766% ReferencePixelCache() increments the reference count associated with the
4767% pixel cache returning a pointer to the cache.
4768%
4769% The format of the ReferencePixelCache method is:
4770%
4771% Cache ReferencePixelCache(Cache cache_info)
4772%
4773% A description of each parameter follows:
4774%
4775% o cache_info: the pixel cache.
4776%
4777*/
4778MagickExport Cache ReferencePixelCache(Cache cache)
4779{
4780 CacheInfo
4781 *cache_info;
4782
4783 assert(cache != (Cache *) NULL);
4784 cache_info=(CacheInfo *) cache;
4785 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004786 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004787 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004788 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004789 return(cache_info);
4790}
4791
4792/*
4793%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4794% %
4795% %
4796% %
4797+ S e t P i x e l C a c h e M e t h o d s %
4798% %
4799% %
4800% %
4801%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4802%
4803% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4804%
4805% The format of the SetPixelCacheMethods() method is:
4806%
4807% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4808%
4809% A description of each parameter follows:
4810%
4811% o cache: the pixel cache.
4812%
4813% o cache_methods: Specifies a pointer to a CacheMethods structure.
4814%
4815*/
4816MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4817{
4818 CacheInfo
4819 *cache_info;
4820
4821 GetOneAuthenticPixelFromHandler
4822 get_one_authentic_pixel_from_handler;
4823
4824 GetOneVirtualPixelFromHandler
4825 get_one_virtual_pixel_from_handler;
4826
4827 /*
4828 Set cache pixel methods.
4829 */
4830 assert(cache != (Cache) NULL);
4831 assert(cache_methods != (CacheMethods *) NULL);
4832 cache_info=(CacheInfo *) cache;
4833 assert(cache_info->signature == MagickSignature);
4834 if (cache_info->debug != MagickFalse)
4835 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4836 cache_info->filename);
4837 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4838 cache_info->methods.get_virtual_pixel_handler=
4839 cache_methods->get_virtual_pixel_handler;
4840 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4841 cache_info->methods.destroy_pixel_handler=
4842 cache_methods->destroy_pixel_handler;
4843 if (cache_methods->get_virtual_indexes_from_handler !=
4844 (GetVirtualIndexesFromHandler) NULL)
4845 cache_info->methods.get_virtual_indexes_from_handler=
4846 cache_methods->get_virtual_indexes_from_handler;
4847 if (cache_methods->get_authentic_pixels_handler !=
4848 (GetAuthenticPixelsHandler) NULL)
4849 cache_info->methods.get_authentic_pixels_handler=
4850 cache_methods->get_authentic_pixels_handler;
4851 if (cache_methods->queue_authentic_pixels_handler !=
4852 (QueueAuthenticPixelsHandler) NULL)
4853 cache_info->methods.queue_authentic_pixels_handler=
4854 cache_methods->queue_authentic_pixels_handler;
4855 if (cache_methods->sync_authentic_pixels_handler !=
4856 (SyncAuthenticPixelsHandler) NULL)
4857 cache_info->methods.sync_authentic_pixels_handler=
4858 cache_methods->sync_authentic_pixels_handler;
4859 if (cache_methods->get_authentic_pixels_from_handler !=
4860 (GetAuthenticPixelsFromHandler) NULL)
4861 cache_info->methods.get_authentic_pixels_from_handler=
4862 cache_methods->get_authentic_pixels_from_handler;
4863 if (cache_methods->get_authentic_indexes_from_handler !=
4864 (GetAuthenticIndexesFromHandler) NULL)
4865 cache_info->methods.get_authentic_indexes_from_handler=
4866 cache_methods->get_authentic_indexes_from_handler;
4867 get_one_virtual_pixel_from_handler=
4868 cache_info->methods.get_one_virtual_pixel_from_handler;
4869 if (get_one_virtual_pixel_from_handler !=
4870 (GetOneVirtualPixelFromHandler) NULL)
4871 cache_info->methods.get_one_virtual_pixel_from_handler=
4872 cache_methods->get_one_virtual_pixel_from_handler;
4873 get_one_authentic_pixel_from_handler=
4874 cache_methods->get_one_authentic_pixel_from_handler;
4875 if (get_one_authentic_pixel_from_handler !=
4876 (GetOneAuthenticPixelFromHandler) NULL)
4877 cache_info->methods.get_one_authentic_pixel_from_handler=
4878 cache_methods->get_one_authentic_pixel_from_handler;
4879}
4880
4881/*
4882%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4883% %
4884% %
4885% %
4886+ S e t P i x e l C a c h e N e x u s P i x e l s %
4887% %
4888% %
4889% %
4890%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4891%
4892% SetPixelCacheNexusPixels() defines the region of the cache for the
4893% specified cache nexus.
4894%
4895% The format of the SetPixelCacheNexusPixels() method is:
4896%
4897% PixelPacket SetPixelCacheNexusPixels(const Image *image,
4898% const RectangleInfo *region,NexusInfo *nexus_info,
4899% ExceptionInfo *exception)
4900%
4901% A description of each parameter follows:
4902%
4903% o image: the image.
4904%
4905% o region: A pointer to the RectangleInfo structure that defines the
4906% region of this particular cache nexus.
4907%
4908% o nexus_info: the cache nexus to set.
4909%
4910% o exception: return any errors or warnings in this structure.
4911%
4912*/
cristyabd6e372010-09-15 19:11:26 +00004913
4914static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4915 NexusInfo *nexus_info,ExceptionInfo *exception)
4916{
4917 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4918 return(MagickFalse);
4919 nexus_info->mapped=MagickFalse;
4920 nexus_info->cache=(PixelPacket *) AcquireMagickMemory((size_t)
4921 nexus_info->length);
4922 if (nexus_info->cache == (PixelPacket *) NULL)
4923 {
4924 nexus_info->mapped=MagickTrue;
4925 nexus_info->cache=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
4926 nexus_info->length);
4927 }
4928 if (nexus_info->cache == (PixelPacket *) NULL)
4929 {
4930 (void) ThrowMagickException(exception,GetMagickModule(),
4931 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4932 cache_info->filename);
4933 return(MagickFalse);
4934 }
4935 return(MagickTrue);
4936}
4937
cristy3ed852e2009-09-05 21:47:34 +00004938static PixelPacket *SetPixelCacheNexusPixels(const Image *image,
4939 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4940{
4941 CacheInfo
4942 *cache_info;
4943
4944 MagickBooleanType
4945 status;
4946
cristy3ed852e2009-09-05 21:47:34 +00004947 MagickSizeType
4948 length,
4949 number_pixels;
4950
cristy3ed852e2009-09-05 21:47:34 +00004951 cache_info=(CacheInfo *) image->cache;
4952 assert(cache_info->signature == MagickSignature);
4953 if (cache_info->type == UndefinedCache)
4954 return((PixelPacket *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00004955 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00004956 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
4957 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00004958 {
cristybb503372010-05-27 20:51:26 +00004959 ssize_t
cristybad067a2010-02-15 17:20:55 +00004960 x,
4961 y;
cristy3ed852e2009-09-05 21:47:34 +00004962
cristyeaedf062010-05-29 22:36:02 +00004963 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4964 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00004965 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4966 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00004967 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00004968 ((nexus_info->region.width == cache_info->columns) ||
4969 ((nexus_info->region.width % cache_info->columns) == 0)))))
4970 {
4971 MagickOffsetType
4972 offset;
4973
4974 /*
4975 Pixels are accessed directly from memory.
4976 */
4977 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4978 nexus_info->region.x;
4979 nexus_info->pixels=cache_info->pixels+offset;
4980 nexus_info->indexes=(IndexPacket *) NULL;
4981 if (cache_info->active_index_channel != MagickFalse)
4982 nexus_info->indexes=cache_info->indexes+offset;
4983 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00004984 }
4985 }
4986 /*
4987 Pixels are stored in a cache region until they are synced to the cache.
4988 */
4989 number_pixels=(MagickSizeType) nexus_info->region.width*
4990 nexus_info->region.height;
4991 length=number_pixels*sizeof(PixelPacket);
4992 if (cache_info->active_index_channel != MagickFalse)
4993 length+=number_pixels*sizeof(IndexPacket);
4994 if (nexus_info->cache == (PixelPacket *) NULL)
4995 {
4996 nexus_info->length=length;
4997 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4998 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004999 {
5000 nexus_info->length=0;
5001 return((PixelPacket *) NULL);
5002 }
cristy3ed852e2009-09-05 21:47:34 +00005003 }
5004 else
5005 if (nexus_info->length != length)
5006 {
5007 RelinquishCacheNexusPixels(nexus_info);
5008 nexus_info->length=length;
5009 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5010 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005011 {
5012 nexus_info->length=0;
5013 return((PixelPacket *) NULL);
5014 }
cristy3ed852e2009-09-05 21:47:34 +00005015 }
5016 nexus_info->pixels=nexus_info->cache;
5017 nexus_info->indexes=(IndexPacket *) NULL;
5018 if (cache_info->active_index_channel != MagickFalse)
5019 nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
5020 return(nexus_info->pixels);
5021}
5022
5023/*
5024%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5025% %
5026% %
5027% %
5028% 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 %
5029% %
5030% %
5031% %
5032%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5033%
5034% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5035% pixel cache and returns the previous setting. A virtual pixel is any pixel
5036% access that is outside the boundaries of the image cache.
5037%
5038% The format of the SetPixelCacheVirtualMethod() method is:
5039%
5040% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5041% const VirtualPixelMethod virtual_pixel_method)
5042%
5043% A description of each parameter follows:
5044%
5045% o image: the image.
5046%
5047% o virtual_pixel_method: choose the type of virtual pixel.
5048%
5049*/
5050MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5051 const VirtualPixelMethod virtual_pixel_method)
5052{
5053 CacheInfo
5054 *cache_info;
5055
5056 VirtualPixelMethod
5057 method;
5058
5059 assert(image != (Image *) NULL);
5060 assert(image->signature == MagickSignature);
5061 if (image->debug != MagickFalse)
5062 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5063 assert(image->cache != (Cache) NULL);
5064 cache_info=(CacheInfo *) image->cache;
5065 assert(cache_info->signature == MagickSignature);
5066 method=cache_info->virtual_pixel_method;
5067 cache_info->virtual_pixel_method=virtual_pixel_method;
5068 return(method);
5069}
5070
5071/*
5072%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5073% %
5074% %
5075% %
5076+ 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 %
5077% %
5078% %
5079% %
5080%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5081%
5082% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5083% in-memory or disk cache. The method returns MagickTrue if the pixel region
5084% is synced, otherwise MagickFalse.
5085%
5086% The format of the SyncAuthenticPixelCacheNexus() method is:
5087%
5088% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5089% NexusInfo *nexus_info,ExceptionInfo *exception)
5090%
5091% A description of each parameter follows:
5092%
5093% o image: the image.
5094%
5095% o nexus_info: the cache nexus to sync.
5096%
5097% o exception: return any errors or warnings in this structure.
5098%
5099*/
5100MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5101 NexusInfo *nexus_info,ExceptionInfo *exception)
5102{
5103 CacheInfo
5104 *cache_info;
5105
5106 MagickBooleanType
5107 status;
5108
5109 /*
5110 Transfer pixels to the cache.
5111 */
5112 assert(image != (Image *) NULL);
5113 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005114 if (image->cache == (Cache) NULL)
5115 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5116 cache_info=(CacheInfo *) image->cache;
5117 if (cache_info->type == UndefinedCache)
5118 return(MagickFalse);
5119 if ((image->clip_mask != (Image *) NULL) &&
5120 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5121 return(MagickFalse);
5122 if ((image->mask != (Image *) NULL) &&
5123 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5124 return(MagickFalse);
5125 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5126 return(MagickTrue);
5127 assert(cache_info->signature == MagickSignature);
5128 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5129 if ((cache_info->active_index_channel != MagickFalse) &&
5130 (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
5131 return(MagickFalse);
5132 return(status);
5133}
5134
5135/*
5136%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5137% %
5138% %
5139% %
5140+ S y n c A u t h e n t i c P i x e l C a c h e %
5141% %
5142% %
5143% %
5144%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5145%
5146% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5147% or disk cache. The method returns MagickTrue if the pixel region is synced,
5148% otherwise MagickFalse.
5149%
5150% The format of the SyncAuthenticPixelsCache() method is:
5151%
5152% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5153% ExceptionInfo *exception)
5154%
5155% A description of each parameter follows:
5156%
5157% o image: the image.
5158%
5159% o exception: return any errors or warnings in this structure.
5160%
5161*/
5162static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5163 ExceptionInfo *exception)
5164{
5165 CacheInfo
5166 *cache_info;
5167
cristy5c9e6f22010-09-17 17:31:01 +00005168 const int
5169 id = GetOpenMPThreadId();
cristy3ed852e2009-09-05 21:47:34 +00005170
cristy3ed852e2009-09-05 21:47:34 +00005171 cache_info=(CacheInfo *) image->cache;
cristy6ebe97c2010-07-03 01:17:28 +00005172 assert(id < (int) cache_info->number_threads);
cristyf54fb572010-09-17 20:08:14 +00005173 return(SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5174 exception));
cristy3ed852e2009-09-05 21:47:34 +00005175}
5176
5177/*
5178%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5179% %
5180% %
5181% %
5182% S y n c A u t h e n t i c P i x e l s %
5183% %
5184% %
5185% %
5186%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5187%
5188% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5189% The method returns MagickTrue if the pixel region is flushed, otherwise
5190% MagickFalse.
5191%
5192% The format of the SyncAuthenticPixels() method is:
5193%
5194% MagickBooleanType SyncAuthenticPixels(Image *image,
5195% ExceptionInfo *exception)
5196%
5197% A description of each parameter follows:
5198%
5199% o image: the image.
5200%
5201% o exception: return any errors or warnings in this structure.
5202%
5203*/
5204MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5205 ExceptionInfo *exception)
5206{
5207 CacheInfo
5208 *cache_info;
5209
cristy2036f5c2010-09-19 21:18:17 +00005210 const int
5211 id = GetOpenMPThreadId();
5212
cristy3ed852e2009-09-05 21:47:34 +00005213 assert(image != (Image *) NULL);
5214 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005215 assert(image->cache != (Cache) NULL);
5216 cache_info=(CacheInfo *) image->cache;
5217 assert(cache_info->signature == MagickSignature);
cristyd317f372010-09-18 01:42:20 +00005218 if (cache_info->methods.sync_authentic_pixels_handler !=
5219 (SyncAuthenticPixelsHandler) NULL)
5220 return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
cristy2036f5c2010-09-19 21:18:17 +00005221 assert(id < (int) cache_info->number_threads);
5222 return(SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5223 exception));
cristy3ed852e2009-09-05 21:47:34 +00005224}
5225
5226/*
5227%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5228% %
5229% %
5230% %
5231+ W r i t e P i x e l C a c h e I n d e x e s %
5232% %
5233% %
5234% %
5235%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5236%
5237% WritePixelCacheIndexes() writes the colormap indexes to the specified
5238% region of the pixel cache.
5239%
5240% The format of the WritePixelCacheIndexes() method is:
5241%
5242% MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5243% NexusInfo *nexus_info,ExceptionInfo *exception)
5244%
5245% A description of each parameter follows:
5246%
5247% o cache_info: the pixel cache.
5248%
5249% o nexus_info: the cache nexus to write the colormap indexes.
5250%
5251% o exception: return any errors or warnings in this structure.
5252%
5253*/
5254static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5255 NexusInfo *nexus_info,ExceptionInfo *exception)
5256{
5257 MagickOffsetType
5258 count,
5259 offset;
5260
5261 MagickSizeType
5262 length,
5263 number_pixels;
5264
5265 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005266 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005267
cristybb503372010-05-27 20:51:26 +00005268 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005269 y;
5270
cristybb503372010-05-27 20:51:26 +00005271 size_t
cristy3ed852e2009-09-05 21:47:34 +00005272 rows;
5273
cristy3ed852e2009-09-05 21:47:34 +00005274 if (cache_info->active_index_channel == MagickFalse)
5275 return(MagickFalse);
5276 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5277 return(MagickTrue);
5278 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5279 nexus_info->region.x;
5280 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
5281 rows=nexus_info->region.height;
5282 number_pixels=(MagickSizeType) length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005283 p=nexus_info->indexes;
5284 switch (cache_info->type)
5285 {
5286 case MemoryCache:
5287 case MapCache:
5288 {
5289 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005290 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005291
5292 /*
5293 Write indexes to memory.
5294 */
cristydd341db2010-03-04 19:06:38 +00005295 if ((cache_info->columns == nexus_info->region.width) &&
5296 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5297 {
5298 length=number_pixels;
5299 rows=1UL;
5300 }
cristy3ed852e2009-09-05 21:47:34 +00005301 q=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00005302 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005303 {
cristy8f036fe2010-09-18 02:02:00 +00005304 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00005305 p+=nexus_info->region.width;
5306 q+=cache_info->columns;
5307 }
5308 break;
5309 }
5310 case DiskCache:
5311 {
5312 /*
5313 Write indexes to disk.
5314 */
5315 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5316 {
5317 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5318 cache_info->cache_filename);
5319 return(MagickFalse);
5320 }
cristydd341db2010-03-04 19:06:38 +00005321 if ((cache_info->columns == nexus_info->region.width) &&
5322 (number_pixels < MagickMaxBufferExtent))
5323 {
5324 length=number_pixels;
5325 rows=1UL;
5326 }
cristy3ed852e2009-09-05 21:47:34 +00005327 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005328 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005329 {
5330 count=WritePixelCacheRegion(cache_info,cache_info->offset+number_pixels*
5331 sizeof(PixelPacket)+offset*sizeof(*p),length,
5332 (const unsigned char *) p);
5333 if ((MagickSizeType) count < length)
5334 break;
5335 p+=nexus_info->region.width;
5336 offset+=cache_info->columns;
5337 }
cristybb503372010-05-27 20:51:26 +00005338 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005339 {
5340 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5341 cache_info->cache_filename);
5342 return(MagickFalse);
5343 }
5344 break;
5345 }
5346 default:
5347 break;
5348 }
5349 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005350 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005351 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005352 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005353 nexus_info->region.width,(double) nexus_info->region.height,(double)
5354 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005355 return(MagickTrue);
5356}
5357
5358/*
5359%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5360% %
5361% %
5362% %
5363+ W r i t e C a c h e P i x e l s %
5364% %
5365% %
5366% %
5367%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5368%
5369% WritePixelCachePixels() writes image pixels to the specified region of the
5370% pixel cache.
5371%
5372% The format of the WritePixelCachePixels() method is:
5373%
5374% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5375% NexusInfo *nexus_info,ExceptionInfo *exception)
5376%
5377% A description of each parameter follows:
5378%
5379% o cache_info: the pixel cache.
5380%
5381% o nexus_info: the cache nexus to write the pixels.
5382%
5383% o exception: return any errors or warnings in this structure.
5384%
5385*/
5386static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5387 NexusInfo *nexus_info,ExceptionInfo *exception)
5388{
5389 MagickOffsetType
5390 count,
5391 offset;
5392
5393 MagickSizeType
5394 length,
5395 number_pixels;
5396
cristy3ed852e2009-09-05 21:47:34 +00005397 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005398 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005399
cristybb503372010-05-27 20:51:26 +00005400 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005401 y;
5402
cristybb503372010-05-27 20:51:26 +00005403 size_t
cristy3ed852e2009-09-05 21:47:34 +00005404 rows;
5405
cristy3ed852e2009-09-05 21:47:34 +00005406 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5407 return(MagickTrue);
5408 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5409 nexus_info->region.x;
5410 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
5411 rows=nexus_info->region.height;
5412 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005413 p=nexus_info->pixels;
5414 switch (cache_info->type)
5415 {
5416 case MemoryCache:
5417 case MapCache:
5418 {
5419 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005420 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005421
5422 /*
5423 Write pixels to memory.
5424 */
cristydd341db2010-03-04 19:06:38 +00005425 if ((cache_info->columns == nexus_info->region.width) &&
5426 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5427 {
5428 length=number_pixels;
5429 rows=1UL;
5430 }
cristy3ed852e2009-09-05 21:47:34 +00005431 q=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00005432 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005433 {
cristy8f036fe2010-09-18 02:02:00 +00005434 (void) memcpy(q,p,(size_t) length);
cristy3ed852e2009-09-05 21:47:34 +00005435 p+=nexus_info->region.width;
5436 q+=cache_info->columns;
5437 }
5438 break;
5439 }
5440 case DiskCache:
5441 {
5442 /*
5443 Write pixels to disk.
5444 */
5445 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5446 {
5447 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5448 cache_info->cache_filename);
5449 return(MagickFalse);
5450 }
cristydd341db2010-03-04 19:06:38 +00005451 if ((cache_info->columns == nexus_info->region.width) &&
5452 (number_pixels < MagickMaxBufferExtent))
5453 {
5454 length=number_pixels;
5455 rows=1UL;
5456 }
cristybb503372010-05-27 20:51:26 +00005457 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005458 {
5459 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5460 sizeof(*p),length,(const unsigned char *) p);
5461 if ((MagickSizeType) count < length)
5462 break;
5463 p+=nexus_info->region.width;
5464 offset+=cache_info->columns;
5465 }
cristybb503372010-05-27 20:51:26 +00005466 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005467 {
5468 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5469 cache_info->cache_filename);
5470 return(MagickFalse);
5471 }
5472 break;
5473 }
5474 default:
5475 break;
5476 }
5477 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005478 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005479 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005480 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005481 nexus_info->region.width,(double) nexus_info->region.height,(double)
5482 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005483 return(MagickTrue);
5484}